style-dictionary 4.0.0 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +9 -13
  2. package/examples/README.md +0 -4
  3. package/examples/advanced/assets-base64-embed/package.json +1 -1
  4. package/examples/advanced/create-react-app/package.json +1 -1
  5. package/examples/advanced/create-react-native-app/package.json +1 -1
  6. package/examples/advanced/custom-parser/package.json +1 -1
  7. package/examples/advanced/custom-transforms/README.md +1 -1
  8. package/examples/advanced/custom-transforms/package.json +1 -1
  9. package/examples/advanced/font-face-rules/package.json +1 -1
  10. package/examples/advanced/format-helpers/package.json +1 -1
  11. package/examples/advanced/format-helpers/sd.config.js +1 -1
  12. package/examples/advanced/matching-build-files/package.json +1 -1
  13. package/examples/advanced/multi-brand-multi-platform/package.json +1 -1
  14. package/examples/advanced/node-modules-as-config-and-properties/package.json +1 -1
  15. package/examples/advanced/npm-module/package.json +1 -1
  16. package/examples/advanced/referencing_aliasing/package.json +1 -1
  17. package/examples/advanced/s3/package.json +1 -1
  18. package/examples/advanced/tokens-deprecation/package.json +1 -1
  19. package/examples/advanced/transitive-transforms/package.json +2 -2
  20. package/examples/advanced/transitive-transforms/sd.config.js +36 -23
  21. package/examples/advanced/transitive-transforms/tokens/color/core.json5 +0 -4
  22. package/examples/advanced/transitive-transforms/tokens/color/font.json5 +7 -9
  23. package/examples/advanced/transitive-transforms/tokens/color/overlay.json5 +4 -4
  24. package/examples/advanced/variables-in-outputs/package.json +1 -1
  25. package/examples/advanced/yaml-tokens/package.json +1 -1
  26. package/lib/StyleDictionary.d.ts +78 -16
  27. package/lib/StyleDictionary.js +113 -57
  28. package/lib/common/formatHelpers/createPropertyFormatter.d.ts +9 -0
  29. package/lib/common/formatHelpers/createPropertyFormatter.js +1 -1
  30. package/lib/common/formatHelpers/fileHeader.js +1 -0
  31. package/lib/common/formats.d.ts +1 -1
  32. package/lib/common/formats.js +5 -3
  33. package/lib/common/templates/scss/map-deep.template.js +12 -6
  34. package/lib/common/templates/scss/map-flat.template.js +22 -10
  35. package/lib/common/transforms.js +1 -0
  36. package/lib/fs.d.ts +2 -0
  37. package/lib/fs.js +3 -1
  38. package/lib/utils/combineJSON.js +1 -1
  39. package/lib/utils/expandObjectTokens.js +7 -1
  40. package/lib/utils/groupMessages.d.ts +1 -1
  41. package/lib/utils/groupMessages.js +1 -1
  42. package/package.json +4 -3
  43. package/types/Config.d.ts +3 -3
  44. package/types/File.d.ts +6 -4
  45. package/types/Volume.d.ts +2 -2
  46. package/types/typeless-modules/bundled-memfs.d.ts +0 -1
package/README.md CHANGED
@@ -1,12 +1,8 @@
1
1
  <pre>
2
- <a href="https://amzn.github.io/style-dictionary/#/version_3">What's new in Style Dictionary 3.0!</a>
2
+ <a href="https://styledictionary.com/version-4/migration/">What's new in Style Dictionary 4.0!</a>
3
3
  </pre>
4
4
 
5
- <pre>
6
- <a href="https://github.com/amzn/style-dictionary#version-4">What's coming in Style Dictionary 4.0?</a>
7
- </pre>
8
-
9
- <img src="docs/assets/logo.png" alt="Style Dictionary logo and mascot" title="&quot;Pascal&quot;" width="100" align="right" />
5
+ <img src="docs/src/assets/logo.png" alt="Style Dictionary logo and mascot" title="&quot;Pascal&quot;" width="100" align="right" />
10
6
 
