Skip to content

Commit

Permalink
chore: update docs for reference utils
Browse files Browse the repository at this point in the history
  • Loading branch information
jorenbroekema committed Dec 7, 2023
1 parent 92fd7dd commit 47b26e5
Show file tree
Hide file tree
Showing 2 changed files with 226 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- [Architecture](architecture.md)
- [Using the CLI](using_the_cli.md)
- [Using the NPM Module](using_the_npm_module.md)
- [Using reference utilities](using_reference_utils.md)
- [API](api.md)
- [Parsers](parsers.md)
- [Preprocessors](preprocessors.md)
Expand Down
225 changes: 225 additions & 0 deletions docs/using_reference_utils.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
# Using Reference Utilities

The Style Dictionary npm module exposes a `utils` endpoint that contains some helpful functions for finding and resolving references.

## Installation

```bash
$ npm install -D style-dictionary
```

## Usage

### usesReference

Whether or not a token value contains references

```javascript
import StyleDictionary from 'style-dictionary';
import { usesReference } from 'style-dictionary/utils';

usesReference('{foo.bar}'); // true
usesReference('solid {border.width} {border.color}'); // true
usesReference('5px'); // false
usesReference('[foo.bar]', {
opening_character: '[',
closing_character: ']',
}); // true
```

### resolveReferences

Takes a token value string value and resolves any reference inside it

```javascript
import StyleDictionary from 'style-dictionary';
import { resolveReferences } from 'style-dictionary/utils';

const sd = new StyleDictionary({
tokens: {
colors: {
black: {
value: '#000',
type: 'color',
},
},
spacing: {
2: {
value: '2px',
type: 'dimension',
},
},
border: {
value: 'solid {spacing.2} {colors.black}',
},
},
});
resolveReferences(sd.tokens.border.value, sd.tokens); // "solid 2px #000"
resolveReferences('solid {spacing.2} {colors.black}', sd.tokens); // alternative way, yet identical to line above -> "solid 2px #000"
```

### getReferences

Whether or not a token value contains references

```javascript
import StyleDictionary from 'style-dictionary';
import { getReferences } from 'style-dictionary/utils';

const sd = new StyleDictionary({
tokens: {
colors: {
black: {
value: '#000',
type: 'color',
},
},
spacing: {
2: {
value: '2px',
type: 'dimension',
},
},
border: {
value: 'solid {spacing.2} {colors.black}',
},
},
});

getReferences(sd, sd.tokens.border.value);
getReferences(sd, 'solid {spacing.2} {colors.black}'); // alternative way, yet identical to line above
/**
* [
* { value: '2px', type: 'dimension' },
* { value: '#000', type: 'color' }
* ]
*/
```

#### Complicated example

You can use the `getReferences` utility to create your own custom formats that have `outputReferences` capability.

```js
import StyleDictionary from 'style-dictionary';
import { usesReference, getReferences } from 'style-dictionary/utils';

const { fileHeader } = StyleDictionary.formatHelpers;

const sd = new StyleDictionary({
tokens: {
colors: {
black: {
value: '#000',
type: 'color',
},
},
spacing: {
2: {
value: '2px',
type: 'dimension',
},
},
zIndex: {
// number example.. which should stay a number in the output
aboveFold: {
value: 1,
type: 'other',
},
},
semantic: {
bg: {
primary: {
value: '{colors.black}',
type: 'color',
},
},
},
border: {
value: 'solid {spacing.2} {semantic.bg.primary}',
},
},
platforms: {
es6: {
transformGroup: 'js',
files: [
{
format: 'es6',
destination: 'output.js',
options: {
outputReferences: true,
},
},
],
},
},
});

// More complex case
// Note that this example format does not account for token values that are arrays or objects
StyleDictionary.registerFormat({
name: 'es6',
formatter: (dictionary) => {
const { allTokens, options, file } = dictionary;
const isNumeric = (str) => {
if (typeof str !== 'string') return false;
return (
!isNaN(str) && // use type coercion to parse the _entirety_ of the string (`parseFloat` alone does not do this)...
!isNaN(parseFloat(str)) // ...and ensure strings of whitespace fail
);
};

const compileTokenValue = (token) => {
let value = `${token.value}`;
const original = `${token.original.value}`;
const originalIsReferenceExclusively = original.match(/^\{.+\}$/g);
if (options.outputReferences && usesReference(original)) {
value = original;
if (!originalIsReferenceExclusively) {
// since we're putting references back and value is not exclusively a reference, use template literals
value = `\`${value}\``;
}
const refs = getReferences(dictionary, original);
refs.forEach((ref) => {
// check if the ref has a value, path and name property, meaning that a name transform
// that creates the token name is mandatory for this format to function properly
if (['value', 'name', 'path'].every((prop) => Object.hasOwn(ref, prop))) {
value = value.replace(
// e.g. `{foo.bar.qux}` or `{foo.bar.qux.value}`
// replaced by `${fooBarQux}`
new RegExp(`{${ref.path.join('.')}(.value)?}`, 'g'),
originalIsReferenceExclusively ? ref.name : `\${${ref.name}}`,
);
}
});
return value;
}
return isNumeric(value) ? value : JSON.stringify(value);
};

return `${fileHeader({ file })}${allTokens.reduce((acc, token) => {
return (
acc +
`export const ${token.name} = ${compileTokenValue(token)}; ${
token.comment ? `// ${token.comment}` : ''
}\n`
);
}, '')}`;
},
});

await sd.buildAllPlatforms();

// output below

/**
* Do not edit directly
* Generated on Thu, 07 Dec 2023 14:44:53 GMT
*/

export const ColorsBlack = '#000';
export const Spacing2 = '2px';
export const ZIndexAboveFold = 1;
export const SemanticBgPrimary = ColorsBlack;
export const Border = `solid ${Spacing2} ${SemanticBgPrimary}`;
```

0 comments on commit 47b26e5

Please sign in to comment.