Learn about our API and how to sync and transform design tokens in your design system.
Glossary
Looking for a definition? We've got your back!
Organization (workspace)
An organization, sometimes called workspace, is the Specify place you share with your team.
Repository
Source
Destination
Specify Design Token Format (SDTF)
Token type
A Token type is a type of design token or asset supported by Specify like a color, a textStyle or a vector.
Collection
A collection is a way to group design tokens while ensuring the modes of the tokens they contain within the SDTF. A Collection can contain groups, and design tokens with one or several modes.
Group
A group is way to semantically group design tokens in the SDTF. A group contains design tokens, other groups and exists in the context of a collection.
Alias
An alias design token is a design token whose value is not a raw value but a reference to another design token's value.
Mode
A Mode is a way to associate the value of a design token to a specific context. For instance, a color named background can have several values associated to different modes like Light or Dark.
Parsers Engine
Parser Rule
Parser
SDTF Client
SDTF Engine
Configuration file
Pulling your first tokens with the CLI
A 5min guide on collecting and pulling your first design tokens with the Specify CLI.
Introduction
In this guide you’ll learn how to pull your first design tokens to CSS Custom Properties using the Specify CLI.
Before getting started
To get the most out of this guide, you’ll need:
A Specify account
1. Install the CLI
Install @specifyapp/cli
curl -sL https://static.specifyapp.com/cli/install.sh | sh
2. Create your Specify config file
3. Add your Specify repository
Add your Specify repository and workspace from which you want to pull your design tokens. You can find your workspace name and repository name in the URL of the app when inside a repository.
Our configuration is ready and we can now pull our design tokens and assets using the pull command.
specify pull
What is a Source?
Definition
Collecting the design data
From this point on, you can synchronize your source(s) with Specify anytime, at a click of a button.
Repository with many sources
Data from many sources get automatically merged into a consolidated SDTF token tree. If Specify detects a conflict over sources, it will refuse to synchronize the first source that cause the conflict and turn it into an error state.
A repository is like a directory containing your design tokens and assets. The design data is stored within a JSON compatible tree built upon the .
A source belongs to a repository, it represents where the original design tokens and/or assets come from - think of (Variables or Local Styles) or .
A destination belongs to a repository, it represents where the formatted design data get distributed on updates - think of or any automation you can come up with our and .
The SDTF stands for . It's a token format that helps you sync design tokens from Figma Styles, Figma Variables, and Tokens Studio. Your design tokens are created and saved as a token tree you can query and transform thanks to the Specify API. The SDTF is composed of more than 50 token types. In a SDTF token tree, design tokens can be organized in Collections, Groups, and Modes.
The is the high-level design data transformation and export API.
A is a JSON object describing a series of parsers and options, responsible to transform and export your design tokens and assets to your code base.
are functions allowing you to transform design tokens and assets coming from Specify to fit your needs and company standards. .
The offers versatile methods for working with token trees, enabling data manipulation, transformation, and conversion into various formats or languages, bridging the gap between stored and live token instances within your repository.
The brings together the core APIs that enable most of Specify features to seamlessly integrate, whether you're working in Figma or Token Studio, managing GitHub pull-requests, or directly within your codebase with the SDK or the CLI.
A file is a JSON or JavaScript file, made of one or many rules and the credentials to authenticate. The configuration is used to communicate with the Parsers Engine.
Want to know more on how to collect design tokens from Figma to Specify first? Head towards the section!
A Specify repository containing design tokens ()
Create a configuration file for your desired output format using one of our
Generate a personalAccessToken for the CLI and add it in your configuration. You can generate a personal access token from you .
Add your first rule and use the parser to generate your tokens as CSS variables.
A Source represents where the original design data come from - think of (Variables or Local Styles) or .
You can add many sources into a .
Learn more about the available compatible with Specify.
Once a source is configured, Specify starts to collect your design data. Over this process, the acquires, validates and converts the original data into a SDTF token tree that get stored within the repository.
You can review your sources status by heading to any repository page on the Specify .
The first Design Token Engine allowing you to send your design tokens across your design system tools. Specify is built with this idea: configure once, synchronize anytime.
Specify is a central and tool-agnostic platform. It means you can integrate your daily tools to collect, store and distribute your design data to the right teams, in the right format, at the right time. To sum things up, see Specify as the synchronization layer for your design data at the heart of your design system.
Teams can benefit from a single source of truth and a continuous delivery system that ensures brand consistency.
In short, you have more time to focus on what matters most: your products and your end-users.
Designers, connect your favorite design tool, like or , and let Specify monitor and collect your design tokens and assets automatically. This way, you control what is sent to developers and reduce the risk of inconsistencies.
Developers, configure tailored transformation pipelines for every project and get design tokens and assets from wherever you want. Use our or get automated Pull Requests. You can also create your custom pipeline thanks to our .
In this guide you’ll learn how to sync your design tokens from Tokens Studio to your Specify repository and how to keep them updated.
Before getting started
To get the most out of this guide, you will need:
Specify automatically fetches design tokens through the JSON file created by Tokens Studio. The best way to keep your design tokens in sync with both tools is to host your JSON file in a repository like GitHub.
1. Sync your design tokens from Tokens Studio to a provider
Head to your Tokens Studio plugin in Figma
Within the settings tab, add a new sync provider
Commit your Tokens Studio JSON file to your repository
You can also manually export your file from Tokens Studio and upload it manually to your code repository. Click on Tools on the bottom left of the plugin and Export to file/folder. Be careful to tick all the boxes before exporting. We are not supporting multiple files at the moment.
2. Add your JSON file from a provider to your Specify Repository
Go to your Specify workspace
Click on "Create repository"
Choose "Advanced Repository"
Name your repository
Click on "Create repository"
In the "Source" tab, click on "Create a source"
Select "Remote URL"
At this point, you have two ways to sync your JSON file. Either with a public hosting link or a private one. We will go through both options below.
From a public URL
In the "Source" tab, click on "Create a source"
Select "Remote URL"
Select "Public"
Name your source
Paste your raw public URL of your JSON file
Select the format "Tokens Studio"
Let Specify check the connection
And voila!
Your JSON file is now detected as a source and your design tokens appear within your repository.
From a private URL
On the opposite of the public URL, Specify will ask you for some additional information so its system is able to fetch your file. Let’s see how to proceed with the main versioning tools:
GitHub
Requirements:
Have a GitHub account
Have an Advanced Repository created
Have a JSON file containing design tokens from Tokens Studio
To add a private URL source from GitHub to Specify:
In the "Source" tab of your Specify repository, click on "Create a source"
Select "Remote URL"
Select "Private"
Name your source
Select "Tokens Studio Format"
Specify will test your JSON
And voila!
Azure DevOps
Requirements:
Have an Azure DevOps account
Have a Project containing a repository
Have a JSON file containing design tokens from Tokens Studio
To add a private URL source from Azure DevOps to Specify:
In the "Source" tab of your Specify repository, click on "Create a source"
Select "Remote URL"
Select "Private"
Name your source
Paste your Azure DevOps file URL such as https://dev.azure.com/{OrgName}/{ProjectName}/_apis/git/repositories/{RepositoryName}/items?path={FilePath}&api-version=7.0&includeContent=true
Select "Tokens Studio Format"
Specify will test your JSON
And voila!
GitLab
Requirements:
Have a GitLab account
Have an Advanced Repository created
Have a JSON file containing design tokens from Tokens Studio
To add a private URL source from GitLab to Specify:
In the "Source" tab of your Specify repository, click on "Create a source"
Select "Remote URL"
Select "Private"
Give a name to your source
Paste your GitLab file URL such as: https://gitlab.com/api/v4/projects/{OrgName}%2F{RepositoryName}/repository/files/{FilePath}?ref={branch}
Create an access token in GitLab: "Settings > Access Tokens". Select a role as Developer or Owner and select the scopes of read_api and read_repository.
In Specify, select Header as auth system
Fill PRIVATE-TOKEN in the key field
Paste your GitLab project access token
Select "Tokens Studio Format"
Specify will test your JSON
And voila!
JSONBin
Requirements:
Have a JSONBin account
Have an Advanced Repository created
Have a bin with a JSON file containing design tokens from Tokens Studio
To add a private URL source from JSONBin to Specify:
In the "Source" tab of your Specify repository, click on "Create a source"
Select "Remote URL"
Select "Private"
Name your source
Paste your BIN private URL such as https://api.jsonbin.io/v3/b/{bin_id}
Select Header as auth system
Following your choice, fill in the key field either with X-MASTER-KEY or X-ACCESS-KEY
Paste your key in the value field
Select "Tokens Studio Format"
Specify will test your JSON
And voila!
3. How to update your JSON File
After adding your source. All you have to do is to:
Go to the "Source" tab of your Specify repository
Click on the context menu next to your source
Click on "sync"
Your source is now updated!
4. Non-supported design token types
Please keep in mind Specify is yet not compatible with the following data coming from Tokens Studio:
Composition
Assets (bitmap & vectors)
Color manipulation (gradients, alpha, darken, lighten & mix)
A account
The plugin installed in your Figma
A , , , or account
Select "Sync from Figma Variables & Tokens Studio" ()
Create and Paste this GitHub file URL such as: https://api.github.com/repos/{owner}/{repo}/contents/{file_path}
Select "Bearer Token" as the auth system & paste your personal access token from GitHub ( and be sure to check the repo section)
Select "Basic Auth" as auth system. Use your Azure DevOps email and a new Azure DevOps personal access token with Full Access or Code -> Read permissions.
Depending on your choice, you can use your master key or an access key. on JSONBin.
They will be released in future updates. However, if you have urgent needs for Specify to be compatible with one of them, .
Distribute your design tokens and assets from Specify right from your codebase.
You are in Control
The Specify SDK is here to give you more power and freedom toward design token code generation. Built on top of our newly released format (SDTF), this brand new tool will help you build custom solutions tailor-shaped to your design token workflow. In a few words, the SDK provides all the necessary pieces and architecture you will need to ensure that you are in control of your design tokens system delivery. Written in TypeScript, it can also be used in a JavaScript environment.
Leverage the most advanced design token format
By levering your design token graph, the SDK provides all the methods needed to manipulate and transform the data coming from Specify. Whether it is about filtering and renaming tokens, groups and collections, deleting modes in tokens or transforming your data into any languages. Based on the Specify engine and parsers technology, you'll benefit from their flexibility without any maintenance.
Built to suit your standards
The idea behind the SDK is also for you to have more freedom on the output. Meaning that if the current parser technology doesn't meet your standards entirely, you can add custom codes among the pipeline chain. Everything is executable locally so you are not tied to a vendor, which allows you to create your own dedicated delivery engine that follows your company standards.
Let's jump in!
How to get started? Easy as pie, follow our section to grasp the best usage of the SDK.
Video tutorial (7min) to help you sync tokens from Tokens Studio to your local git repo as CSS variables
Figma Variables & Styles
In this guide, you’ll learn how to sync your Figma Variables and/or Styles to a Specify Repository and how to keep them updated.
Before getting started
To get the most out of this guide, you will need:
A Specify Account
A Figma file containing Variables and/or Styles
1. Sync your Figma Variables and Styles with a Specify Repository
Access your Figma file which includes the Variables and/or Styles you would like to sync to Specify
2. Connect your Specify account
Click "Connect"
Choose Advanced Repository
Note: the widget can be used for syncing Figma Styles from the Classic repositories as well, you can switch between the two by clicking "Switch to".
3. Create a repository in Specify
Go to your Specify workspace
Click on "Create repository"
Choose a name
Click "Create repository"
4. Connect the Specify Repository in your Widget
Go back to your Figma file that includes the Variables and/or Styles
Click on "Create Source" in the Specify Widget
It will show you the local collections and styles that are detected
Select the Specify repository you want to sync with. You should be able to see the Repository you have just created in Specify (if not, reload the list).
Click "Save to Specify"
You will immediately see the repository listed with the latest syncing time
Make sure to understand that only Advanced repositories are listed here.
5. Sync updates variables and styles on the fly
6. Check or delete your source inside the Specify interface
You will see the category of design tokens that are synced on the left-hand side
In the Sources section (left-hand menu), you will see your connection(s) and when the last sync between your Figma file and Specify repository has occurred.
Delete your source by clicking on the 3 dots option menu in the source card.
the Specify Widget in the Figma file which includes your Variables and/or Styles. Or update the widget if you already have it. To update the Specify Widget you have to disconnect it, remove the entire frame in all of your Figma files, and reopen the latest version of the Widget.
Follow the steps in the widget to connect your account. You will need to create a personal access token and you will need to add the link to the Figma file to which the widget is added.
Select "Advanced Repository" ()
Select the design tokens format you want to collect from your Figma file.
Use the Sync button to update your Variables and/or Styles with Specify. Now you are ready to ! 🎉
How to sync Figma Variables and Styles to Specify (3min)
Parsers Engine
Configure automated pipelines and deliver the design data to battle-tested technologies like CSS, Style Dictionary, Javascript, TypeScript, Swift, Kotlin — and more.
Overview
The Parsers Engine is a set of APIs you interact with anytime you need to transform your design data - tokens & assets - from your repository token tree into pre-configured file outputs.
Parser Rules
As the medium to interact with the Parsers Engine, the parser rules are meant to be configured to follow your output needs.
A parser rule is simply a JSON object with two properties:
name: the name of the rule — we recommend setting up the purpose: CSS variables, Icons export...
Parser Configuration
output: an object describing the desired output type - can be optional when no output is expected.
options: an object of arbitrary keys and values defined by the parser - can be optional.
Example of a parser rule for a CSS custom properties output
{
"rules": [
{
"name": "Generate tokens as CSS Custom Properties",
"parsers": [
{
"name": "to-css-custom-properties", // parser name
"output": {
"type": "file",
"filePath": "public/css/tokens.css" // ouput will be a file
},
"options": { // parser specific options
"tokenNameTemplate": "--{{groups}}-{{token}}",
"selectorTemplate": "[data-theme=\"{{mode}}\"]"
}
}
]
}
]
}
Parser rules templates
Remote execution
Executed over HTTP, the parser rules are sent over to Specify servers to evaluate, transform and return the structured result.
Configuration file
A Specify configuration file allows you to:
Provide a personal access token as authentication credentials for your user.
By default the file is named .specifyrc.js or .specifyrc.json
Local execution
Once executed, the parsers pipeline yields the result back to the SDK instance.
The Parsers functions
Parsers play a pivotal role. They are functions acting as interpreters and transformers of design tokens. They process the initial token tree and apply a set of transformations toward the expected output. Each parser, whether it pertains to utilities or generation, contributes to the workflow by either mutating the token tree or generating tangible assets and code snippets respectively.
Utility parsers
Utility parsers mutate the design token tree, through dedicated functions like filter, convert-color, change-case…
You configure their options property to instruct the changes to apply to your token tree before it get passed to the next step.
Generation parsers
Code generation parsers generate one or several outputs like CSS, JavaScript, TypeScript or assets like SVGs or bitmaps.
You configure their output property to produce the files that will end up in your codebase.
The options property is also available for most of the generation parsers.
GitHub
Distribute your design tokens and assets via automated Pull Requests.
Specify will sync your GitHub repository if you have a config file .specifyrc.json saved at the root of your GitHub repository.
Prerequisites
Please make sure you have:
A GitHub account
A Specify account
One or multiple Specify repositories containing some design tokens.
Want to connect a GitHub repository from your GitHub organization? Please make sure you have the correct access rights. Otherwise, you'll need an owner to approve your installation request.
Connecting Specify and GitHub
Once you've connected your GitHub account, Specify has to know what design tokens to synchronize and how.
Go to the Specify Advanced Repository you want to distribute design data from
Go to its "Destinations" page
Click on "Create Pipeline"
Select "GitHub application"
Connect or select your GitHub account
Select the GitHub repository you want to distribute your design data to
Create the Pull Request containing your configuration file
Merge the PR created by Specify containing your configuration file
Specify will now automatically sync design data to your GitHub repository 🎉
Useful resources
Specify CLI
Build for the CI/CD
Let's jump in!
What is a Destination?
Definition
Distributing the design data
Once your repository is filled in, you will start to distribute your design data throughout your design system consumers, starting with development teams.
The destinations offer several levels of control over the transformation required to meet your company standards.
Two main APIs at stake here:
Getting started with templates
Specify Design Token Format
Learn more about the Specify Design Token Format (SDTF) specifications.
Introduction
The Specify Design Token Format (SDTF) is a JSON based notation made to capture the architecture of information of design tokens regardless of its source. Supporting 50+ token types, the SDTF allows to compose the most complex types by referencing/aliasing others. Its primary focus is compatibility among design (system) tools and the frontend technologies used to build design systems.
In Specify, each repository is home to one SDTF token tree.
The SDTF is a transport format, if it can be read easily, we do not recommend writing its content directly. Instead, use the APIs provided by Specify.
JSON Tree Structure
With the SDTF, you organize design tokens as a regular JSON tree with some remarkable signatures such as token, group and collection.
With groups and collections, you create sets of tokens to convey meaning like color.primary where color is the group and where my primary is a token, nested in color.
There is no technical limitation to the level of nesting you can achieve, yet good practices would drive the usage to a couple or so.
Tree node (token, group, collection)
A tree node is any of token, group or collection that live within a SDTF token tree.
Naming
Token, group and collection names are free to use any character except the following:
.(dot/period) used for aliasing
$ reserved for SDTF
Common properties
Any group, collection or design token can hold extra properties:
$description a string aimed to complement the name.
$extensions a JSON object to complement the value for a given provider.
Example with dimensions
Note on $extensions
Tree path
The tree path is the unique identifier of a tree node within the token tree. It is formed from the enumeration of the node's parent names.
In the following example, the token base is nested into the spacing group. Thus, its path is ['spacing', 'base'] or "spacing.base".
Representations
Among the Specify APIs, you'll find 2 path representations.
the string based representation concatenates the path with . (dot/period) . Mainly used for aliasing. Giving for our previous example "spacing.base".
the array based representation with an array of string, where each item is the name of a tree node. Mainly used for working with the SDTF Engine. Giving for our previous example ['spacing', 'base'].
Design token
A design token represents the value of a design decision for all the possible modes you want to attach. It is defined by its $type and its corresponding $value, where the $value is a JSON object, Record<mode: string, value: any>, where the mode name is the key and holds to the actual value.
A design token can be placed anywhere within a group or a collection.
Token value
Value defines at least one mode
Any Token Value MUST define at least one mode.
Default mode, by convention, is: default such as $value: { default: ... }
Modes naming
Modes names are free to use any character except the following:
.(dot/period) used for aliasing
$ reserved for SDTF
Modes outside a collection
A token placed outside of a collection can define any mode as far as it defines at least one mode.
Modes inside a collection
A token placed inside of a collection must strictly define the modes allowed by the collection.
Aliasing (reference)
Within a design token value, we can declare { $alias: 'path.to.token' } to reference another token, thus avoiding information duplication.
You can alias tokens through three levels.
Top-level aliasing
You can alias an entire Token. Hence you also inherit from its modes.
Note that $mode does not apply here.
Mode-level aliasing
You can alias on one or many modes of a Token. The value resolution will follow the indicated target $mode.
Note that $mode is mandatory
Value-level aliasing
You can alias on (almost) all sub-values composing the SDTF. The value resolution will follow the indicated target $mode.
Note that $mode is mandatory
Aliasing validation
Aliases must reference compatible Tokens. Each type has a unique mapping to other types defining which ones can be referenced at which place.
Example of invalid aliasing
Here is a dimension using value level aliasing.
The Token expected to resolve for { $alias: 'a.value' } must be a number.
But since number is a broad definition, we would also accept integerNumber, zeroToOneNumber, arcDegreeNumber, rgbColorNumber, positiveNumber, positiveIntegerNumber.
Following the rationale, the Token expected to resolve for { $alias: 'a.unit' } must be a dimensionUnit.
Supported types
The SDTF defines a large variety of token types in order to capture (almost) any design decision.
bitmap
blur
border
breakpoint
color
dimension
duration
font
gradient
gradients
opacity
radius
radii
shadow
shadows
spacing
spacings
textStyle
transition
vector
zIndex
UI type helpers
bitmapFormat
borderStyle
borderStyleLineCap
cubicBezier
dimensionUnit
durationUnit
fontFamily
fontFeature
fontFeatures
fontFormat
fontStyle
fontWeight
shadowType
stepsTimingFunction
textAlignHorizontal
textAlignVertical
textDecoration
textTransform
vectorFormat
JSON inherited types
string
number
boolean
null
array
object
Constrained primitives
integerNumber
zeroToOneNumber
arcDegreeNumber
rgbColorNumber
positiveNumber
positiveIntegerNumber
percentageNumber
hexadecimalColorString
Group
A group is meant to order and nest design tokens semantically, it can be placed in any parent group or collection.
A group is a simple JSON object that can contain none to many groups, collections or tokens. With no mandatory keys or children, a group can be empty and represented as an empty object {}.
Collection
A collection is a special kind of group defining a mandatory $collection property. It constrain any enclosed token to respect a given set of modes.
A Collection can be placed within any group, nested at any level. But a Collection cannot be nested within another Collection.
$collection property
The $collection property is an object strictly containing the $modes key.
The $modes property is an array of mode names (string) defining the allowed modes for any token within the collection.
Getting started
Getting started with the Specify CLI
Automatic Installation
If you are on OS X or Linux, you can use the automated downloader, which will fetch the latest release version for you and install it:
To install a specific version, use the flag VERSION:
Installation via JS ecosystem
Installation via Homebrew
Coming soon
Installation via Scoop
Coming soon
Configuration file 101
Learn more about how to setup your Specify configuration file to generate design tokens and assets fitting your company standards.
Introduction
A configuration file helps you:
request design tokens and assets from a Specify repository
Properties
A configuration is composed of 3 main properties:
repository
personalAccessToken
rules
Repository
The name of the Specify repository you want to pull your design tokens and assets from.
Let's say we have the following repository in Specify called "all-design-data" located in the "@acme-inc" organization.
We target it like this:
Personal Access Token
The Specify personalAccessToken used to authenticate you.
Parser Rules
The Parsers Rules help you transform your design tokens and assets the way you want.
You can have as many rules as you want and you can have rules that transform several Token types at once.
Here are different kind of rules and parsers you can use to generate color tokens as CSS Custom Properties:
Examples
How to run these examples
The following examples are made to be used with the Specify CLI.
Requirements:
a Specify repository containing design tokens
Run all examples by copying the code and running the specify pull command.
Basic
Here's a basic configuration file that targets a Specify repository called design-system from the @acme-inc organization:
This example config file will return a colors.css file containing all design tokens stored in the design-system repository.
Here's an example of a token value returned by Specify:
Pull colors as CSS Custom Properties
Now let's update our previous configuration to only pull colors and transform them as CSS Custom Properties in RGB.
Here is the input returned by Specify and the output generated by Specify after executing our configuration.
SDTF Engine
Leverage the Specify core APIs to manipulate the SDTF token tree and produce any output you need.
Introduction
The SDTF Engine brings together the core APIs that enable most of Specify features to seamlessly integrate, whether you're working in Figma or Token Studio, managing GitHub pull-requests, or directly within your codebase with the SDK or the CLI.
all parsers written by Specify uses the SDTF Engine under the hood.
Token Tree CRUD API
At the core of the SDTF Engine, the query and mutation methods.
Query
The SDTF Engine provides a set of built-in getter functions to access tokens, groups, collections and aliases over the loaded token tree.
Mutation
The SDTF Engine provides a set of built-in mutation functions to locally manipulate the underlaying token tree in order to meet your project and/or company standards.
SDTF Query Language
Elevating your control over the data, the SDTF Query Language offers sophisticated techniques to navigate and cherry-pick the token tree with precision. You will find functions that allow complex querying patterns, matching specific criteria and conditions, vital for advanced manipulation and data extraction tasks.
With this powerful language at your disposal, it becomes easy to implement custom scenarios and data transformations.
Stateful Value API
The Stateful Value API grants direct access to examine the values assigned to tokens.
Through an exhaustive map interface, the API simplifies the process of keeping your design tokens and their implementations in sync despite the creation of aliases along the way.
HTTP API
Consume your design tokens and assets over HTTP requests.
Access raw data
Using the Specify HTTP API, you access the most barebone data directly out of our generation services. Thus, you can fetch your design tokens, manipulate them programmatically, and integrate them smoothly into any development workflow.
Work with any language
Your project cannot support JavaScript or TypeScript? Bring your own language and integrate seamlessly with Specify resources.
Generate upon request
Get started
The Specify HTTP API is read-only upon your design data.
To use the HTTP API, you'll need:
A Specify account with at least one repository, filled with design data from any source.
Overview
Take some time to understand the basic concepts of Specify. Getting to know its foundational ideas will help you glimpse into how to leverage the apps and APIs in your projects.
The Specify platform is based on the following pillars.
Above them, sit the engines:
Organization
As a Specify user, you belong to an organization.
In this organization, you create repositories to structure your projects.
All over Specify APIs, you access your organization using its namespace (e.g @specifyapp)
Repository
The repository is where the design data get stored, merged and eventually deleted over iterations.
Source
Collecting the design data
From this point on, you can synchronize your source(s) with Specify anytime, at a click of a button.
Repository with many sources
Data from many sources get automatically merged into a consolidated SDTF token tree. If Specify detects a conflict over sources, it will refuse to synchronize the first source that cause the conflict and turn it into an error state.
Destination
Distributing the design data
While the source part is highly automated and managed by Specify internals, the destination offers many levers of control over the transformation required to meet your company standards.
Two main APIs at stake here:
The Parsers Engine serves as the orchestrator for a series of functions, called designed to transform design data, in parallel and/or chained. By configuring , you customize how and where design tokens and assets are exported.
The Parsers Engine can operate both , using the Pipe Engine API over HTTP, and , through the . This dual capability enables it to be integrated into various workflows, offering flexibility whether working from remote servers, custom CI or directly within local development environments.
The Parsers Engine relies on the , which are actual converter implementations from the SDTF tokens to their representation in various formats and languages.
parsers: an array of
name: the name of the parser - to-json, to-tailwind over the .
Looking for how to configure the output property? 👉 review the reference.
Looking for a precise parser option? 👉 review the full .
To get started with the parser rules 👉 heads up to the resources.
are compatible with the remote execution.
For some destinations, like & the you need a Configuration file in order to keep track of your desired settings.
Define the source from which to fetch design data.
Describe the to configure your ouput.
Looking for the configuration file details? 👉 review the reference
Executed on the local environment, the parser rules are evaluated by the .
Only the are meant to be used in a local execution. In fact, you can apply any mutation on your token tree using the API, before generating the final output.
Get started with local execution 👉 review the guide.
Looking for the parsers settings? 👉 review the .
The utility parsers are only available to the of the Parsers Engine.
Name for your configuration file ()
The Specify CLI enables you to generate your code in any environment. Built on top of the , built with our newly released format (), and compiled with , this tool will help you create your CI/CD workflows.
How to get started? Easy as pie, follow our.
A destination belongs to a , it represents where the formatted design data flow on updates - think of or any automation you can come up with our and .
You can add many destinations into a single repository. Read more about the available compatible with Specify.
The , accessible via all , offers an high level abstraction to directly transform any SDTF token tree into many well-known technologies like CSS, tailwind, style-dictionary… Read more about .
The , accessible via the , offers a fine grained control over your SDTF token tree by allowing any mutation and post-process hooks, directly in your codebase.
If you are planning to use the or , you can head over to our that will help you start distributing your token to the main common use cases.
Example with dimensions in a group
Example with colors in a collection
The key used to index the $extensions object in $extensions: { [key: string]: JSONValue }MUST follow the in order to ensure collision-free collaboration of actors.
Whenever you want to work with the or the destination, you need to create a Configuration file to instruct the how to transform your design data, so it generate tokens that match your technical requirements.
transform them to fit your company standards thanks to
You can only target one repository per configuration file. Want to pull design tokens from several Specify repositories? Create several configuration files and run them with the Specify CLI ().
Need a personal access token?
Looking for the rules configuration? 👉 review the reference.
to target on a specific collection named "Colors" that contains our colors
to convert our colors in HSL
to change the name of our tokens and modes to kebabCase
to generate a CSS file containing our tokens
a valid personal access token ()
You can access the SDTF Engine APIs over the .
getAllTokenStates, getChildrenOf, getParentsOf, getAliasReference… - give you the opportunity to traverse and iterate over the different instances of TokenState, GroupState, and CollectionState.
updateTokenModeValue, updateTokenValue, moveToken, addToken, deleteToken, renameToken… - assemble into a CRUD API giving you the control to bend your data just right for your use cases, without ever making changes to the original design data from the repository.
Looking for the SDTF Query Language details? 👉 review the reference
The SDTF Query Language is accessible in the and in some via a dedicated option.
The HTTP API leverage the to let you instruct transformations to your SDTF design tokens right when you make the request making sure the data you receive is up to date with your repository.
A personal access token 👉 .
Jump to the section to get started.
The , accessible via all , offers an high level abstraction to directly transform any SDTF token tree into many well-known technologies like CSS, tailwind, style-dictionary…
The , accessible via the , offers a fine grained control over your SDTF token tree by allowing any mutation and post-process hooks, directly in your codebase.
A repository is exactly one design token tree built with the .
You can explore a repository designtoken tree by heading to the Specify .
A source belongs to a , it represents where the original design data come from - think of (Variables or Local Styles) or .
You can add many sources into a single repository. Read more about the available compatible with Specify.
Once a source is configured, Specify starts to collect your design data. Over this process, the acquires, validates and converts the original data into a SDTF token tree that get stored within the repository.
You can review your sources status by heading to any repository page on the Specify .
A destination belongs to a , it represents where the formatted design data get distributed on updates - think of or any automation you can come up with our and .
You can add many destinations into a single repository. Read more about the available compatible with Specify.
The , accessible via all , offers an high level abstraction to directly transform any SDTF token tree into many well-known technologies like CSS, tailwind, style-dictionary…
The , accessible via the , offers a fine grained control over your SDTF token tree by allowing any mutation and post-process hooks, directly in your codebase.
const dimensionToken = {
$type: 'dimension', // Mandatory
$value: { // Mandatory
default: { // Stands for "default mode", mode name can be any string not starting with "$"
value: 1, unit: '%' // Must be a valid value or reference for the type
}
},
$description: 'A dimension token', // Optional string
$extensions: { 'com.specifyapp.data': true } // Optional Record<string, JSONValue>
}
Step into the Specify SDK APIs to get fined grained access to your design data.
Introduction
Overview
The Specify Client API
The Specify Client manages:
your authentication credentials - personal access token
your access to your organization repositories
The SDTF Client API
The SDTF Client bridges the gap between the raw token tree stored into your repository - in Specify database - and the live token tree instance provided by the SDK.
Mutate the token tree locally
Since the client is instantiated locally, all changes made to the token tree are only affecting the current version of the client.
Then, create several updates:
Convert tokens to XXX
Specify CLI usage 101
Otherwise, if you're here to learn how to use the CLI, you're at the right place!
Authentication
Environment variable (recommended)
You can use the environment variable named SPECIFY_PAT
SPECIFY_PAT=xxxxxxxxxxxxxxxxxx specify pull
Flag
If you prefer a flag, you can use --personal-access-token or -p
If multiple credentials are used together, Specify will choose following this order:
the flag
the configuration file
the environment variable
Generate Files
Example: Export All Tokens and Assets In JSON
Getting started
Getting started with the Specify SDK.
Prerequisites
NodeJS >= 18.x
[Optional] Typescript >= 4.9
TypeScript vs JavaScript
We recommend using TypeScript for a better developer experience. TypeScript's autocompletion in your editor can save you numerous trips to the documentation by suggesting methods and options from the Specify APIs.
Installation
Let's pretend you have a front-end application structured as follows:
Create a specify directory
You'll start by creating a specify directory at the application level.
Initialize a JavaScript module
Using your terminal, navigate to the directory.
Within this directory, you initialize a JavaScript module by using the package manager of your choice - preferably the one you use to manage your application.
If you use vanilla JavaScript, you can skip the installation of the typescript package.
The init command creates a minimal package.json file where the dev dependencies will be added too. Then, you complete/override the content to match the following:
Note that "type": "module" is mandatory for the SDK to properly work.
Setup TypeScript
If you use vanilla JavaScript, you can skip this step.
Within the specify directory, you create a tsconfig.json file which matches the following configuration:
Prepare the environment secrets
Thus, create a .env file within the specify directory:
If you use a version control utility like git, you most likely want to add the specify/.env file to your ignore configuration.
Create a Specify Client
Within the specify directory, you create an extract.ts file. This TypeScript script will handle the extraction process by utilizing the personal access token specified in your .env file.
If you use vanilla JavaScript, you can name this file extract.js.
Authenticate
In order to consume the private data from a Specify repository, you must authenticate using your personal access token stored in .env.
Test your script
From your terminal, launch the script.
You should get a log such as:
List your organization repositories
Get a list of repositories belonging to your organization.
The produces finite and opinionated outputs, but sometimes you need to have more control over our generated files.
That's where the SDTF Client takes over and provide plenty of methods to work with any token tree.
Looking for how to get started with the SDK? 👉 heads up to the guide.
The SDTF Client offers versatile methods for working with token trees, enabling data manipulation, transformation, and conversion into various formats or languages, bridging the gap between stored and live token instances within your repository.
To access your data, you use the . You can then fetch a and use the to manipulate the data and transform to your desired custom format.
The SDTF Client API wraps up the which holds the lower level methods to work with the token tree.
You can create several instances of the same initial token tree - using
with predefined formatters using
with cherry-picking of a sub-tree using
with custom implementation using
and
Converting tokens is always a matter of iterating over the tokens of your tree and decide what to do with their value(s), their and potential .
Looking for usage? 👉 heads up to the guide.
This page is the starting point of multiple guides that will help you to learn how to use our CLI. If you still don't know what our CLI is, you can have a look right .
If you're not sure if you should use the or the , you can have a look to this .
Specify use a Personal Access Token for the authentication. You can create it from the . Once you have a personal access token, you can use it in two ways:
The personal access token in a config file is useful if you need to execute some custom business logic. To stay safe, you should use a library like to store credentials outside of the code.
The Specify CLI can be configured by default with a configuration file named .specifyrc.json . You can also override these settings .
The configuration file lets you describe your transformation pipelines (aka ) following the to generate your output. The guide provides full documentation of the configuration file API.
To interact with your Specify repositories you'll need to provide a Personal Access Token that you prefer to keep secret. For that reason, we recommend the use of the package.
Get a Personal Access Token from
Your configuration does not run? Get in touch with us on .
One of the benefits to work directly with the SDK is that you can update the tokens value on the fly to match exactly your needs. Before explaining you how to do it, it's important that you note that updating tokens won't run a remote update in your repository.
All the updates will be performed locally on the loaded SDTF, but that's it, there's no side effects
Importing the updaters
Before even updating the tokens, we need to import the updaters that will help us to perform the updates. Everything is grouped inside the updaters object:
import { updaters } from '@specifyapp/sdk'
Update the colors
If you need to have your colors to be converted to a specific format, you can use the prebuilt color updater:
An updater is in reality a function that looks like this:
import type { SDTFQuery, SDTFEngine } from '@specifyapp/specify-design-token-format'
function myUpdater(
options?: {}
applyTo?: SDTFQuery,
): Updater {
return (engine: SDTFEngine, applyToInner?: SDTFQuery) => {
const query = applyTo ?? applyToInner;
// Do the conversion
};
}
If you're wondering why there's 2 applyTo, it's because the first one is the one that you're passing when calling the function, and the second one is passed if the updater is called with withQuery.
Once implemented, you can use it the same way we're using the updaters above:
sdtfClient.update(myUpdater())
The above implementation works for a reusable updater, but if you exactly know what you want, you can do the following as well:
import type { SDTFEngine } from '@specifyapp/specify-design-token-format'
function myUpdater(engine: SDTFEngine) {
// Do something
}
sdtf.update(myUpdater)
Converting a token to XXX
If your goal is to create your own output, you'll have to go through 2 steps:
Converting the tokens to the desired output, e.g: CSS, Js, Swift, etc...
Formatting the converted tokens into the desired template
We can't know what's the perfect template for your needs, but we can definitely help you converting tokens to your desired output. That's why we created the converters.
What's a converter?
A converter is a function that takes a resolvable alias strategy, an unresolvable alias strategy, and returns a function that takes a TokenState and will convert it to any available format. This is the way to build your custom output with the SDK. We provide you the conversion, and you only have to format it the way you want. Here is an example:
This is as straightforward as it looks, but you're probably wondering what is the strategy const.
The alias strategies
Let's focus on what are the strategies. When working with the SDTF, you are probably aware that a token can contains an alias at a top level, mode level, or value level. When converting a token, we need to decide what we want to do with the aliases. In the case of resolvable aliases, there will be generally 2 strategies:
Resolve the alias to retrieve the value and use the value as is
If the target language supports it, convert the alias itself to a variable, alias, etc... Although it may sounds simple, the reality is that there's a lot of pitfalls, especially when trying to work with the aliases without resolving them. This is the reason why we provide premade strategies, so you don't have to go through all the pain of implementing it.
Note that there is strategies both for resolvable and unresolvable aliases. Generally speaking, the recommended way to work with a token is the following:
The most important here are the first lines. If the token is not fully resolvable, we just ignore it, and you should do it this way as much as possible. Working with unresolvable aliases is not really desirable, so it's better to just avoid doing it. That's why the default unresolvable alias strategy is to throw an error, and checking if the token is fully resolvable or not is enough to make sure you'll avoid a lot of problems.
Using a strategy
Let's take CSS as example, and compare the output of various strategies.
Resolve alias strategy
This strategy will resolve the token in order to retrieve the value and convert it to CSS:
This strategy is the default one for the unresolvable aliases. As the name is saying it, It'll throw an error if we encounter an unresolvable alias during the conversion:
This strategy is actually quite special. It'll convert unresolvable aliases to a CSS variable. Even if an alias is unresolvable, we still have a lot of informations on the target based on the path, mode, and the token referencing the alias.
Note that top level aliases lacks to much informations, so if this strategy encounter one, it'll throw an error.
Create your own strategy
If the provided strategies don't satisfy you, you can still decide to create your own strategy! In the case of a resolvable alias strategy, you'll have to create a function that follows this type:
type ResolvableAliasStrategy<
Return,
Composites extends SpecifyDesignTokenTypeName
> = <
Alias extends AllResolvableAlias = AllResolvableAlias,
>(
alias: Alias,
) => Alias extends ResolvableTopLevelAlias
? {
[mode: string]: Alias extends AllResolvableAlias<Composites>
? Record<string, Return>
: Return;
}
: Alias extends AllResolvableAlias<Composites>
? Record<string, Return>
: Return;
Let's breakdown the signature:
Return is the desired return type for your strategy. Generally it'll be the same than the converters
Composites is a union of the types of the composites tokens. Those tokens are expected to be converted to a Record<string, Return> as they have multiple outputs
About the Alias, it's a generic that will be one of these:
type AllResolvableAlias<
Type extends SpecifyDesignTokenTypeName = SpecifyDesignTokenTypeName,
> =
| ResolvableValueLevelAlias<Type>
| ResolvableModeLevelAlias<Type>
| ResolvableTopLevelAlias<Type>;
Finally, you can notice that in the case of a top level alias, you need to return an object containing the modes, and then the return value.
Here is an example of the CSS resolvable alias strategy:
We expect the return type to be a string, and the tokens font, textStyle and transition to return multiple values, thus, a Record<string, string>.
In general, you'll probably don't want to work with ResolvableAliasStrategy, but rather with the converter strategy, e.g: CssResolvableAliasStrategy. Here is an example of an implementation:
Primitives tokens are generally quite straightforward to convert to a different output. So almost every time, the output of a primitive token will be a single output. Here is an example with a dimension token converted to CSS:
Input:
{
value: 12,
unit: "px"
}
Output:
"12px"
Composites tokens
Composites tokens are a bit more complex than the simples ones. The main issue is that they contain a lot of informations, and most of the time we need multiple outputs to convert all the data. To do so, a converted composites token will output an object containing all the outputs. Here is an example with a transition token that we convert to a CSS output.
In the case of a transition, we can't assume on which property the transition will be applied, so we have to split everything in different tokens so you can build your transition on the property that you want.
If you want more informations on which tokens are primitives and which ones are composites, and on the inputs and outputs, you can have a look to the reference of each converters:
Retrieving and working with the tokens
Get a SDTFClient
It's the way of interacting with your tokens and generating content.
You would want to grab the SDTF JSON token tree of a repository anytime you want to: send the token tree over the network or debug an intermediate manipulation.
const jsonTokenTree = sdtfClient.getJSONTokenTree();
console.log(jsonTokenTree) // the object literal representation of the Specify Design Token data
Now that we know how to retrieve our SDTF, let's see how we can manipulate and retrieve our tokens.
Retrieving the tokens
There's multiple way to retrieve a token. If you want to work with a specific one you'll probably want to only get one, if you're developing a generic solution, you'll probably prefer iterating over many tokens. Let's have a look on how to do this.
Retrieving a single token
To retrieve a single token, you can just pick it by its path:
The TokenState instance will be your main access to your tokens. Through this, you can retrieve your token data or perform updates. But first, let’s put some context and try to figure out what this TokenState is trying to solve.
As you can see, there’s a lot of way to express a token, and dealing with all the possible cases is quite difficult. That’s why one of the goal of the TokenState is to help you to deal with everything.
How to differentiate the tokens?
Before even thinking about retrieving the value of a token, we need to know what type of token we’re working with.
It’s actually quite easy to know as there’s a type property in the TokenState :
But even if we know the type, a problem will remain: Typescript doesn’t. TokenState is quite a generic class as the default type is something that looks like this: TokenState<'dimension' | 'font' | 'breakpoint' | ...> .
So the first mission is to be able to narrow down the type to be able to work with it. To do so, there’s a pretty convenient function:
If you copy/paste this code inside your editor, Typescript will complain and gives you the following error: Type '(_: TokenState<"breakpoint", Value, Mode>) => string' is not assignable to type '(token: TokenState<"breakpoint", Value, Mode>) => number | undefined'.
Basically Typescript is unhappy that we return a number and a string. To fix the issue, there's 2 solutions:
Depending on the use case, you'll prefer the first over the second solution, or the second over the first.
How to get the token value ?
Now that we know how to get the TokenState that we want, we want to extract the value from it. As mentioned before, a token can have a lot of places that can contains an alias, so when retrieving the value, there’s 2 ways of doing it.
Ignoring aliasing
If you only want to get the raw value of a token and ignore the aliases, you can use the following function:
If you want to support the aliases in your output, you’ll need to handle them when they are some at the top level, mode level, or value level. To do so, we provide the Stateful Value API that helps you to make sure you handle all the possible cases. Let’s see an example and then break down everything.
All you need to do for the mode level is to return a value, and it'll be mapped to the right mode.
And finally the value level (we take a dimension token as an example):
.mapRawValue((dimension, mode) => {
const value = dimension
.value
// mapPrimitiveValue is not required if you only need the value inside
// without updating it
.mapPrimitiveValue(value => { ... })
.mapUnresolvableValueLevelAlias(alias => { ... })
.mapResolvableValueLevelAlias(alias => { ... })
.unwrap()
return value
})
If you call mapPrimitiveValue, it needs to be the first one to be called in order to avoid remapping results produced by mapUnresolvableValueLevelAlias or mapResolvableValueLevelAlias.
As you can see each step is always the same: handling unresolvable alias, resolvable alias and the value.
Resolving an alias
Sometimes, you need to use the precision of the stateful result API, but don't want to deal with the aliases at some levels. To avoid doing so, you can resolve an alias by calling resolveDeepValue, and you'll be left with handling the unresolvable alias and value case. Here is an example:
Although we could get rid of the resolvable alias case, handling the unresolvable case might still be too verbose. So let me introduce you to a nice pattern to only deal with values:
We will check if the token is fully resolvable
We'll use resolveDeepValue to remove the need of handling the resolvable aliases
We'll use unwrapValue to remove the need of handling the unresolvable case at the type level
Thanks to this pattern, we went from a really verbose API to something lighter.
Executing generation parsers
The SDK provides two main methods to face either the need of the flexibility or increased performance.
By default, the generation is run locally utilizing the host machine resources. To meet some environment limitation, any Specify's built-in parser can be executed remotely, on Specify servers.
Create parsers pipelines
With your SDTF client, you can create as many parsers pipelines as you need to generate your outputs.
The executePipelines is an asynchronous function that will actually execute the generation. Hence:
The results is a ParsersEngineResults instance, which comes with its own set of helper methods to work with the outputs and messages issued over the generation.
Note that results is plural since it can accumulate more than one parsers pipeline for a single execution.
Write the outputs to the file system
writeToDisk takes an optional base path and returns a promise containing a report of the written files and errors if any.
Run many concurrent parsers pipelines
All parsers pipelines passed to createParsersPipelines are run concurrently out of the box. It means, you can write the following:
And have both pipelines executed concurrently from the same initial token tree.
Chain parsers to run specific pre-generation
In some cases, you need to chain the parser functions to act like A -> B -> C where you are only interested in C. For that matter, you can leverage the chainParserFunctions util.
In this example, we want to optimize the content of the vector tokens with SVGO, and then, generate JSX components.
Execute a built-in parser function remotely
In some cases, you might need to deal with few host machine resources (like in many CI). To help with this, any Specify's built-in generation parser can be executed remotely by passing the shouldExecuteRemotely: true option.
Doing so, the SVGO process will be run on Specify's servers and the results will be returned to the SDK to be further processed / written on disk.
Create pipelines from parser rules configuration
With the SDK, the use of parser rules configuration reduces the interoperability with custom code, but can significantly increase the speed of a remote execution.
In order to build parsers pipelines from the SDTF client we need to call the createParsersPipelinesFromRules method.
Doing so, it creates an async parsers engine executor in the exact same manner it did for parser functions.
Run faster remote executions
Any built-in generation parser holds a shouldExecuteRemotely: boolean option to treat its inner execution as remote.
Yet, rules configuration also implement that option, allowing the SDK to collect all the remote rules and parsers, then sends out a single HTTP request for the whole execution.
Create your custom parser function
If the parsers that Specify is providing are not enough for your use case, you can create your own parser function!
Now that we are able to execute parsers locally, it means that parsers are simple functions, so creating a custom parser is only about writing a function. But before creating your own parser, you have to understand how a parser is working.
The next part will describe how parsers are working, but you'll quickly notice that it doesn't looks like the parsers above, e.g: an output option and a parser option. The reason for it is that all our parsers are actually functions that return a parser function. So don't worry if it doesn't looks like above, in the end it's all the same thing
The anatomy of a parser
A parser is a function that will take 3 parameters:
An input will be one of the type of ParsersEngineDataBox :
The ParserToolbox, which helps accumulate the output that will be written to your file system
An important thing to understand is that a parser has 2 outputs:
The return type of the function, that can be passed to another parser if chained
The output that you want to write to the file system (files, text, JSON, SDTF), and that'll be accumulated into the ParserToolbox
There's actually 2 reasons for this choice:
There's only 1 return value, but you can append as much output as you want to an accumulator
We need a difference between the output of a parser, and what we want to send to the next parser
Let's have a look to the output in itself.
The parser output
First, let's focus on the return. The output will be the input of the next parser if you use it inside a ParserChainer. So as the return is the input of the next parser, you probably guessed it: it's the same one for the input, which means one of ParsersEngineDataBox :
Most of the parsers take an SDTFDataBox as an input, and return it as the output as they don't modify anything and only output some files. So if you're not sure about what to return, just return the input.
So now that we know what is a parser, let's have a look to an example of parser that create a file with all the token's name:
Let's break down the example:
We use the engine to get all the names
We populate the output into the accumulator
Finally, we return the input as we didn't modify anything and don't need to return something else
Now that we have our custom parser, we can use it freely in the ParserPipeline or ParserChainer.
Specify SDK Cheatsheet
On this page you'll find a lot of common actions you'll probably want to perform when using the SDK
Creating Specify and SDTF clients
You will first create a Specify client, then authenticate, then create a SDTF client by fetching the repository token tree.
Updating tokens
Convert a token to XXX
Execute a parser
Retrieving data
Get a specific token
Get all the tokens
Map over all the tokens
Get a specific group
Get all the groups
Map over all the groups
Get a specific collection
Get all collections
Map over all the collections
Filtering data
Keeping a sub-graph from a path
If you only want a specific portion of the graph, you can cherry-pick using the pick function:
Keeping the children of a path
If you only want the children of a specific portion of the graph you can use the pick function this way:
Query a specific set of data
You can use the query method of the SDTFClient to create a copy of the current SDTF with only the tokens that'll match your query:
Remove tokens from the SDTF
You can use the remove method to delete tokens based on a query:
Renaming tokens
Rename a node
By not specifying any type, the method will rename any node as long as the path is valid.
Rename a collection
By specifying the type, the method will rename only a collection node.
Rename a group
By specifying the type, the method will rename only a group node.
Rename a token
By specifying the type, the method will rename only a token node.
You can refer to to see all the available colors.
You can refer to to see all the available casing.
You can refer to to see all the available units.
So if you want to create a custom updater, feel free to copy/paste the above function and implement it the way you want. You can refer to the to understand how to perform updates on the SDTF.
The is a class providing numerous methods to work with the design data stored using the Specify Design Token Format (SDTF).
Looking for details about the query? 👉 heads up to the concept.
Looking for more methods to retrieve tokens? 👉 heads up to the reference.
If we take a look at , it’s basically a JSON value where a lot of keys can be an alias rather than a value. Let’s have a look at all the possible cases with an example. Note that the following examples are 4 different ways of achieving the same result from a value point of view.
When it comes to generate code from your with the , you can leverage Specify's built-in and / or add your own custom implementation.
While being executed, the parsers engine produces outputs that gets returned within the instance which comes with few helper methods like writeToDisk
A is a JSON object representing a parsers pipeline where all parsers will be run sequencially. Rules configuration are primarily utilized within the configuration file for the or .
The following example is only an overview, if you need more details you can have a look .
The following example is only an overview, if you need more details you can have a look .
The following example is only an overview, if you need more details you can have a look .
You can find all the details about querying the data .
The object is composed of the following properties:
Name
Type
Required
Description
name
string
true
options
false
output
object
false
The output you want the parser to generate. In most cases, a file or a directory.
ParsersEngineDataBox
The parsers engine can take several input types called parsers engine data boxes. On start, the Parsers engine requires one of the data box types to be passed in as initial input.
The parsers produce different types of outputs based on your configuration and their proper capabilities. If not all the parsers accept an output configuration property, the ones which do always take a standardized type as input.
File
Use case: the parser is expected to produce exactly one file.
type FileOutput = {
type: 'file';
filePath: string;
}
Utility parsers help you mutate your token tree before generating final outputs.
Utility parsers do not have the output option since they mutate the internal state without producing any actual output.
Parser
Description
Usage example
This parser helps you change the case of names or modes over a SDTF graph.
This parser helps you convert the color formats of color compatible tokens over a SDTF graph.
This parser helps you convert units of dimension tokens (spacing, sizing, breakpoint, blur...) and composite tokens sub values (font-size, letter-spacing, border-width...).
This parser helps you transform your text style lineheight values relative to their font size.
This parser helps you filter a SDTF graph.
This parser helps you register a SDTF view that can be later used by generation parser to allow for partial outputs of the token tree with no destructive mutations.
This parser helps you select design tokens from specific mode(s).
This parser helps you prefix the name of your collections, groups and tokens from your SDTF token tree.
This parser helps you suffix the name of your collections, groups and tokens from your SDTF token tree.
This parser helps you replace a part or the whole name of your collections, groups and tokens from your SDTF token tree.
Generation parsers
Generation parsers help you generate your token tree into any technology / purposed oriented outputs.
Parser
Description
Usage example
This parser helps you transform design tokens in CSS Custom Properties.
This parser helps you generate text styles as CSS classes.
This parser helps you create CSS @font-face rules to import your font files.
This parser helps you generate a Flutter theme from all your design tokens coming from Specify.
This parser helps you pull design tokens as JavaScript objects for all token types and their respective getter functions.
This parser helps you pull design tokens in JSON with token values in JSON or CSS.
This parser helps you pull design tokens in JSON within an iterable array structure.
This parser helps you generate design tokens for Kotlin.
This parser helps you pull design tokens as a theme compatible with React Native and their respective helper functions.
This parser helps you generate text styles as SCSS mixins.
This parser helps you generate .scss files for each token type containing SCSS map and function / mixin to access the values of the tokens.
This parser helps you get your design tokens as a SDTF graph in JSON.
This parser helps you generate design tokens as Swift classes.
This parser helps you generate a Tailwind theme from all your design tokens coming from Specify.
This parser helps you pull design tokens as TypeScript objects for all token types and their respective getter functions.
This parser helps you generate JSX or TSX components from your vector assets.
This parser helps you generate TSX components from your vector assets.
This parser helps you generate SVG files from your vector assets.
This parser helps you generate PNG and JPG files from your bitmap assets.
This parser helps you generate files from any asset token: Bitmap, Font and Vector.
Manage font files
Learn how to add font files to your Specify repositories once you've synced text styles.
Introduction
Sources like Figma and Tokens Studio manages textStyle and font token types as parameters applied to the fonts available on the host machine.
To bridge that gap, we'll share with you some techniques you can leverage to keep your font files in sync with your font and text styles tokens.
Prerequisites
Before we start you need:
A Specify account with a repository
One or more font files in the following formats: ttf, woff, woff2, otf, eot.
#1 The easy way: upload font files in Specify
#2 Add font files by creating your own SDTF graph
1. Host your font files
You are free to host your font files anywhere you can grab a public link to give Specify the ability to fetch the binaries.
We recommend using a company cloud storage like Amazon S3.
2. Create a SDTF tokens file
To register your font files to Specify, you need to create a SDTF JSON file containing your font tokens with the URLs from your cloud provider.
Once executed, the font files are available within the ./public/fonts directory.
convert-dimension
This parser helps you convert units of dimension tokens (spacing, sizing, breakpoint, blur...) and composite tokens sub values (font-size, letter-spacing, border-width...)
The selection where to apply the transformation.
collection, group, token take a Regex string or true to select anything of the kind.
An SDTFQuery can be used for advance use cases.
applyToKeys
false
Select composite tokens sub-values to convert
excludeFormats
false
array
List of dimension formats you don't want to convert.
includeFormats
false
array
List of dimension formats you only want to convert.
Learn more about how to query your SDTF token graph.
Introduction
Your token system can be more complex than it seems. You will often need to interact with your token graph to transform a specific set of design tokens within a Specify configuration.
This article will help you understand how you can query your token graph to select a specific set of tokens.
Compatible parsers
Query structure
Every Query holds a single a where property being an object, to select one branch of the graph, or an array of objects, to select many branches of the graph (OR statement).
Type Query = { where: Where | Array<Where> }
The where property splits in 3 kinds: token, group, collection - offering a dedicated set of options to match against the given kind.
The name property accepts a RegExp for a value. These resources will help you debug your regular expressions:
Change the names or the modes of the selected items.
toCase
required
applyTo
required
Basic usage
This example helps you transform in kebabCase the name all collections, groups, tokens and modes. Use this example if you want to generate CSS Custom properties with the to-css-custom-properties parser.
This parser helps you transform your text style lineheight values relative to their font size.
Interface
Basic usage
The parsers you want to apply to transform your token tree. For further details see .
Looking for the parsers list and options? 👉 heads up to the reference
The name of the parser. Choose from .
The options relative to the parser you apply. Each parser has its own options. For further details see .
Many generation parsers can be placed in the same , as long as they all need the same transformed - or not - token tree and they all use the file or directory output setting.
This parser helps you generate raw token files for all your design tokens coming from Specify.
This parser help you optimize and transform your SVG strings with .
For both technical and legal reasons, Specify cannot extract font files from those sources, even though the is able to manage font files natively.
Create a new public or private repository on .
Create a new private or public bin on .
(Optional) Provide authentication credentials for your provider. Read more about managing .
Let's have a look to one of the that can be used into any configuration file:
We then generate our transformed SDTF graph in a JSON file thanks to the parser.
The case transformation to apply. Actual transform is done by the package.
The selection where to apply the transformation.
collection, group, token take a Regex string or true to select anything of the kind.
An can be used for advance use cases.
We eventually generate our transformed SDTF graph in a JSON file thanks to the parser.
We want to get all design tokens from the mode named "light"
We eventually generate our design tokens ass CSS variables in a CSS file thanks to the to-css-custom-properties parser.
.specifyrc.json
{
"version": "2",
"repository": "@organization/repository",
// Only use the personalAccessToken when working with the CLI
"personalAccessToken": "<your-personal-access-token>",
"rules": [
{
"name": "Only get tokens from the mode named 'light' and gererate tokens in CSS",
"parsers": [
{
"name": "select-modes",
"options": {
"modes": ["light"]
}
},
{
"name": "to-css-custom-properties",
"options": {
"selectorTemplate": "[data-theme=\"{{mode}}\"]"
},
"output": {
"type": "file",
"filePath": "public/css-custom-properties.css"
}
}
]
}
]
}
Whether to resolve the aliases of the graph.
Thus, preventing aliases to become unresolvable when their source is not included in the selected items.
allowUnresolvableAliases
false
boolean
true
Whether to allow unresolvable aliases to flow through.
This option is only available when resolveAliases = true
deduplicate
false
true | undefined
undefined
When you target tokens from different areas in your graph you can end up with tokens that will have the same name which will lead to an override. When set to true, this option will suffix tokens with a -{number} to prevent the override.
failOnMutate
false
true | undefined
undefined
By default, this parser mutates your graph. When set to true this option will make your pipeline return an error when your tokens respective path differ from their original one in the graph. Set this option to true if you want to be 100% aligned between design and code.
Basic usage: select all tokens from a group in a collection
Otherwise, if you're here to learn how to use the SDK, you're at the right place!
register-view
This parser helps you register a SDTF view that can be later used by generation parser to allow for partial outputs of the token tree with no destructive mutations.
The selection where to apply the transformation.
collection, group, token take a Regex string or true to select anything of the kind.
An SDTFQuery can be used for advance use cases.
This parser helps you transform design tokens into CSS Custom Properties.
Interface
Options
Basic usage
A design token can have modes, be nested in groups and be part of a collection. The following use case will generate a single CSS file containing core tokens and semantic tokens.
to-flutter
This parser helps you generate a Flutter theme from all your design tokens coming from Specify.
Interface
Options
Basic usage
to-json
This parser helps you pull design tokens in JSON with token values in JSON or CSS.
Interface
Basic usage - JSON token values
to-css-font-import
This parser helps you create CSS @font-face rules to import your font files.
Interface
Options
Basic usage
to-react-native
This parser helps you pull design tokens as a theme compatible with React Native and their respective helper functions.
Interface
Basic usage
to-scss-map
This parser helps you generate .scss files for each token type containing SCSS map and function / mixin to access the values of the tokens.
Interface
Options
Basic usage
to-javascript
This parser helps you pull design tokens as JavaScript objects for all token types and their respective helper functions.
Interface
Basic usage
to-json-list
This parser helps you pull design tokens in JSON within an iterable array structure.
Interface
Options
Return type
The parser produces a custom data structure representing the flatten token tree.
Basic usage
to-scss-mixin-text-style
This parser helps you generate text styles as SCSS mixins.
Interface
Options
Basic usage
suffix-by
This parser helps you suffix the name of your collections, groups and tokens from your SDTF token tree.
Interface
Options
Basic usage: Suffix color tokens
This page is the starting point of multiple guides that will help you to learn how to use our SDK. If you still don't know what our SDK is, you can have a look right .
If you're not sure if you should use the or the , you can have a look to this .
The target color format to convert to. Actual value conversion is done by the package.
We then generate our transformed SDTF graph in a JSON file thanks to the parser.
The selection where to apply the transformation.
collection, group, token take a Regex string or true to select anything of the kind.
An can be used for advance use cases.
If string: the parameter used for the . If your use case need to use flags prefer object notation.
The pattern of the regex used as first argument of the .
The flags to use for regex. In the regex constructor it's the second argument .
The value will used as replacement. is used to apply the replacement.
Set true to remove spaces before and after the transformed values. is used to trim.
The selection where to apply the transformation.
collection, group, token take a Regex string or true to select anything of the kind.
An can be used for advance use cases.
Parameter
Required
Type
Default
Description
Head towards our to see how you can use this parser with others to suit a common use case when working with CSS.
{
"version": "2",
"repository": "@organization/repository",
// Only use the personalAccessToken when working with the CLI
"personalAccessToken": "<your-personal-access-token>",
"rules": [
{
"name": "To React Native theme",
"parsers": [
{
"name": "to-react-native",
"output": {
"type": "file",
"filePath": "public/theme.js"
}
}
]
}
]
}
tokens.js
/**
* @typedef {'primitive.spacing.1'} DimensionPath - All the valid paths for the tokens of type dimension.
* To use this type you can do: `@type {import('path/to/myTokensFile').DimensionPath}`
*/
/**
* @typedef {'themedColor.highEmphasis'} ColorPath - All the valid paths for the tokens of type color.
* To use this type you can do: `@type {import('path/to/myTokensFile').ColorPath}`
*/
/**
* @typedef {DimensionPath | ColorPath} AllPath - All possible paths
*/
/**
* @typedef {typeof pathsByType} PathsByType - All the paths for a given token type. Needed for `getTokensByType`
*/
const pathsByType = /** @type {const} */ ({
dimension: [ 'primitive.spacing.1' ],
color: [ 'themedColor.highEmphasis' ]
});
/**
* @typedef {typeof colorModes[number]} ColorModes - All the valid modes of color.
* To use this type you can do: `@type {import('path/to/myTokensFile').ColorModes}`
*/
export const colorModes = /** @type {const} */ ([ 'dark', 'light' ]);
/**
* @typedef {typeof themedColorModes[number]} ThemedcolorModes - All the valid modes of themedColor.
* To use this type you can do: `@type {import('path/to/myTokensFile').ThemedcolorModes}`
*/
export const themedColorModes = /** @type {const} */ ([ 'light', 'dark' ]);
/**
@typedef {ColorModes | ThemedcolorModes} AllMode - All the available modes
*/
/**
* @typedef {typeof tokens} Tokens - All the tokens.
* Use `getTokenByMode` to retrieve one.
*/
export const tokens = /** @type {const} */ ({
'primitive.spacing.1': '4px',
'themedColor.highEmphasis': { dark: '#ffffff', light: '#000000' }
});
/**
* Retrieve any token for a given mode. If available, the default mode will be: 'default'
* @template {AllPath} Path - A generic extending all the possible paths
* @template {Tokens[Path] extends Record<string, any>
? keyof Tokens[Path]
: undefined} Mode - A generic representing all the valid modes for a given path
* @template {Tokens[Path] extends Record<string, any>
? Tokens[Path][Mode extends undefined ? never : Mode]
: Tokens[Path]} Return - The return type
* @param {Path} path - The path to the token
* @param {Mode} mode - The mode of the token you want to retrieve
* @returns {Return} - The value of a token for a given mode
*/
export function getTokenByMode(path, mode) {
if (!tokens[path]) {
throw new Error("Path: '" + path + "' doesn't exist. Here are all the valid paths:\n- " + Object.keys(tokens).join('\n- '))
}
if (typeof tokens[path] !== 'object') {
return tokens[path] ;
}
if (!mode) throw new Error('Mode is undefined but it should be one of ' + Object.keys(tokens[path]).join(', ') + ' for path: ' + path);
if (!tokens[path][mode]) {
throw new Error("Invalid mode '" + mode.toString() + " at path '" + path + "', here are all the valid modes:\n- " + Object.keys(tokens[path]).join('\n- '))
}
return tokens[path][mode]
}
/**
* Retrieve all the tokens for a specific type (color, dimension, etc...).
* Note that the value will either be a string or an object if the token has modes
* @template {keyof PathsByType} Type - A generic extending all the possible types
* @template {Tokens[PathsByType[Type][number]]} Token - A generic representing a union of all the outputs
* @param {Type} type - The path to the token
* @returns {Array<Token>} - An array with all the values
*/
export function getTokensByType(type) {
if (!pathsByType[type]) {
throw new Error('The type: \'' + type + '\' does not exist')
}
return pathsByType[type].map(path => tokens[path]);
}
{
"version": "2",
"repository": "@organization/repository",
// Only use the personalAccessToken when working with the CLI
"personalAccessToken": "<your-personal-access-token>",
"rules": [
{
"name": "To JavaScript",
"parsers": [
{
"name": "to-javascript",
"output": {
"type": "file",
"filePath": "tokens.js"
}
}
]
}
]
}
tokens.js
/**
* @enum {string} All the valid paths for the collection colors.
* Use it when calling `getColorsTokenByMode`
*/
export const colorsColorPath = {
'colors.Core.blue-100': 'colors.Core.blue-100',
'colors.Core.blue-700': 'colors.Core.blue-700',
'colors.semantic.background.button.primary.hover': 'colors.semantic.background.button.primary.hover'
};
/**
* All the modes of the collection colors.
* Use it when calling `getColorsTokenByMode`
*/
export const colorsModes = [ 'light', 'dark' ];
/**
* All the tokens of the collection colors.
* Use `getColorsTokenByMode` to retrieve the tokens
*/
export const colors = {
'colors.Core.blue-100': { dark: 'rgb(229, 29, 29)', light: 'rgb(255, 255, 255)' },
'colors.Core.blue-700': { dark: 'rgb(229, 0, 0)', light: 'rgb(255, 200, 255)' },
'colors.semantic.background.button.primary.hover': { dark: 'rgb(229, 29, 29)', light: 'rgb(255, 200, 255)' }
};
/**
* Retrieve a token for the collection 'colors'.
* @param {keyof typeof colorsPath} path - The path to the token
* @param {'light' | 'dark'} mode - The mode of the token you want to retrieve
* @returns {number | string} The value of a token for a given mode
*/
export function getColorsTokenByMode(path, mode) {
if (!colors[path]) {
throw new Error("Path: '" + path + "' doesn't exist for collection 'colors'. Here are all the valid paths for each type:" + `
- color:
- colors.Core.blue-100
- colors.Core.blue-700
- colors.semantic.background.button.primary.hover`)
}
if (!colors[path][mode]) {
throw new Error("Invalid mode '" + mode.toString() + "' for collection 'colors' at path '" + path + "', here are all the valid modes:\n- " + Object.keys(colors[path]).join('\n- '))
}
return colors[path][mode]
}
{
"version": "2",
"repository": "@organization/repository",
// Only use the personalAccessToken when working with the CLI
"personalAccessToken": "<your-personal-access-token>",
"rules": [
{
"name": "Generate tokens as a Tailwind theme",
"parsers": [
{
"name": "to-tailwind",
"output": {
"type": "file",
"filePath": "theme.js"
}
}
]
}
]
}
{
"version": "2",
"repository": "@organization/repository",
// Only use the personalAccessToken when working with the CLI
"personalAccessToken": "<your-personal-access-token>",
"rules": [
{
"name": "To TypeScript",
"parsers": [
{
"name": "to-typescript",
"output": {
"type": "file",
"filePath": "tokens.ts"
}
}
]
}
]
}
tokens.js
/**
* @enum {string} All the valid paths for the collection colors.
* Use it when calling `getColorsTokenByMode`
*/
export const colorsColorPath = {
'colors.Core.blue-100': 'colors.Core.blue-100',
'colors.Core.blue-700': 'colors.Core.blue-700',
'colors.semantic.background.button.primary.hover': 'colors.semantic.background.button.primary.hover'
} as const;
export type colorsColorPathType = keyof typeof colorsColorPath;
export type colorsPathType = colorsColorPathType;
/**
* All the modes of the collection colors.
* Use it when calling `getColorsTokenByMode`
*/
export const colorsModes = [ 'light', 'dark' ] as const;
export type colorsModesType = typeof colorsModes[number];
/**
* All the tokens of the collection colors.
* Use `getColorsTokenByMode` to retrieve the tokens
*/
export const colors = {
'colors.Core.blue-100': { dark: 'rgb(229, 29, 29)', light: 'rgb(255, 255, 255)' },
'colors.Core.blue-700': { dark: 'rgb(229, 0, 0)', light: 'rgb(255, 200, 255)' },
'colors.semantic.background.button.primary.hover': { dark: 'rgb(229, 29, 29)', light: 'rgb(255, 200, 255)' }
} as const;
/**
* Retrieve a token for the collection 'colors'.
* @param {keyof typeof colorsPath} path - The path to the token
* @param {'light' | 'dark'} mode - The mode of the token you want to retrieve
* @returns {number | string} The value of a token for a given mode
*/
export function getColorsTokenByMode<T extends colorsPathType, M extends keyof typeof colors[T]>(path: T, mode: M) {
if (!colors[path]) {
throw new Error("Path: '" + path + "' doesn't exist for collection 'colors'. Here are all the valid paths for each type:" + `
- color:
- colors.Core.blue-100
- colors.Core.blue-700
- colors.semantic.background.button.primary.hover`)
}
if (!colors[path][mode]) {
throw new Error("Invalid mode '" + mode.toString() + "' for collection 'colors' at path '" + path + "', here are all the valid modes:\n- " + Object.keys(colors[path]).join('\n- '))
}
return colors[path][mode]
}
to-swift
This parser helps you generate design tokens as Swift classes.
When set to true, you will have both core tokens and alias tokens in each CSS scopes thus making alias tokens always resolvable.
allowUnresolvable
false
boolean
false
When set to true, you'll be able to generate alias CSS variables targeting tokens which are not generating in the same scope or file (e.g., if you want a primitive.css and semantic.css files).
When set to true, tokens will be named with the tokenNotInCollectionNameTemplate option.
withSDTFView
false
string
all
false
string
Select all collections, groups and tokens in your SDTF token graph.
This parser helps you generate TSX components from your vector assets.
Interface
Options
Basic usage
The pattern used to generate the CSS selector name(s). It must match template syntax.
You can use collection, mode and groups names.
The pattern used to generate token names. It must match template syntax.
You can use collection, mode,groups and token names.
The pattern used to generate token names when they are located outside of collections. It must match template syntax.
You can use mode,groups and token names.
The name of a registered view. See for more details using the CLI or GitHub.
The selection where to apply the transformation.
collection, group, token take a Regex string or true to select anything of the kind.
An can be used for advance use cases.
The mustache template used to generate the file path to write to the file system.
Available variables:
parents: group and collection names of the token's parents
name: the name of the asset token
mode: the name of the current mode
extension: the file extension extracted from the token
The mustache template used to generate the file path to write to the file system.
Available variables:
parents: group and collection names of the token's parents
name: the name of the asset token
mode: the name of the current mode
extension: the file extension extracted from the token
The mustache template used to generate the file path to write to the file system.
Available variables:
parents: group and collection names of the token's parents
name: the name of the asset token
mode: the name of the current mode
extension: the file extension extracted from the token
Basic usage - Single mode
Our vector has a default mode and is in a group named "icons".
The parser will generate the following output: {directoryPath}/{groups}/{vectorName}.svg
A collection will generate a folder at the top level
The default level refers to the SDTF Token Type associated SD Category → {collectionName?}/{SDCategory}
The next folder level is the name of the potential first group containing the token → {collectionName?}/{SDCategory}/{1stLevelGroupName?}
The default filename is the name of the first group, or the name of the each mode the token might have, or base.json → {collectionName?}/{SDCategory}/{ mode? | 1stLevelGroupName? | base}.json (priority order for filename: groupName > mode > base)
The token path inside the file must match the token file path with the following priority order: collection > SDCategoryType > Mode > Groups
The client to use SDTFEngine and Parsers Pipeline APIs. It provides methods for interacting with the token tree of a repository.
Properties
engine
This property represents the SDTF engine used by the SDTFClient.
repository
This property represents the repository that the SDTFClient is interacting with.
Methods
getJSONTokenTree
Returns the JSON token tree from the current repository.
clone
Create a new SDTFClient instance to avoid mutating the current token tree. Especially useful when you want to perform multiple distinct operations on the same token tree.
pick
Narrow the current token tree by picking a subtree based on the given path.
query
Create a clone of the current SDTF and only keep the selection of the query. When creating a new tree it's possible that tokens, groups and collections names will collide.
renameNode
Rename a node to a new name. If you specify a type, it'll rename the node only if it's matching the type parameter. If it doesn't, it'll throw an error.
Example
update
Execute an update on the current token tree. Note that the update won't be applied to the remote repository.
withQuery
Execute multiple updater functions with the same query.
resolveAliases
Resolve aliases in the current token tree. Useful before pick to avoid unresolvable aliases.
remove
Narrow the current token tree by removing any matching node based on the given query.
reset
Resets the current token tree to its initial value. The initial value being the token tree of the repository at the time of the creation of the first SDTFClient instance.
executeEngine
Tap into the current token tree to perform custom side effects.
forEachTokenState
Iterate against the tokenStates of the current token tree.
mapTokenStates
Iterate against the tokenStates of the current token tree, and accumulate the results in an array.
getTokenState
Get a token state for a given path.
getAllTokenStates
Get all the token states.
forEachCollectionState
Iterate against the collectionStates of the current token tree.
mapCollectionStates
Iterate against the collectionStates of the current token tree, and accumulate the results in an array.
getCollectionState
Get a collection state for a given path.
getAllCollectionStates
Get all the collection states.
forEachGroupState
Iterate against the groupStates of the current token tree.
mapGroupStates
Iterate against the groupStates of the current token tree, and accumulate the results in an array.
getGroupState
Get a group state for a given path.
getAllGroupStates
Get all the group states.
forEachQueryResult
Iterate against the nodeStates given by the query.
mapQueryResults
Iterate against the nodeStates given by the query, and accumulate the result in an array.
createParsersPipelines
Create a parsers engine executor from the custom or built-in parser functions passed as arguments. All pipelines are executed in parallel, if you need to chain parsers, have a look to the chainParserFunctions util.
createParsersPipelinesFromRules
Create a parsers engine executor from the built-in parser rules passed as arguments. All pipelines are executed in parallel, if you need to chain parsers, have a look to the chainParserFunctions util.
Unlike , this one doesn't have any options yet.
Follow the guide.
Authenticates the client with a Personal Access Token. Can be generated at
The SDTF Query Language is a JSON structure describing several match criteria used to select nodes - tokens, groups and collections - within the token tree.
Examples
Query Language Structure
Every SDTFQuery holds a single a where property being:
an object: to select one branch of the graph
an array of objects: to select many branches of the graph - equivalent to an OR statement.
type SDTFQuery = { where: Where | Array<Where> }
The where property splits in 3 kinds: token, group, collection - offering a dedicated set of options to match against the given kind.
function createTokenModeValue(param:{
atPath: Array<string>,
mode: string,
// We cannot know with type of the value since no type is enforced
value: unknown,
}): void;
function deleteTokenModeValue(param: {
atPath: Array<string>;
mode: string;
}): void;
function deleteToken(param: { atPath: Array<string> }): void;
function moveToken(param: {
atPath: Array<string>;
toPath: Array<string>;
}): void;
Get all tokenState instances from the tokens token tree.
function getAllTokenStates(): Array<TokenState>;
getAllGroupStates
Get all groupState instances from the tokens token tree.
function getAllGroupStates(): Array<GroupState>;
getAllCollectionStates
Get all collectionState instances from the tokens token tree.
function getAllCollectionStates(): Array<CollectionState>;
getAllNodeStates
Get all tokenState, groupState and collectionState instances from the tokens token tree.
function getAllNodeStates(): Array<TokenState | GroupState | CollectionState>;
getTokenChildrenOf
Get the tokenState instances that are children of the given path.
function getTokenChildrenOf(path: Array<string>): Array<TokenState>;
getGroupChildrenOf
Get the groupState instances that are children of the given path.
function getGroupChildrenOf(path: Array<string>): Array<GroupState>;
getCollectionChildrenOf
Get the collectionState instances that are children of the given path.
function getCollectionChildrenOf(path: Array<string>): Array<CollectionState>;
getChildrenOf
Get the tokenState, groupState and collectionState instances that are children of the given path.
function getChildrenOf(path: Array<string>, depth: number): Array<TokenState | GroupState | CollectionState>;
getParentsOf
Get the groupState and collectionState instances that are parents of the given path.
function getParentsOf(path: Array<string>, depth: number): Array<TokenState | GroupState | CollectionState>;
getGroupChildren
Get groupState instances that are direct children of the given path.
function getGroupChildren(path: Array<string>): Array<GroupState>;
getTokenChildren
Get tokenState instances that are direct children of the given path.
function getTokenChildren(path: Array<string>): Array<TokenState>;
getCollectionChildren
Get collectionState instances that are direct children of the given path.
function getCollectionChildren(path: Array<string>): Array<CollectionState>;
renderJSONTree
Get the JSON representation of the tokens token tree.
function renderJSONTree(renderOptions: RenderOptions): JSON;
getAliasReference
Get the aliasReference instance from given coordinates.
function getAliasReference(
from: AliasReferenceCoordinates
): Result<AliasReference, SDTFError>;
getAllAliasReferences
Get all aliasReference instances from the tokens token tree.
function getAllAliasReferences(): Array<AliasReference>;
getAliasReferencesTo
Get all aliasReference instances that reference the given "to" coordinates.
function getAliasReferencesTo(
to: Partial<AliasReferenceCoordinates>,
options: AliasReferenceResolvabilityOptions
): Array<AliasReference>;
getAliasReferencesFrom
Get all aliasReference instances that reference the given "from" coordinates.
function getAliasReferencesFrom(
from: Partial<AliasReferenceCoordinates>,
options: AliasReferenceResolvabilityOptions
): Array<AliasReference>;
getStatefulAliasReference
Get the statefulAliasReference instance of the given "from" coordinates.
function getStatefulAliasReference(
from: AliasReferenceCoordinates
): Result<StatefulAliasReference, SDTFError>;
getStatefulAliasReferencesTo
Get the statefulAliasReference instances that reference the given "to" coordinates.
function getStatefulAliasReferencesTo(
to: Partial<AliasReferenceCoordinates>,
options: AliasReferenceResolvabilityOptions
): Array<StatefulAliasReference>;
getStatefulAliasReferencesFrom
Get the statefulAliasReference instances that reference the given "from" coordinates.
function getStatefulAliasReferencesFrom(
from: Partial<AliasReferenceCoordinates>,
options: AliasReferenceResolvabilityOptions
): Array<StatefulAliasReference>;
The initial state to launch the parsers engine from.
rules
The parser rule definitions to instruct the transformation and generation pipelines.
returnedKeys
Record<string, boolean | undefined> | undefined
Select which response keys should be present. Defaults to true.
Parser Rules templates
Automatically distribute your design tokens and assets according to your organization's standards with our ready-to-use configuration templates.
Ready-to-use configuration templates for your next project
This section will help you get started with ready-to-use configuration template. Each configuration file will be filled by one or several configuration rules.
SDTF
This template helps you pull your design tokens in the SDTF format in a JSON file.
This example uses the following parser:
React Native
This template helps you generate your design tokens as a React Native theme and icons as JSX components
This example uses the following parsers:
JSON
This template helps you pull your design tokens in JSON.
This example uses the following parser:
Flutter
This template helps you generate your design tokens in a dart file and icons as SVG files.
This example uses the following parsers:
CSS Custom Properties
This template is dedicated for Web developers using CSS. It helps you generate all types of design tokens as CSS Custom Properties in their respective CSS file and it helps you to optimize your SVG's.
This example uses 5 different parsers:
Tailwind
This template helps you generate your design tokens as a Tailwind theme.
This example uses the following parsers:
Specify CLI
Here you can find all the detailed informations about the CLI
Global flags
-h, --help
Show the help
-v, --version
Show the current version of the CLIx
-C, --config-path [configPath]
The path to your JSON or Javascript config file, or the folder containing all your configs (default: .specifyrc.json)
-p, --personal-access-token <personalAccessToken>
Your personal access token. . It will try to read it from the env var SPECIFY_PAT as well.
-r, --repository <repository>
The repository containing the design tokens you're requesting. It follows the pattern @organizationName/repositoryName. It will try to read it from the env var SPECIFY_REPOSITORY as well.
Init
Generate a Specify ready-to-use configuration to pull your design data from your Specify repository.
For now it will only generate an empty config file, but we will bring back the template selection soon
Flags
--root [.]
By default everything is generated in the current dir, but you can choose a different path to generate your configuration file (Default: .)
Pull
Pull the tokens from the repository following the configs
Flags
No flags for now
Playground
Learn how to use the Specify Playground to iterate more easily on your configuration files
Introduction
The Specify Playground helps you run parsers against a token graph and see the generated output in live. It's a great tool to help you iterate on your configuration files or try new parsers on the go.
Usage
The middle panel contains your Specify configuration rule
The right side panel displays the generated code
Specify CLI VS Specify SDK
TL;DR - The CLI is faster to get started, but the SDK is more flexible and can match exactly what you need
Overview
Setup
CLI
In the case of the CLI, you'll first need to install the CLI:
And then create a .specifyrc.json :
SDK
Then you, you have to create a file where we'll import all the installed dependencies:
Running a parser
CLI
We first need to fill up a bit the configuration file with the parser we want to run:
Then we can run everything through the CLI:
SDK
On the SDK side, there's two way of doing it.
Running parsers locally
The main interest of the SDK is to be able to run everything locally. To do so, you can do the following:
Running parsers remotely
Running parsers remotely is basically wrapping the configuration into the SDK:
Filtering the tokens
CLI
To do so, we'll need to introduce a new parser in the configuration file:
SDK
Because the SDK is loading the SDTF, we can work directly with it. No need to run a parser, we can just execute filtering methods, and then generate our tokens:
Updating tokens
CLI
Just like before, it can be done through a parser:
SDK
Converting a token to a specific format
CLI
This cannot be done with the CLI.
SDK
Execute the against a given input and
Array<>
Make sure to read the concept to better understand how configuration file works with Specify.
Template
Description
This template is dedicated for Web developers using CSS. It helps you generate all types of design tokens as CSS Custom Properties in their respective CSS file.
This template is dedicated for Web developers using Tailwind theme.
This template helps you generate your design tokens in a dart file and icons as SVG files.
This template helps you pull your design tokens in the SDTF format in a JSON file.
This template helps you pull your design tokens in JSON.
to generate your design tokens in SDTF
If you use the CLI, you need to fill three properties:
repository is @organization/repository
personalAccessToken which you can generate
rules are where you provide parsers and compatible options
.specifyrc.json
{
"version": "2",
"repository": "@organization/repository",
// Only use the personalAccessToken when working with the CLI
"personalAccessToken": "<your-personal-access-token>",
"rules": [
{
"name": "Generate tokens in SDTF",
"parsers": [
{
"name": "to-sdtf",
"output": {
"type": "file",
"filePath": "output/tokens.json"
}
}
]
}
]
}
If you use the GitHub, you need to fill 4 properties:
repository is @organization/repository
head lets you set the branch your PR will be created on
base lets you set the branch your PR will be merged on
rules lets you transform tokens by chaining parsers
The left side panel contains the SDTF graph you'll run your rules against. It's editable and you're free to use your own SDTF graph which you can get with the parser
Historically, if you wanted to convert your tokens to various outputs: , , ... you could only distribute your tokens thanks to a configuration file. With the introduction of the , you might want to know which option suits your needs, so let's compare them!
This page will be an overview of both options, so if you need more details, you can have look to the page, and the page.
Specify CLI
Specify SDK
For the SDK, you'll first want to install the dependencies of the SDK, and the :
There's actually a way to choose which parser runs locally, and which one runs remotely, you can learn more about it .
Again, as the SDK is loading the SDTF, we can work directly with it through the update method and an :
Here is an example of converting a token to CSS, more detals on the conversion can be found .
Make sure you have connected your GitHub account with your Specify account. Head toward to learn more.
Make sure you have connected your GitHub account with your Specify account. Head toward to learn more.
Make sure you have connected your GitHub account with your Specify account. Head toward to learn more.
Make sure you have connected your GitHub account with your Specify account. Head toward to learn more.
Make sure you have connected your GitHub account with your Specify account. Head toward to learn more.
Make sure you have connected your GitHub account with your Specify account. Head toward to learn more.