11
7
  [![npm version](https://img.shields.io/npm/v/style-dictionary.svg?style=flat-square)](https://badge.fury.io/js/style-dictionary)
12
8
  ![license](https://img.shields.io/npm/l/style-dictionary.svg?style=flat-square)
@@ -136,7 +132,7 @@ A style dictionary is a collection of design tokens, key/value pairs that descri
136
132
 
137
133
  ### config.json
138
134
 
139
- This tells the style dictionary build system how and what to build. The default file path is `config.json` or `config.js` in the root of the project, but you can name it whatever you want by passing in the `--config` flag to the [CLI](https://amzn.github.io/style-dictionary/#/using_the_cli).
135
+ This tells the style dictionary build system how and what to build. The default file path is `config.json` or `config.js` in the root of the project, but you can name it whatever you want by passing in the `--config` flag to the [CLI](https://styledictionary.com/getting-started/using_the_cli/).
140
136
 
141
137
  ```json
142
138
  {
@@ -176,7 +172,7 @@ This tells the style dictionary build system how and what to build. The default
176
172
  | platform.buildPath | String (optional) | Base path to build the files, must end with a trailing slash. |
177
173
  | platform.files | Array (optional) | Files to be generated for this platform. |
178
174
  | platform.file.destination | String (optional) | Location to build the file, will be appended to the buildPath. |
179
- | platform.file.format | String (optional) | Format used to generate the file. Can be a built-in one or you can create your own. [More on formats](https://amzn.github.io/style-dictionary/#/formats) |
175
+ | platform.file.format | String (optional) | Format used to generate the file. Can be a built-in one or you can create your own. [More on formats](https://styledictionary.com/reference/hooks/formats/) |
180
176
  | platform.file.options | Object (optional) | A set of extra options associated with the file. |
181
177
  | platform.file.options.showFileHeader | Boolean | If the generated file should have a "Do not edit + Timestamp" header (where the format supports it). By default is "true". |
182
178
 
@@ -224,7 +220,7 @@ float const SizeFontBase = 16.00f;
224
220
 
225
221
  The style dictionary framework comes with some example code to get you started. Install the node module globally, create a directory and `cd` into it.
226
222
 
227
- ```
223
+ ```bash
228
224
  $ npm i -g style-dictionary
229
225
  $ mkdir MyStyleDictionary
230
226
  $ cd MyStyleDictionary
@@ -232,13 +228,13 @@ $ cd MyStyleDictionary
232
228
 
233
229
  Now run:
234
230
 
235
- ```
231
+ ```bash
236
232
  $ style-dictionary init basic
237
233
  ```
238
234
 
239
235
  This command will copy over the example files found in [example](examples/) in this repo. Now you have an example project set up. You can make changes to the style dictionary and rebuild the project by running:
240
236
 
241
- ```
237
+ ```bash
242
238
  $ style-dictionary build
243
239
  ```
244
240
 
@@ -313,7 +309,7 @@ StyleDictionary.registerTransform({
313
309
  StyleDictionary.buildAllPlatforms();
314
310
  ```
315
311
 
316
- For more information on creating your own transforms and formats, take a look at our [docs](https://amzn.github.io/style-dictionary/).
312
+ For more information on creating your own transforms and formats, take a look at our [docs](https://styledictionary.com).
317
313
 
318
314
  ## Version 4
319
315
 
@@ -340,7 +336,7 @@ We are very open to feedback and collaboration, feel free to reach out to us in
340
336
 
341
337
  The mascot for Style Dictionary is ["Pascal"](https://github.com/amzn/style-dictionary/issues/97) the chameleon (seen below). You can also find them blending in as the logo throughout the documentation.
342
338
 
343
- <img src="docs/assets/logo.png" alt="Style Dictionary logo and mascot" title="&quot;Pascal&quot;" width="240" />
339
+ <img src="docs/src/assets/logo.png" alt="Style Dictionary logo and mascot" title="&quot;Pascal&quot;" width="240" />
344
340
 
345
341
  ## Contributing
346
342
 
@@ -31,12 +31,8 @@ This is a more complete package and should have everything you need to get start
31
31
  If you want to look at more advanced examples of possible applications and customizations of Style Dictionary, the [`examples/advanced`](https://github.com/amzn/style-dictionary/tree/main/examples/advanced/) folder on GitHub contains these extra folders:
32
32
 
33
33
  - [**assets-base64-embed**](https://github.com/amzn/style-dictionary/tree/main/examples/advanced/assets-base64-embed) shows how it's possible to embed and distribute assets – like images, icons and fonts – directly as design tokens.
34
- - [**auto-rebuild-watcher**](https://github.com/amzn/style-dictionary/tree/main/examples/advanced/auto-rebuild-watcher) shows how to setup a "watcher" that auto-rebuilds the tokens every time there is a change in the tokens.
35
- - [**component-cti**](https://github.com/amzn/style-dictionary/tree/main/examples/advanced/component-cti) shows how to write component tokens and still use the CTI structure.
36
34
  - [**create-react-app**](https://github.com/amzn/style-dictionary/tree/main/examples/advanced/create-react-app) shows how to integrate Style Dictionary into a React application.
37
35
  - [**create-react-native-app**](https://github.com/amzn/style-dictionary/tree/main/examples/advanced/create-react-native-app) shows how to integrate Style Dictionary into a React Native application.
38
- - [**custom-file-header**](https://github.com/amzn/style-dictionary/tree/main/examples/advanced/custom-file-header) shows how to define custom file headers and use them in output files.
39
- - [**custom-formats-with-templates**](https://github.com/amzn/style-dictionary/tree/main/examples/advanced/custom-formats-with-templates) shows how to generate custom output formats using templates, useful when you need to distribute your design tokens into your own pipelines or scripts.
40
36
  - [**custom-parser**](https://github.com/amzn/style-dictionary/tree/main/examples/advanced/custom-parser) shows how to use custom parsers for token files.
41
37
  - [**custom-transforms**](https://github.com/amzn/style-dictionary/tree/main/examples/advanced/custom-transforms) shows how to use custom transforms (and transformGroups) to apply custom "transformations" to the design tokens.
42
38
  - [**flutter**](https://github.com/amzn/style-dictionary/tree/main/examples/advanced/flutter) shows how to integrate with Flutter applications.
@@ -12,6 +12,6 @@
12
12
  "author": "",
13
13
  "license": "Apache-2.0",
14
14
  "devDependencies": {
15
- "style-dictionary": "4.0.0"
15
+ "style-dictionary": "^4.1.0"
16
16
  }
17
17
  }
@@ -12,7 +12,7 @@
12
12
  },
13
13
  "devDependencies": {
14
14
  "eslint-config-react-app": "^7.0.1",
15
- "style-dictionary": "4.0.0"
15
+ "style-dictionary": "^4.1.0"
16
16
  },
17
17
  "resolutions": {
18
18
  "immer": "8.0.1",
@@ -29,7 +29,7 @@
29
29
  "eslint-config-react-app": "^7.0.1",
30
30
  "jest": "~25.2.6",
31
31
  "react-test-renderer": "~16.13.1",
32
- "style-dictionary": "4.0.0"
32
+ "style-dictionary": "^4.1.0"
33
33
  },
34
34
  "jest": {
35
35
  "preset": "react-native"
@@ -10,6 +10,6 @@
10
10
  "author": "",
11
11
  "license": "Apache-2.0",
12
12
  "devDependencies": {
13
- "style-dictionary": "4.0.0"
13
+ "style-dictionary": "^4.1.0"
14
14
  }
15
15
  }
@@ -9,7 +9,7 @@ Transforms are functions that modify a design token (in a non-destructive way).
9
9
  The need for custom transforms is that Style Dictionary expects the tokens to be declared according to certain criteria, to use the pre-defined transforms and formats/templates. For example, the _web_ transformGroup consists of the _attribute/cti_, _name/kebab_, _size/px_ and _color/css_ transforms.
10
10
  The _size/px_ adds 'px' to the end of the number, and is applied only if `token.attributes.category === 'size'`. This means that your token needs to be expressed without units, and be under the _'size'_ "category. If you need a different logic or you want to organize your tokens differently, probably you can't use the out-of-the-box transformation groups, but you have to declare your custom ones.
11
11
 
12
- If [custom formats](../custom-formats-with-templates/) are the way to allow users to customize the format of the _output_ of Style Dictionary, custom transforms are the way to allow them to customize both the _input_ (the token names/values/attributes) and the _output_ (the actual values expressed in the design tokens). For this reasons, custom transforms are probably one of the **most powerful features** of Style Dictionary: they make it extremely versatile, allowing limitless possibilities of extension and customization of the entire design token pipeline.
12
+ If [custom formats](https://v4.styledictionary.com/reference/hooks/formats/#custom-formats) are the way to allow users to customize the format of the _output_ of Style Dictionary, custom transforms are the way to allow them to customize both the _input_ (the token names/values/attributes) and the _output_ (the actual values expressed in the design tokens). For this reasons, custom transforms are probably one of the **most powerful features** of Style Dictionary: they make it extremely versatile, allowing limitless possibilities of extension and customization of the entire design token pipeline.
13
13
 
14
14
  #### Running the example
15
15
 
@@ -16,6 +16,6 @@
16
16
  "author": "",
17
17
  "license": "Apache-2.0",
18
18
  "devDependencies": {
19
- "style-dictionary": "4.0.0"
19
+ "style-dictionary": "^4.1.0"
20
20
  }
21
21
  }
@@ -9,6 +9,6 @@
9
9
  },
10
10
  "license": "Apache-2.0",
11
11
  "devDependencies": {
12
- "style-dictionary": "4.0.0"
12
+ "style-dictionary": "^4.1.0"
13
13
  }
14
14
  }
@@ -10,6 +10,6 @@
10
10
  "author": "",
11
11
  "license": "Apache-2.0",
12
12
  "devDependencies": {
13
- "style-dictionary": "4.0.0"
13
+ "style-dictionary": "^4.1.0"
14
14
  }
15
15
  }
@@ -3,7 +3,7 @@ import {
3
3
  fileHeader,
4
4
  formattedVariables,
5
5
  sortByReference,
6
- } from 'style-dictionary';
6
+ } from 'style-dictionary/utils';
7
7
 
8
8
  export default {
9
9
  hooks: {
@@ -17,6 +17,6 @@
17
17
  "author": "Kelly Harrop <kn.harrop@gmail.com>",
18
18
  "license": "Apache-2.0",
19
19
  "devDependencies": {
20
- "style-dictionary": "4.0.0"
20
+ "style-dictionary": "^4.1.0"
21
21
  }
22
22
  }
@@ -16,6 +16,6 @@
16
16
  "author": "",
17
17
  "license": "Apache-2.0",
18
18
  "devDependencies": {
19
- "style-dictionary": "4.0.0"
19
+ "style-dictionary": "^4.1.0"
20
20
  }
21
21
  }
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "homepage": "https://github.com/dbanksdesign/style-dictionary-node#readme",
22
22
  "devDependencies": {
23
- "style-dictionary": "4.0.0",
23
+ "style-dictionary": "^4.1.0",
24
24
  "tinycolor2": "^1.4.1"
25
25
  }
26
26
  }
@@ -17,6 +17,6 @@
17
17
  "author": "",
18
18
  "license": "Apache-2.0",
19
19
  "devDependencies": {
20
- "style-dictionary": "4.0.0"
20
+ "style-dictionary": "^4.1.0"
21
21
  }
22
22
  }
@@ -16,6 +16,6 @@
16
16
  "author": "",
17
17
  "license": "Apache-2.0",
18
18
  "devDependencies": {
19
- "style-dictionary": "4.0.0"
19
+ "style-dictionary": "^4.1.0"
20
20
  }
21
21
  }
@@ -16,6 +16,6 @@
16
16
  "devDependencies": {
17
17
  "aws-sdk": "^2.7.21",
18
18
  "fs-extra": "^1.0.0",
19
- "style-dictionary": "4.0.0"
19
+ "style-dictionary": "^4.1.0"
20
20
  }
21
21
  }
@@ -16,6 +16,6 @@
16
16
  "author": "",
17
17
  "license": "Apache-2.0",
18
18
  "devDependencies": {
19
- "style-dictionary": "4.0.0"
19
+ "style-dictionary": "^4.1.0"
20
20
  }
21
21
  }
@@ -11,7 +11,7 @@
11
11
  "author": "",
12
12
  "license": "ISC",
13
13
  "devDependencies": {
14
- "chroma-js": "^2.1.0",
15
- "style-dictionary": "4.0.0"
14
+ "colorjs.io": "^0.5.2",
15
+ "style-dictionary": "^4.1.0"
16
16
  }
17
17
  }
@@ -1,10 +1,13 @@
1
1
  import StyleDictionary from 'style-dictionary';
2
2
  import { usesReferences } from 'style-dictionary/utils';
3
- import chroma from 'chroma-js';
3
+ import Color from 'colorjs.io';
4
4
 
5
5
  const colorTransform = (token) => {
6
6
  const { value, modify = [] } = token;
7
- let color = chroma(value);
7
+
8
+ // This assumes "hex" format, if you want to support { h, s, l } format you have to do
9
+ // `new Color('hsl', [value.h, value.s, value.l]);`
10
+ const color = new Color(value);
8
11
 
9
12
  // defer until reference is resolved
10
13
  if (typeof modify === 'string' && usesReferences(modify)) {
@@ -18,15 +21,22 @@ const colorTransform = (token) => {
18
21
  if (usesReferences(type) || usesReferences(amount)) {
19
22
  return undefined;
20
23
  }
21
- // modifier type must match a method name in chromajs
22
- // https://gka.github.io/chroma.js/
23
- // chroma methods can be chained, so each time we override the color variable
24
- // we can still call other chroma methods, similar to
25
- // chroma(value).brighten(1).darken(1).hex();
26
- color = color[type](amount);
24
+
25
+ switch (type) {
26
+ case 'lighten': {
27
+ const lightness = color.hsl.l;
28
+ const difference = 100 - lightness;
29
+ const newLightness = Math.min(100, lightness + difference * amount);
30
+ color.set('hsl.l', newLightness);
31
+ break;
32
+ }
33
+ case 'transparentize':
34
+ color.alpha = Math.max(0, Math.min(1, Number(amount)));
35
+ break;
36
+ }
27
37
  });
28
38
 
29
- return color.hex();
39
+ return color.to('srgb').toString({ format: 'hex' });
30
40
  };
31
41
 
32
42
  export default {
@@ -36,21 +46,24 @@ export default {
36
46
 
37
47
  // I am directly defining transforms here
38
48
  // This would work if you were to call StyleDictionary.registerTransform() as well
39
- transform: {
40
- colorTransform: {
41
- type: `value`,
42
- // only transforms that have transitive: true will be applied to tokens
43
- // that alias/reference other tokens
44
- transitive: true,
45
- filter: (token) => token.attributes.category === 'color' && token.modify,
46
- transform: colorTransform,
47
- },
49
+ hooks: {
50
+ transforms: {
51
+ colorTransform: {
52
+ type: `value`,
53
+ // only transforms that have transitive: true will be applied to tokens
54
+ // that alias/reference other tokens
55
+ transitive: true,
56
+ filter: (token) => token.attributes.category === 'color' && token.modify,
57
+ transform: colorTransform,
58
+ },
48
59
 
49
- // For backwards compatibility, all built-in transforms are not transitive
50
- // by default. This will make the 'color/css' transform transitive
51
- 'color/css': Object.assign({}, StyleDictionary.transform[`color/css`], {
52
- transitive: true,
53
- }),
60
+ // For backwards compatibility, all built-in transforms are not transitive
61
+ // by default. This will make the 'color/css' transform transitive
62
+ 'color/css': {
63
+ ...StyleDictionary.hooks.transforms[`color/css`],
64
+ transitive: true,
65
+ },
66
+ },
54
67
  },
55
68
 
56
69
  platforms: {
@@ -6,10 +6,6 @@
6
6
 
7
7
  red: {
8
8
  '100': {
9
- // hue, saturation, and lightness are defined in
10
- // tokens/hue.json5, tokens/saturation.json5, and tokens/lightness.json5
11
- // The {h, s, l} object structure conforms to the input structure for
12
- // chromajs: https://gka.github.io/chroma.js/#chroma
13
9
  value: { h: '{hue.red}', s: '{saturation.7}', l: '{lightness.7}' },
14
10
  type: 'color',
15
11
  },
@@ -1,15 +1,13 @@
1
1
  {
2
2
  color: {
3
3
  font: {
4
- primary: { value: '{color.core.black.value}', type: 'color' },
4
+ primary: { value: '{color.core.black}', type: 'color' },
5
5
  secondary: {
6
- value: '{color.font.primary.value}',
6
+ value: '{color.font.primary}',
7
7
  modify: [
8
8
  {
9
- type: 'brighten',
10
- // See https://gka.github.io/chroma.js/#color-brighten
11
- // for definition of brighten
12
- amount: 1,
9
+ type: 'lighten',
10
+ amount: 0.2,
13
11
  },
14
12
  ],
15
13
  type: 'color',
@@ -20,10 +18,10 @@
20
18
  value: '{color.font.secondary}',
21
19
  modify: [
22
20
  {
23
- // this will brighten the secondary value, which is a brightened version
21
+ // this will lighten the secondary value, which is a lightened version
24
22
  // of primary
25
- type: 'brighten',
26
- amount: 1,
23
+ type: 'lighten',
24
+ amount: 0.2,
27
25
  },
28
26
  ],
29
27
  type: 'color',
@@ -2,10 +2,10 @@
2
2
  color: {
3
3
  overlay: {
4
4
  primary: {
5
- value: '{color.core.white.value}',
5
+ value: '{color.core.white}',
6
6
  modify: [
7
7
  {
8
- type: 'alpha',
8
+ type: 'transparentize',
9
9
  // You can access other parts of your style dictionary in here too:
10
10
  amount: '{alpha.1}',
11
11
  },
@@ -14,10 +14,10 @@
14
14
  },
15
15
 
16
16
  secondary: {
17
- value: '{color.core.white.value}',
17
+ value: '{color.core.white}',
18
18
  modify: [
19
19
  {
20
- type: 'alpha',
20
+ type: 'transparentize',
21
21
  // You can access other parts of your style dictionary in here too:
22
22
  amount: '{alpha.2}',
23
23
  },
@@ -11,6 +11,6 @@
11
11
  "author": "",
12
12
  "license": "MIT",
13
13
  "devDependencies": {
14
- "style-dictionary": "4.0.0"
14
+ "style-dictionary": "^4.1.0"
15
15
  }
16
16
  }
@@ -10,7 +10,7 @@
10
10
  "author": "",
11
11
  "license": "Apache-2.0",
12
12
  "devDependencies": {
13
- "style-dictionary": "4.0.0",
13
+ "style-dictionary": "^4.1.0",
14
14
  "yaml": "^1.10.0"
15
15
  }
16
16
  }
@@ -32,10 +32,10 @@ export default class StyleDictionary extends Register {
32
32
  get options(): import("../types/Config.ts").Config;
33
33
  _options: import("../types/Config.ts").Config | undefined;
34
34
  config: string | import("../types/Config.ts").Config;
35
- /** @type {Tokens|TransformedTokens|PreprocessedTokens} */
36
- tokens: Tokens | TransformedTokens | PreprocessedTokens;
37
- /** @type {TransformedToken[]} */
38
- allTokens: TransformedToken[];
35
+ /** @type {PreprocessedTokens} */
36
+ tokens: PreprocessedTokens;
37
+ /** @type {PreprocessedTokens[]} */
38
+ allTokens: PreprocessedTokens[];
39
39
  /** @type {boolean | undefined} */
40
40
  usesDtcg: boolean | undefined;
41
41
  /** @type {LogConfig} */
@@ -64,6 +64,14 @@ export default class StyleDictionary extends Register {
64
64
  unfilteredAllTokens: TransformedToken[];
65
65
  hasInitialized: Promise<any>;
66
66
  hasInitializedResolve: (value: any) => void;
67
+ /**
68
+ * Storing the platform specific transformed tokens so we can prevent re-running exportPlatform when we already know the outcome
69
+ * Same thing for platform specific configs, we don't need to call transformConfig again if we already know the outcome
70
+ */
71
+ /** @type {Record<string,Dictionary>} */
72
+ _dictionaries: Record<string, Dictionary>;
73
+ /** @type {Record<string,PlatformConfig>} */
74
+ _platformConfigs: Record<string, PlatformConfig>;
67
75
  /**
68
76
  * @param {{verbosity?: LogConfig['verbosity'], warnings?: LogConfig['warnings']}} [opts]
69
77
  * @returns
@@ -95,20 +103,47 @@ export default class StyleDictionary extends Register {
95
103
  shouldRunExpansion(expandCfg?: import("../types/Config.ts").ExpandConfig | undefined): boolean;
96
104
  /**
97
105
  * @param {string} platform
106
+ * @param {{ cache?: boolean }} [opts]
107
+ */
108
+ getPlatformConfig(platform: string, opts?: {
109
+ cache?: boolean;
110
+ } | undefined): import("../types/Config.ts").PlatformConfig;
111
+ /**
112
+ * @param {string} platform
113
+ * @param {{ cache?: boolean }} [opts]
114
+ */
115
+ getPlatformTokens(platform: string, opts?: {
116
+ cache?: boolean;
117
+ } | undefined): Promise<import("../types/DesignToken.ts").Dictionary>;
118
+ /**
119
+ * Public wrapper around _exportPlatform, returns only tokens object
120
+ * Here for backwards compatibility.
121
+ * @deprecated use getPlatformTokens instead
122
+ *
123
+ * @param {string} platform
124
+ * @param {{ cache?: boolean }} [opts]
98
125
  * @returns {Promise<TransformedTokens>}
99
126
  */
100
- exportPlatform(platform: string): Promise<TransformedTokens>;
127
+ exportPlatform(platform: string, opts?: {
128
+ cache?: boolean;
129
+ } | undefined): Promise<TransformedTokens>;
130
+ /**
131
+ * @param {string} platform
132
+ * @returns {Promise<Dictionary>}
133
+ */
134
+ _exportPlatform(platform: string): Promise<Dictionary>;
101
135
  /**
102
136
  * This will get the dictionary / platformConfig for specified platform name
103
137
  * Runs transforms, reference resolutions
138
+ * @deprecated use getPlatformConfig / getPlatformTokens instead
104
139
  * @param {string} platform
140
+ * @param {{ cache?: boolean }} [opts]
105
141
  * @returns
106
142
  */
107
- getPlatform(platform: string): Promise<{
108
- dictionary: {
109
- tokens: import("../types/DesignToken.ts").TransformedTokens;
110
- allTokens: import("../types/DesignToken.ts").TransformedToken[];
111
- };
143
+ getPlatform(platform: string, opts?: {
144
+ cache?: boolean;
145
+ } | undefined): Promise<{
146
+ dictionary: import("../types/DesignToken.ts").Dictionary;
112
147
  platformConfig: import("../types/Config.ts").PlatformConfig;
113
148
  }>;
114
149
  /**
@@ -134,24 +169,51 @@ export default class StyleDictionary extends Register {
134
169
  }>;
135
170
  /**
136
171
  * @param {string} platform
172
+ * @param {{ cache?: boolean }} [opts]
137
173
  */
138
- formatPlatform(platform: string): Promise<{
174
+ formatPlatform(platform: string, opts?: {
175
+ cache?: boolean;
176
+ } | undefined): Promise<{
139
177
  output: unknown;
140
178
  destination: string | undefined;
141
179
  }[]>;
142
- formatAllPlatforms(): Promise<{}>;
180
+ /**
181
+ * @param {{ cache?: boolean }} [opts]
182
+ * @returns
183
+ */
184
+ formatAllPlatforms(opts?: {
185
+ cache?: boolean;
186
+ } | undefined): Promise<{}>;
143
187
  /**
144
188
  * @param {string} platform
189
+ * @param {{ cache?: boolean }} [opts]
145
190
  * @returns
146
191
  */
147
- buildPlatform(platform: string): Promise<this>;
148
- buildAllPlatforms(): Promise<this>;
192
+ buildPlatform(platform: string, opts?: {
193
+ cache?: boolean;
194
+ } | undefined): Promise<this>;
195
+ /**
196
+ * @param {{ cache?: boolean }} [opts]
197
+ * @returns
198
+ */
199
+ buildAllPlatforms(opts?: {
200
+ cache?: boolean;
201
+ } | undefined): Promise<this>;
149
202
  /**
150
203
  * @param {string} platform
204
+ * @param {{ cache?: boolean }} [opts]
205
+ * @returns
206
+ */
207
+ cleanPlatform(platform: string, opts?: {
208
+ cache?: boolean;
209
+ } | undefined): Promise<this>;
210
+ /**
211
+ * @param {{ cache?: boolean }} [opts]
151
212
  * @returns
152
213
  */
153
- cleanPlatform(platform: string): Promise<this>;
154
- cleanAllPlatforms(): Promise<this>;
214
+ cleanAllPlatforms(opts?: {
215
+ cache?: boolean;
216
+ } | undefined): Promise<this>;
155
217
  }
156
218
  export type Volume = import("../types/Volume.ts").Volume;
157
219
  export type Config = import("../types/Config.ts").Config;
@@ -78,7 +78,7 @@ export default class StyleDictionary extends Register {
78
78
  // Placeholder is transformed on prepublish -> see scripts/inject-version.js
79
79
  // Another option might be import pkg from './package.json' with { "type": "json" } which would work in both browser and node, but support is not there yet.
80
80
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#browser_compatibility
81
- static VERSION = '4.0.0';
81
+ static VERSION = '4.1.0';
82
82
 
83
83
  /** @returns {Config} */
84
84
  get options() {
@@ -110,9 +110,9 @@ export default class StyleDictionary extends Register {
110
110
  super();
111
111
  this.config = config;
112
112
  this.options = {};
113
- /** @type {Tokens|TransformedTokens|PreprocessedTokens} */
113
+ /** @type {PreprocessedTokens} */
114
114
  this.tokens = {};
115
- /** @type {TransformedToken[]} */
115
+ /** @type {PreprocessedTokens[]} */
116
116
  this.allTokens = [];
117
117
  /** @type {boolean | undefined} */
118
118
  this.usesDtcg = undefined;
@@ -156,6 +156,15 @@ export default class StyleDictionary extends Register {
156
156
  this.hasInitializedResolve = resolve;
157
157
  });
158
158
 
159
+ /**
160
+ * Storing the platform specific transformed tokens so we can prevent re-running exportPlatform when we already know the outcome
161
+ * Same thing for platform specific configs, we don't need to call transformConfig again if we already know the outcome
162
+ */
163
+ /** @type {Record<string,Dictionary>} */
164
+ this._dictionaries = {};
165
+ /** @type {Record<string,PlatformConfig>} */
166
+ this._platformConfigs = {};
167
+
159
168
  // By default, always call async extend function when constructing new SD instance
160
169
  // However, for testability and managing error handling,
161
170
  // you can call constructor with { init: false }
@@ -331,25 +340,28 @@ export default class StyleDictionary extends Register {
331
340
  }
332
341
  }
333
342
  }
343
+ this.options = { ...this.options, usesDtcg: this.usesDtcg };
334
344
 
335
345
  // Merge inline, include, and source tokens
336
- /** @type {PreprocessedTokens|Tokens} */
337
- let tokens = deepExtend([{}, inlineTokens, includeTokens, sourceTokens]);
346
+ let preprocessedTokens = /** @type {PreprocessedTokens} */ (
347
+ deepExtend([{}, inlineTokens, includeTokens, sourceTokens])
348
+ );
349
+
350
+ preprocessedTokens = await preprocess(
351
+ preprocessedTokens,
352
+ this.preprocessors,
353
+ this.hooks.preprocessors,
354
+ this.options,
355
+ );
338
356
  if (this.usesDtcg) {
339
357
  // this is where they go from type Tokens -> Preprocessed tokens because the prop $type is removed
340
- tokens = typeDtcgDelegate(tokens);
358
+ preprocessedTokens = typeDtcgDelegate(preprocessedTokens);
341
359
  }
342
- let preprocessedTokens = /** @type {PreprocessedTokens} */ (tokens);
343
360
  if (this.shouldRunExpansion(this.expand)) {
344
361
  preprocessedTokens = expandTokens(preprocessedTokens, this.options);
345
362
  }
346
- this.options = { ...this.options, usesDtcg: this.usesDtcg };
347
- this.tokens = await preprocess(
348
- preprocessedTokens,
349
- this.preprocessors,
350
- this.hooks.preprocessors,
351
- this.options,
352
- );
363
+ this.tokens = preprocessedTokens;
364
+ this.allTokens = flattenTokens(/** @type {PreprocessedTokens} */ (this.tokens), this.usesDtcg);
353
365
  this.hasInitializedResolve(null);
354
366
 
355
367
  // For chaining
@@ -378,27 +390,62 @@ export default class StyleDictionary extends Register {
378
390
 
379
391
  /**
380
392
  * @param {string} platform
381
- * @returns {Promise<TransformedTokens>}
393
+ * @param {{ cache?: boolean }} [opts]
382
394
  */
383
- async exportPlatform(platform) {
384
- await this.hasInitialized;
385
-
395
+ getPlatformConfig(platform, opts) {
386
396
  if (!platform || !this.platforms?.[platform]) {
387
- throw new Error('Please supply a valid platform');
397
+ throw new Error(`Please supply a valid platform, "${platform}" does not exist`);
398
+ }
399
+ if (!this._platformConfigs[platform] || opts?.cache === false) {
400
+ this._platformConfigs[platform] = transformConfig(this.platforms[platform], this, platform);
388
401
  }
402
+ return this._platformConfigs[platform];
403
+ }
389
404
 
390
- // We don't want to mutate the original object
391
- const platformConfig = transformConfig(this.platforms[platform], this, platform);
405
+ /**
406
+ * @param {string} platform
407
+ * @param {{ cache?: boolean }} [opts]
408
+ */
409
+ async getPlatformTokens(platform, opts) {
410
+ if (!this._dictionaries[platform] || opts?.cache === false) {
411
+ const dictionary = await this._exportPlatform(platform);
412
+ this._dictionaries[platform] = dictionary;
413
+ }
414
+ return this._dictionaries[platform];
415
+ }
416
+
417
+ /**
418
+ * Public wrapper around _exportPlatform, returns only tokens object
419
+ * Here for backwards compatibility.
420
+ * @deprecated use getPlatformTokens instead
421
+ *
422
+ * @param {string} platform
423
+ * @param {{ cache?: boolean }} [opts]
424
+ * @returns {Promise<TransformedTokens>}
425
+ */
426
+ async exportPlatform(platform, opts) {
427
+ const dictionary = await this.getPlatformTokens(platform, opts);
428
+ return dictionary.tokens;
429
+ }
430
+
431
+ /**
432
+ * @param {string} platform
433
+ * @returns {Promise<Dictionary>}
434
+ */
435
+ async _exportPlatform(platform) {
436
+ await this.hasInitialized;
437
+ const platformConfig = this.getPlatformConfig(platform);
392
438
 
393
439
  let platformProcessedTokens = /** @type {PreprocessedTokens} */ (this.tokens);
394
- if (this.shouldRunExpansion(platformConfig.expand)) {
395
- platformProcessedTokens = expandTokens(platformProcessedTokens, this.options, platformConfig);
396
- }
440
+
397
441
  platformProcessedTokens = await preprocess(
398
442
  platformProcessedTokens,
399
443
  platformConfig.preprocessors,
400
444
  this.hooks.preprocessors,
401
445
  );
446
+ if (this.shouldRunExpansion(platformConfig.expand)) {
447
+ platformProcessedTokens = expandTokens(platformProcessedTokens, this.options, platformConfig);
448
+ }
402
449
 
403
450
  let exportableResult = /** @type {PreprocessedTokens|TransformedTokens} */ (
404
451
  platformProcessedTokens
@@ -538,35 +585,25 @@ export default class StyleDictionary extends Register {
538
585
  console.log(chalk.rgb(255, 140, 0).bold(err));
539
586
  }
540
587
  }
541
-
542
- return exportableResult;
588
+ return { tokens: exportableResult, allTokens: flattenTokens(exportableResult, this.usesDtcg) };
543
589
  }
544
590
 
545
591
  /**
546
592
  * This will get the dictionary / platformConfig for specified platform name
547
593
  * Runs transforms, reference resolutions
594
+ * @deprecated use getPlatformConfig / getPlatformTokens instead
548
595
  * @param {string} platform
596
+ * @param {{ cache?: boolean }} [opts]
549
597
  * @returns
550
598
  */
551
- async getPlatform(platform) {
599
+ async getPlatform(platform, opts) {
552
600
  await this.hasInitialized;
553
- if (!this.platforms?.[platform]) {
554
- throw new Error(`Platform "${platform}" does not exist`);
555
- }
556
-
557
- // We don't want to mutate the original object
558
- const platformConfig = transformConfig(this.platforms[platform], this, platform);
559
-
560
- // We need to transform the object before we resolve the
561
- // variable names because if a value contains concatenated
562
- // values like "1px solid {color.border.base}" we want to
563
- // transform the original value (color.border.base) before
564
- // replacing that value in the string.
565
- const tokens = await this.exportPlatform(platform);
566
- this.allTokens = /** @type {TransformedToken[]} */ (flattenTokens(tokens, this.usesDtcg));
567
- // This is the dictionary object we pass to the file
568
- // building and action methods.
569
- return { dictionary: { tokens, allTokens: this.allTokens }, platformConfig };
601
+ const platformConfig = this.getPlatformConfig(platform, opts);
602
+ const dictionary = await this.getPlatformTokens(platform, opts);
603
+ return {
604
+ dictionary,
605
+ platformConfig,
606
+ };
570
607
  }
571
608
 
572
609
  /**
@@ -755,10 +792,13 @@ export default class StyleDictionary extends Register {
755
792
 
756
793
  /**
757
794
  * @param {string} platform
795
+ * @param {{ cache?: boolean }} [opts]
758
796
  */
759
- async formatPlatform(platform) {
797
+ async formatPlatform(platform, opts) {
760
798
  await this.hasInitialized;
761
- const { dictionary, platformConfig } = await this.getPlatform(platform);
799
+ const platformConfig = this.getPlatformConfig(platform, opts);
800
+ const dictionary = await this.getPlatformTokens(platform, opts);
801
+
762
802
  if (
763
803
  platformConfig.buildPath &&
764
804
  platformConfig.buildPath.slice(-1) !== '/' &&
@@ -802,7 +842,11 @@ export default class StyleDictionary extends Register {
802
842
  return formattedFiles.map(({ output, destination }) => ({ output, destination }));
803
843
  }
804
844
 
805
- async formatAllPlatforms() {
845
+ /**
846
+ * @param {{ cache?: boolean }} [opts]
847
+ * @returns
848
+ */
849
+ async formatAllPlatforms(opts) {
806
850
  await this.hasInitialized;
807
851
  if (!this.platforms) {
808
852
  throw new Error('Cannot format platforms due to missing property "platforms" on config');
@@ -812,7 +856,7 @@ export default class StyleDictionary extends Register {
812
856
  * @param {string} platformKey
813
857
  */
814
858
  const getOutputsForPlatform = async (platformKey) => {
815
- const outputs = await this.formatPlatform(platformKey);
859
+ const outputs = await this.formatPlatform(platformKey, opts);
816
860
  return { platform: platformKey, outputs };
817
861
  };
818
862
 
@@ -830,11 +874,13 @@ export default class StyleDictionary extends Register {
830
874
 
831
875
  /**
832
876
  * @param {string} platform
877
+ * @param {{ cache?: boolean }} [opts]
833
878
  * @returns
834
879
  */
835
- async buildPlatform(platform) {
880
+ async buildPlatform(platform, opts) {
836
881
  await this.hasInitialized;
837
- const { dictionary, platformConfig } = await this.getPlatform(platform);
882
+ const platformConfig = this.getPlatformConfig(platform, opts);
883
+ const dictionary = await this.getPlatformTokens(platform, opts);
838
884
 
839
885
  /**
840
886
  * @param {string} destination
@@ -850,7 +896,7 @@ export default class StyleDictionary extends Register {
850
896
  return this.volume.promises.writeFile(destination, output);
851
897
  };
852
898
 
853
- const files = await this.formatPlatform(platform);
899
+ const files = await this.formatPlatform(platform, opts);
854
900
  if (files) {
855
901
  await Promise.all(
856
902
  files.map(({ destination, output }) => {
@@ -876,10 +922,14 @@ export default class StyleDictionary extends Register {
876
922
  return this;
877
923
  }
878
924
 
879
- async buildAllPlatforms() {
925
+ /**
926
+ * @param {{ cache?: boolean }} [opts]
927
+ * @returns
928
+ */
929
+ async buildAllPlatforms(opts) {
880
930
  await this.hasInitialized;
881
931
  if (this.platforms) {
882
- await Promise.all(Object.keys(this.platforms).map((key) => this.buildPlatform(key)));
932
+ await Promise.all(Object.keys(this.platforms).map((key) => this.buildPlatform(key, opts)));
883
933
  }
884
934
  // For chaining
885
935
  return this;
@@ -887,10 +937,12 @@ export default class StyleDictionary extends Register {
887
937
 
888
938
  /**
889
939
  * @param {string} platform
940
+ * @param {{ cache?: boolean }} [opts]
890
941
  * @returns
891
942
  */
892
- async cleanPlatform(platform) {
893
- const { dictionary, platformConfig } = await this.getPlatform(platform);
943
+ async cleanPlatform(platform, opts) {
944
+ const platformConfig = this.getPlatformConfig(platform, opts);
945
+ const dictionary = await this.getPlatformTokens(platform, opts);
894
946
  // collect logs, cleanFiles happens in parallel but we want to log in sequence
895
947
  const logs = await cleanFiles(platformConfig, this.volume);
896
948
  if (logs) {
@@ -915,10 +967,14 @@ export default class StyleDictionary extends Register {
915
967
  return this;
916
968
  }
917
969
 
918
- async cleanAllPlatforms() {
970
+ /**
971
+ * @param {{ cache?: boolean }} [opts]
972
+ * @returns
973
+ */
974
+ async cleanAllPlatforms(opts) {
919
975
  await this.hasInitialized;
920
976
  if (this.platforms) {
921
- await Promise.all(Object.keys(this.platforms).map((key) => this.cleanPlatform(key)));
977
+ await Promise.all(Object.keys(this.platforms).map((key) => this.cleanPlatform(key, opts)));
922
978
  }
923
979
  // For chaining
924
980
  return this;
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Split a string comment by newlines and
3
+ * convert to multi-line comment if necessary
4
+ * @param {string} to_ret_token
5
+ * @param {string} comment
6
+ * @param {Formatting} options
7
+ * @returns {string}
8
+ */
9
+ export function addComment(to_ret_token: string, comment: string, options: Formatting): string;
1
10
  /**
2
11
  * Creates a function that can be used to format a token. This can be useful
3
12
  * to use as the function on `dictionary.allTokens.map`. The formatting
@@ -40,7 +40,7 @@ const defaultFormatting = {
40
40
  * @param {Formatting} options
41
41
  * @returns {string}
42
42
  */
43
- function addComment(to_ret_token, comment, options) {
43
+ export function addComment(to_ret_token, comment, options) {
44
44
  const { commentStyle, indentation } = options;
45
45
  let { commentPosition } = options;
46
46
 
@@ -12,6 +12,7 @@
12
12
  */
13
13
 
14
14
  /**
15
+ *
15
16
  * @typedef {import('../../../types/File.ts').File} File
16
17
  * @typedef {import('../../../types/File.ts').FileHeader} FileHeader
17
18
  * @typedef {import('../../../types/File.ts').FormattingOptions} Formatting
@@ -1,7 +1,7 @@
1
1
  export default formats;
2
2
  export type Format = import("../../types/Format.ts").Format;
3
3
  export type FormatArgs = import("../../types/Format.ts").FormatFnArguments;
4
- export type FormattingOptions = import("../../types/File").FormattingOptions;
4
+ export type FormattingOverrides = import("../../types/File").FormattingOverrides;
5
5
  export type OutputReferences = import("../../types/Format.ts").OutputReferences;
6
6
  export type Token = import("../../types/DesignToken.ts").TransformedToken;
7
7
  export type Tokens = import("../../types/DesignToken.ts").TransformedTokens;
@@ -49,7 +49,7 @@ import plistTemplate from './templates/ios/plist.template.js';
49
49
  /**
50
50
  * @typedef {import('../../types/Format.ts').Format} Format
51
51
  * @typedef {import('../../types/Format.ts').FormatFnArguments} FormatArgs
52
- * @typedef {import('../../types/File').FormattingOptions} FormattingOptions
52
+ * @typedef {import('../../types/File').FormattingOverrides} FormattingOverrides
53
53
  * @typedef {import('../../types/Format.ts').OutputReferences} OutputReferences
54
54
  * @typedef {import('../../types/DesignToken.ts').TransformedToken} Token
55
55
  * @typedef {import('../../types/DesignToken.ts').TransformedTokens} Tokens
@@ -60,11 +60,13 @@ import plistTemplate from './templates/ios/plist.template.js';
60
60
  */
61
61
 
62
62
  /**
63
- * remove prefix because the prefix option for createPropertyFormatting is not the same as the prefix inside header comment
64
- * @param {FormattingOptions} [formatting]
63
+ * Remove prefix because the prefix option for createPropertyFormatter
64
+ * is not the same as the prefix inside header comment
65
+ * @param {FormattingOverrides} [formatting]
65
66
  */
66
67
  function getFormattingCloneWithoutPrefix(formatting) {
67
68
  const formattingWithoutPrefix = structuredClone(formatting) ?? {};
69
+ // @ts-expect-error users are not supposed to pass "prefix" but they might because it used to be supported
68
70
  delete formattingWithoutPrefix.prefix;
69
71
  return formattingWithoutPrefix;
70
72
  }
@@ -12,6 +12,7 @@
12
12
  * @param {number} depth
13
13
  */
14
14
  function processJsonNode(obj, options, depth = 0) {
15
+ const indent = options.formatting?.indentation ?? ' ';
15
16
  let output = '';
16
17
  if (obj === null) {
17
18
  output += `''`;
@@ -22,15 +23,18 @@ function processJsonNode(obj, options, depth = 0) {
22
23
  output += `$${obj.name}`;
23
24
  } else {
24
25
  // if we have found a group of tokens, use the Sass group "(...)" syntax and loop -recursively- on the children
25
- output += '(\n';
26
+ output += `(\n`;
26
27
  output += Object.keys(obj)
27
28
  .map(function (newKey) {
28
29
  const newProp = obj[newKey];
29
- const indent = ' '.repeat(depth + 1);
30
- return `${indent}'${newKey}': ${processJsonNode(newProp, options, depth + 1)}`;
30
+ return `${indent.repeat(depth + 1)}'${newKey}': ${processJsonNode(
31
+ newProp,
32
+ options,
33
+ depth + 1,
34
+ )}`;
31
35
  })
32
- .join(',\n');
33
- output += '\n' + ' '.repeat(depth) + ')';
36
+ .join(`,\n`);
37
+ output += `\n` + indent.repeat(depth) + ')';
34
38
  }
35
39
  return output;
36
40
  }
@@ -41,6 +45,8 @@ function processJsonNode(obj, options, depth = 0) {
41
45
  * options: Config & LocalOptions
42
46
  * }} opts
43
47
  */
44
- export default ({ dictionary, options }) => `
48
+ export default ({ dictionary, options }) => {
49
+ return `
45
50
  $${options.mapName ?? 'tokens'}: ${processJsonNode(dictionary.tokens, options)};
46
51
  `;
52
+ };
@@ -1,3 +1,5 @@
1
+ import { addComment } from '../../formatHelpers/createPropertyFormatter.js';
2
+
1
3
  /**
2
4
  * @typedef {import('../../../../types/DesignToken.ts').TransformedToken} TransformedToken
3
5
  * @typedef {import('../../../../types/Config.ts').Config} Config
@@ -11,14 +13,24 @@
11
13
  * header: string
12
14
  * }} opts
13
15
  */
14
- export default ({ allTokens, options, header }) => `
15
- ${header}$${options.mapName ?? 'tokens'}: (
16
- ${allTokens
17
- .map(
18
- (token) =>
19
- `${token.comment ? ` // ${token.comment}\n` : ''} '${token.name}': ${
16
+ export default ({ allTokens, options, header }) => {
17
+ const _f = options.formatting ?? {};
18
+ const f = {
19
+ ..._f,
20
+ indentation: _f.indentation ?? ' ',
21
+ commentStyle: _f.commentStyle ?? 'short',
22
+ commentPosition: _f.commentPosition ?? 'above',
23
+ };
24
+ return `
25
+ ${header}$${options.mapName ?? 'tokens'}: (\n${allTokens
26
+ .map((token, i, arr) => {
27
+ const tokenString = `${f.indentation}'${token.name}': ${
20
28
  options.usesDtcg ? token.$value : token.value
21
- }`,
22
- )
23
- .join(',\n')}
24
- );`;
29
+ }${i !== arr.length - 1 ? ',' : ''}`;
30
+ if (token.comment && f.commentStyle !== 'none') {
31
+ return addComment(tokenString, token.comment, f);
32
+ }
33
+ return tokenString;
34
+ })
35
+ .join(`\n`)}\n);`;
36
+ };
@@ -832,6 +832,7 @@ export default {
832
832
  }
833
833
  const parsedVal = parseFloat(nonParsed);
834
834
  if (isNaN(parsedVal)) throwSizeError(token.name, nonParsed, 'rem');
835
+ if (parsedVal === 0) return Number.isInteger(nonParsed) ? 0 : '0';
835
836
  return parsedVal + 'rem';
836
837
  },
837
838
  },
package/lib/fs.d.ts CHANGED
@@ -3,6 +3,8 @@
3
3
  */
4
4
  /**
5
5
  * Allow to be overridden by setter, set default to memfs for browser env, node:fs for node env
6
+ * Default CJS export when converted to ESM, messes up the types a bit so we need to
7
+ * cast the default import to type of Volume by first casting to unknown...
6
8
  */
7
9
  export let fs: Volume;
8
10
  export function setFs(_fs: Volume, isNodeFS?: boolean | undefined): void;
package/lib/fs.js CHANGED
@@ -6,8 +6,10 @@ import memfs from '@bundled-es-modules/memfs';
6
6
 
7
7
  /**
8
8
  * Allow to be overridden by setter, set default to memfs for browser env, node:fs for node env
9
+ * Default CJS export when converted to ESM, messes up the types a bit so we need to
10
+ * cast the default import to type of Volume by first casting to unknown...
9
11
  */
10
- export let fs = /** @type {Volume} */ (memfs);
12
+ export let fs = /** @type {Volume} */ (/** @type {unknown} */ (memfs));
11
13
 
12
14
  /**
13
15
  * since ES modules exports are read-only, use a setter
@@ -33,7 +33,7 @@ import { detectDtcgSyntax } from './detectDtcgSyntax.js';
33
33
  function traverseObj(obj, fn) {
34
34
  for (let key in obj) {
35
35
  const prop = obj[key];
36
- if (prop) {
36
+ if (prop != null) {
37
37
  fn.apply(null, [obj, key, prop]);
38
38
  if (typeof prop === 'object') {
39
39
  traverseObj(prop, fn);
@@ -211,7 +211,13 @@ function expandTokensRecurse(slice, original, opts, platform) {
211
211
  if (value) {
212
212
  // if our token is a ref, we have to resolve it first in order to expand its value
213
213
  if (typeof value === 'string' && usesReferences(value)) {
214
- value = resolveReferences(value, original, { usesDtcg: uses$ });
214
+ try {
215
+ value = resolveReferences(value, original, { usesDtcg: uses$ });
216
+ } catch (e) {
217
+ // do nothing, references may be broken but now is not the time to
218
+ // complain about it, as we're just doing this here so we can expand
219
+ // tokens that reference object-value tokens that need to be expanded
220
+ }
215
221
  }
216
222
 
217
223
  if (
@@ -1,4 +1,4 @@
1
- export const verbosityInfo: "Use log.verbosity \"verbose\" or use CLI option --verbose for more details.";
1
+ export const verbosityInfo: "Use log.verbosity \"verbose\" or use CLI option --verbose for more details.\nRefer to: https://styledictionary.com/reference/logging/";
2
2
  export class GroupMessages {
3
3
  /** @type {{[key: string]: string[]}} */
4
4
  groupedMessages: {
@@ -11,7 +11,7 @@
11
11
  * and limitations under the License.
12
12
  */
13
13
 
14
- export const verbosityInfo = `Use log.verbosity "verbose" or use CLI option --verbose for more details.`;
14
+ export const verbosityInfo = `Use log.verbosity "verbose" or use CLI option --verbose for more details.\nRefer to: https://styledictionary.com/reference/logging/`;
15
15
 
16
16
  export class GroupMessages {
17
17
  constructor() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "style-dictionary",
3
- "version": "4.0.0",
3
+ "version": "4.1.0",
4
4
  "description": "Style once, use everywhere. A build system for creating cross-platform styles.",
5
5
  "keywords": [
6
6
  "style dictionary",
@@ -59,6 +59,8 @@
59
59
  "test:coverage": "cd coverage/lcov-report && npx http-server -o -c-1",
60
60
  "test:update-snapshots": "web-test-runner --update-snapshots",
61
61
  "test:node": "mocha -r mocha-hooks.mjs './__integration__/**/*.test.js' './__tests__/**/*.test.js' './__node_tests__/**/*.test.js'",
62
+ "test:perf": "mocha -r mocha-hooks.mjs './__perf_tests__/**/*.test.js'",
63
+ "test:perf:debug": "web-test-runner --config wtr-perf.config.mjs --watch",
62
64
  "install-cli": "npm install -g $(npm pack)",
63
65
  "release": "npm run build && changeset publish",
64
66
  "prepare": "husky install",
@@ -102,7 +104,7 @@
102
104
  "dependencies": {
103
105
  "@bundled-es-modules/deepmerge": "^4.3.1",
104
106
  "@bundled-es-modules/glob": "^10.4.2",
105
- "@bundled-es-modules/memfs": "^4.8.1",
107
+ "@bundled-es-modules/memfs": "^4.9.4",
106
108
  "@zip.js/zip.js": "^2.7.44",
107
109
  "chalk": "^5.3.0",
108
110
  "change-case": "^5.3.0",
@@ -147,7 +149,6 @@
147
149
  "lint-staged": "^12.3.1",
148
150
  "lit": "^3.1.2",
149
151
  "mdast": "^3.0.0",
150
- "memfs": "^4.6.0",
151
152
  "mermaid": "^10.9.1",
152
153
  "mocha": "^10.2.0",
153
154
  "monaco-editor": "^0.47.0",
package/types/Config.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { DesignToken, DesignTokens, PreprocessedTokens } from './DesignToken.ts';
2
2
  import type { Filter } from './Filter.ts';
3
- import type { FileHeader, File, FormattingOptions } from './File.ts';
3
+ import type { FileHeader, File, FormattingOverrides } from './File.ts';
4
4
  import type { Parser } from './Parser.ts';
5
5
  import type { Preprocessor } from './Preprocessor.ts';
6
6
  import type { Transform } from './Transform.ts';
@@ -21,7 +21,7 @@ export interface LocalOptions {
21
21
  fileHeader?: string | FileHeader;
22
22
  outputReferences?: OutputReferences;
23
23
  outputReferenceFallbacks?: boolean;
24
- formatting?: FormattingOptions;
24
+ formatting?: FormattingOverrides;
25
25
  [key: string]: any;
26
26
  }
27
27
  export interface RegexOptions {
@@ -80,7 +80,7 @@ export interface Config {
80
80
  hooks?: Hooks;
81
81
  expand?: ExpandConfig;
82
82
  platforms?: Record<string, PlatformConfig>;
83
- parsers?: Parser[];
83
+ parsers?: string[];
84
84
  preprocessors?: string[];
85
85
  usesDtcg?: boolean;
86
86
  }
package/types/File.d.ts CHANGED
@@ -2,16 +2,18 @@ import type { TransformedToken } from './DesignToken.ts';
2
2
  import type { FormatFn } from './Format.ts';
3
3
  import type { LocalOptions, Config } from './Config.ts';
4
4
  import type { Filter } from './Filter.ts';
5
- export interface FormattingOptions {
5
+ export interface FormattingOptions extends FormattingOverrides {
6
6
  prefix?: string;
7
7
  suffix?: string;
8
8
  lineSeparator?: string;
9
- header?: string;
10
- footer?: string;
9
+ separator?: string;
10
+ }
11
+ export interface FormattingOverrides {
11
12
  commentStyle?: 'short' | 'long' | 'none';
12
13
  commentPosition?: 'above' | 'inline';
13
14
  indentation?: string;
14
- separator?: string;
15
+ header?: string;
16
+ footer?: string;
15
17
  fileHeaderTimestamp?: boolean;
16
18
  }
17
19
  export type FileHeader = (defaultMessage: string[], options?: Config) => Promise<string[]> | string[];
package/types/Volume.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { IFs } from 'memfs';
2
- export type Volume = (IFs | typeof import('node:fs')) & {
1
+ import type { Volume as _Volume } from '@bundled-es-modules/memfs';
2
+ export type Volume = (InstanceType<typeof _Volume> | typeof import('node:fs')) & {
3
3
  __custom_fs__?: boolean;
4
4
  };
@@ -1 +0,0 @@
1
- declare module '@bundled-es-modules/memfs';