Preprocessors
Starting in version 4.0, you can define custom preprocessors to process the dictionary object as a whole, after all token files have been parsed and combined into one. This is useful if you want to do more complex transformations on the dictionary as a whole, when all other ways are not powerful enough.
Preprocessors can be applied globally or per platform.
Applying them per platform means the tokens already have some more metadata on them such as “filePath” and “path”,
and the options object resembles the PlatformConfig
rather than the SD global config options.
It also allows you to preprocess on a per platform basis, while global means you won’t have to repeat the same preprocessing because it will happen once on a global level, so essentially applies to all platforms.
See lifecycle diagram for a visual diagram of the order of the lifecycle hooks.
That said, preprocessing the full dictionary gives ultimate flexibility when needed.
Preprocessor structure
A preprocessor is an object with two props:
name
: the name of the preprocessorpreprocessor
a callback function that receives the dictionary and SD options or platform config as parameters, and returns the processed dictionary
const myPreprocessor = { name: 'strip-third-party-meta', preprocessor: (dictionary, options) => { delete dictionary.thirdPartyMetadata; return dictionary; },};
Asynchronous callback functions are also supported, giving even more flexibility.
const myPreprocessor = { name: 'strip-props', preprocessor: async (dictionary, options) => { const propsToDelete = await someAPICall();
propsToDelete.forEach((propName) => { delete dictionary[propName]; });
return dictionary; },};
Using preprocessors
First you will need to tell Style Dictionary about your parser. You can do this in two ways:
- Using the
.registerPreprocessor
method - Inline in the configuration
.registerPreprocessor
import StyleDictionary from 'style-dictionary';
StyleDictionary.registerPreprocessor(myPreprocessor);
Inline
export default { hooks: { preprocessors: { 'strip-props': myPreprocessor, }, }, // ... the rest of the configuration};
Applying it in config
{ "source": ["**/*.tokens.json"], "preprocessors": ["strip-props"]}
or platform-specific:
{ "source": ["**/*.tokens.json"], "platforms": { "css": { "transformGroup": "css", "preprocessors": ["strip-props"] } }}
Preprocessor examples
Stripping description property recursively in the entire dictionary object:
StyleDictionary.registerPreprocessor({ name: 'strip-descriptions', preprocessor: (dict, options) => { // recursively traverse token objects and delete description props function removeDescription(slice) { delete slice.description; Object.values(slice).forEach((value) => { if (typeof value === 'object') { removeDescription(value); } }); return slice; } return removeDescription(dict); },});
Default preprocessors
There are two default preprocessors that are always applied and run after other custom preprocessors do:
typeDtcgDelegate
, for DTCG tokens, make sure the$type
is either already present or gets inherited from the closest ancestor that has it defined, so that the$type
is always available on the token level, for ease of useexpandObjectTokens
, a private preprocessor that will expand object-value (composite) tokens when user config has this enabled.