style-dictionary 5.1.4 → 5.3.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 (38) hide show
  1. package/examples/advanced/assets-base64-embed/package.json +1 -1
  2. package/examples/advanced/create-react-app/package.json +1 -1
  3. package/examples/advanced/create-react-native-app/package.json +1 -1
  4. package/examples/advanced/custom-parser/package.json +1 -1
  5. package/examples/advanced/custom-transforms/package.json +1 -1
  6. package/examples/advanced/font-face-rules/package.json +1 -1
  7. package/examples/advanced/format-helpers/package.json +2 -1
  8. package/examples/advanced/matching-build-files/README.md +24 -22
  9. package/examples/advanced/matching-build-files/package.json +1 -1
  10. package/examples/advanced/matching-build-files/tokens/index.js +8 -4
  11. package/examples/advanced/multi-brand-multi-platform/package.json +1 -1
  12. package/examples/advanced/node-modules-as-config-and-properties/package.json +1 -1
  13. package/examples/advanced/npm-module/package.json +1 -1
  14. package/examples/advanced/referencing_aliasing/package.json +1 -1
  15. package/examples/advanced/s3/package.json +1 -1
  16. package/examples/advanced/tailwind-preset/package.json +1 -1
  17. package/examples/advanced/tokens-deprecation/package.json +1 -1
  18. package/examples/advanced/transitive-transforms/package.json +1 -1
  19. package/examples/advanced/variables-in-outputs/package.json +1 -1
  20. package/examples/advanced/yaml-tokens/package.json +1 -1
  21. package/lib/StyleDictionary.js +1 -1
  22. package/lib/common/formatHelpers/fileHeader.js +11 -7
  23. package/lib/common/formatHelpers/formattedVariables.d.ts +5 -1
  24. package/lib/common/formatHelpers/formattedVariables.js +59 -10
  25. package/lib/common/formats.js +10 -5
  26. package/lib/common/transforms.d.ts +108 -0
  27. package/lib/common/transforms.js +311 -17
  28. package/lib/enums/index.d.ts +6 -5
  29. package/lib/enums/index.js +6 -5
  30. package/lib/enums/sorts.d.ts +3 -0
  31. package/lib/enums/sorts.js +3 -0
  32. package/lib/enums/transforms.d.ts +4 -0
  33. package/lib/enums/transforms.js +4 -0
  34. package/package.json +7 -5
  35. package/types/Config.d.ts +2 -0
  36. package/types/DesignToken.d.ts +15 -0
  37. package/types/Sort.d.ts +17 -0
  38. package/types/index.d.ts +1 -0
@@ -12,6 +12,6 @@
12
12
  "author": "",
13
13
  "license": "Apache-2.0",
14
14
  "devDependencies": {
15
- "style-dictionary": "^5.1.4"
15
+ "style-dictionary": "^5.3.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": "^5.1.4"
15
+ "style-dictionary": "^5.3.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": "^5.1.4"
32
+ "style-dictionary": "^5.3.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": "^5.1.4"
13
+ "style-dictionary": "^5.3.0"
14
14
  }
15
15
  }
@@ -16,6 +16,6 @@
16
16
  "author": "",
17
17
  "license": "Apache-2.0",
18
18
  "devDependencies": {
19
- "style-dictionary": "^5.1.4"
19
+ "style-dictionary": "^5.3.0"
20
20
  }
21
21
  }
@@ -9,6 +9,6 @@
9
9
  },
10
10
  "license": "Apache-2.0",
11
11
  "devDependencies": {
12
- "style-dictionary": "^5.1.4"
12
+ "style-dictionary": "^5.3.0"
13
13
  }
14
14
  }
@@ -2,6 +2,7 @@
2
2
  "name": "format-helpers",
3
3
  "version": "1.0.0",
4
4
  "description": "",
5
+ "type": "module",
5
6
  "main": "sd.config.js",
6
7
  "scripts": {
7
8
  "build": "style-dictionary build --config ./sd.config.js"
@@ -10,6 +11,6 @@
10
11
  "author": "",
11
12
  "license": "Apache-2.0",
12
13
  "devDependencies": {
13
- "style-dictionary": "^5.1.4"
14
+ "style-dictionary": "^5.3.0"
14
15
  }
15
16
  }
@@ -18,25 +18,25 @@ At this point, you can run `npm run build`. This command will generate the outpu
18
18
 
19
19
  The "build" command processes the JSON files in the `tokens` folder. The `index.js` file adds each folder, allowing you to map through them in `config.js`. The script goes through each folder and generates a file for each folder and populates it with tokens that match the filter.
20
20
 
21
- ```sh
21
+ ```json
22
22
  # tokens/color/base.json
23
23
  {
24
- "color": {
25
- "red": {
26
- "value": "#FF0000"
27
- }
28
- }
24
+ "color": {
25
+ "red": {
26
+ "value": "#FF0000"
27
+ }
28
+ }
29
29
  }
30
30
  ```
31
31
 
32
- ```sh
32
+ ```json
33
33
  # tokens/size/base.json
34
34
  {
35
- "size": {
36
- "small": {
37
- "value": "2px"
38
- }
39
- }
35
+ "size": {
36
+ "small": {
37
+ "value": "2px"
38
+ }
39
+ }
40
40
  }
41
41
  ```
42
42
 
@@ -46,16 +46,18 @@ Because the folder name matches the category, the output would automatically gen
46
46
 
47
47
  Open the `config.js` file and see how the script first looks within the `tokens` directory to map through each folder. The destination then outputs a file that would match the name, and fill that file with the tokens that match the filter criteria.
48
48
 
49
- ```sh
50
- files: tokens.map(tokenCategory => ({
51
- destination: `${tokenCategory}.js`,
52
- format: "format/js",
53
- filter: {
54
- attributes: {
55
- category: tokenCategory
56
- }
57
- }
58
- }))
49
+ ```js
50
+ {
51
+ files: tokens.map((tokenCategory) => ({
52
+ destination: `${tokenCategory}.js`,
53
+ format: 'format/js',
54
+ filter: {
55
+ attributes: {
56
+ category: tokenCategory,
57
+ },
58
+ },
59
+ }));
60
+ }
59
61
  ```
60
62
 
61
63
  Now each new folder that gets added will automatically generate a corresponding file filled with tokens that match the category!
@@ -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": "^5.1.4"
20
+ "style-dictionary": "^5.3.0"
21
21
  }
22
22
  }
@@ -1,4 +1,8 @@
1
- import { readdirSync, statSync } from 'node:fs';
2
- import { join } from 'node:path';
3
- const dirs = (p) => readdirSync(p).filter((f) => statSync(join(p, f)).isDirectory());
4
- export default dirs(import.meta.url);
1
+ import { readdirSync } from 'node:fs';
2
+
3
+ const dirs = (p) =>
4
+ readdirSync(p, { withFileTypes: true })
5
+ .filter((d) => d.isDirectory())
6
+ .map((d) => d.name);
7
+
8
+ export default dirs(import.meta.dirname);
@@ -16,6 +16,6 @@
16
16
  "author": "",
17
17
  "license": "Apache-2.0",
18
18
  "devDependencies": {
19
- "style-dictionary": "^5.1.4"
19
+ "style-dictionary": "^5.3.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": "^5.1.4",
23
+ "style-dictionary": "^5.3.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": "^5.1.4"
20
+ "style-dictionary": "^5.3.0"
21
21
  }
22
22
  }
@@ -16,6 +16,6 @@
16
16
  "author": "",
17
17
  "license": "Apache-2.0",
18
18
  "devDependencies": {
19
- "style-dictionary": "^5.1.4"
19
+ "style-dictionary": "^5.3.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": "^5.1.4"
19
+ "style-dictionary": "^5.3.0"
20
20
  }
21
21
  }
@@ -10,7 +10,7 @@
10
10
  },
11
11
  "license": "Apache-2.0",
12
12
  "devDependencies": {
13
- "style-dictionary": "^5.1.4",
13
+ "style-dictionary": "^5.3.0",
14
14
  "tailwindcss": "^3.4.15",
15
15
  "mocha": "^10.2.0",
16
16
  "chai": "^5.1.1"
@@ -16,6 +16,6 @@
16
16
  "author": "",
17
17
  "license": "Apache-2.0",
18
18
  "devDependencies": {
19
- "style-dictionary": "^5.1.4"
19
+ "style-dictionary": "^5.3.0"
20
20
  }
21
21
  }
@@ -12,6 +12,6 @@
12
12
  "license": "ISC",
13
13
  "devDependencies": {
14
14
  "colorjs.io": "^0.5.2",
15
- "style-dictionary": "^5.1.4"
15
+ "style-dictionary": "^5.3.0"
16
16
  }
17
17
  }
@@ -11,6 +11,6 @@
11
11
  "author": "",
12
12
  "license": "MIT",
13
13
  "devDependencies": {
14
- "style-dictionary": "^5.1.4"
14
+ "style-dictionary": "^5.3.0"
15
15
  }
16
16
  }
@@ -10,7 +10,7 @@
10
10
  "author": "",
11
11
  "license": "Apache-2.0",
12
12
  "devDependencies": {
13
- "style-dictionary": "^5.1.4",
13
+ "style-dictionary": "^5.3.0",
14
14
  "yaml": "^1.10.0"
15
15
  }
16
16
  }
@@ -67,7 +67,7 @@ export default class StyleDictionary extends Register {
67
67
  // Placeholder is transformed on prepublish -> see scripts/inject-version.js
68
68
  // 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.
69
69
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#browser_compatibility
70
- static VERSION = '5.1.4';
70
+ static VERSION = '5.3.0';
71
71
 
72
72
  /** @returns {Config} */
73
73
  get options() {
@@ -61,11 +61,15 @@ export default async function fileHeader({ file, commentStyle, formatting = {},
61
61
  fn = file.options.fileHeader;
62
62
  }
63
63
 
64
- let { prefix, lineSeparator, header, footer, fileHeaderTimestamp } = Object.assign(
65
- {},
66
- defaultFormatting,
67
- formatting,
68
- );
64
+ let {
65
+ prefix,
66
+ lineSeparator,
67
+ header,
68
+ commentStyle: _commentStyle,
69
+ footer,
70
+ fileHeaderTimestamp,
71
+ } = Object.assign({}, defaultFormatting, formatting);
72
+ const commentStyleMerged = commentStyle ?? _commentStyle;
69
73
 
70
74
  // default header
71
75
  const defaultHeader = [
@@ -73,11 +77,11 @@ export default async function fileHeader({ file, commentStyle, formatting = {},
73
77
  ...(fileHeaderTimestamp ? [`Generated on ${new Date().toUTCString()}`] : []),
74
78
  ];
75
79
 
76
- if (commentStyle === commentStyles.short) {
80
+ if (commentStyleMerged === commentStyles.short) {
77
81
  prefix = `// `;
78
82
  header = `${lineSeparator}`;
79
83
  footer = `${lineSeparator}${lineSeparator}`;
80
- } else if (commentStyle === 'xml') {
84
+ } else if (commentStyleMerged === 'xml') {
81
85
  prefix = ` `;
82
86
  header = `<!--${lineSeparator}`;
83
87
  footer = `${lineSeparator}-->`;
@@ -11,6 +11,7 @@
11
11
  * @param {Formatting} [options.formatting] - Custom formatting properties that define parts of a declaration line in code. This will get passed to `formatHelpers` -> `createPropertyformat` and used for the `lineSeparator` between lines of code.
12
12
  * @param {Boolean} [options.themeable] [false] - Whether tokens should default to being themeable.
13
13
  * @param {boolean} [options.usesDtcg] [false] - Whether DTCG token syntax should be uses.
14
+ * @param {SortOption} [options.sort] - Optional sorting strategy.
14
15
  * @returns {String}
15
16
  * @example
16
17
  * ```js
@@ -28,7 +29,7 @@
28
29
  * });
29
30
  * ```
30
31
  */
31
- export default function formattedVariables({ format, dictionary, outputReferences, outputReferenceFallbacks, formatting, themeable, usesDtcg, }: {
32
+ export default function formattedVariables({ format, dictionary, outputReferences, outputReferenceFallbacks, formatting, themeable, usesDtcg, sort, }: {
32
33
  format: string;
33
34
  dictionary: Dictionary;
34
35
  outputReferences?: import("../../../types/Format.d.ts").OutputReferences | undefined;
@@ -36,9 +37,12 @@ export default function formattedVariables({ format, dictionary, outputReference
36
37
  formatting?: import("../../../types/File.d.ts").FormattingOptions | undefined;
37
38
  themeable?: boolean | undefined;
38
39
  usesDtcg?: boolean | undefined;
40
+ sort?: import("../../../types/Sort.d.ts").SortOption | undefined;
39
41
  }): string;
40
42
  export type Token = import("../../../types/DesignToken.d.ts").TransformedToken;
41
43
  export type Tokens = import("../../../types/DesignToken.d.ts").TransformedTokens;
42
44
  export type Formatting = import("../../../types/File.d.ts").FormattingOptions;
43
45
  export type OutputReferences = import("../../../types/Format.d.ts").OutputReferences;
46
+ export type SortFn = import("../../../types/Sort.d.ts").SortFn;
47
+ export type SortOption = import("../../../types/Sort.d.ts").SortOption;
44
48
  export type Dictionary = import("../../../types/DesignToken.d.ts").Dictionary;
@@ -1,11 +1,14 @@
1
1
  import createPropertyFormatter from './createPropertyFormatter.js';
2
2
  import sortByReference from './sortByReference.js';
3
+ import sortByName from './sortByName.js';
3
4
 
4
5
  /**
5
6
  * @typedef {import('../../../types/DesignToken.d.ts').TransformedToken} Token
6
7
  * @typedef {import('../../../types/DesignToken.d.ts').TransformedTokens} Tokens
7
8
  * @typedef {import('../../../types/File.d.ts').FormattingOptions} Formatting
8
9
  * @typedef {import('../../../types/Format.d.ts').OutputReferences} OutputReferences
10
+ * @typedef {import('../../../types/Sort.d.ts').SortFn} SortFn
11
+ * @typedef {import('../../../types/Sort.d.ts').SortOption} SortOption
9
12
  * @typedef {import('../../../types/DesignToken.d.ts').Dictionary} Dictionary
10
13
  */
11
14
 
@@ -26,6 +29,7 @@ const defaultFormatting = {
26
29
  * @param {Formatting} [options.formatting] - Custom formatting properties that define parts of a declaration line in code. This will get passed to `formatHelpers` -> `createPropertyformat` and used for the `lineSeparator` between lines of code.
27
30
  * @param {Boolean} [options.themeable] [false] - Whether tokens should default to being themeable.
28
31
  * @param {boolean} [options.usesDtcg] [false] - Whether DTCG token syntax should be uses.
32
+ * @param {SortOption} [options.sort] - Optional sorting strategy.
29
33
  * @returns {String}
30
34
  * @example
31
35
  * ```js
@@ -51,6 +55,7 @@ export default function formattedVariables({
51
55
  formatting = {},
52
56
  themeable = false,
53
57
  usesDtcg = false,
58
+ sort,
54
59
  }) {
55
60
  // typecast, we know that by know the tokens have been transformed
56
61
  let allTokens = /** @type {Token[]} */ (dictionary.allTokens);
@@ -59,18 +64,62 @@ export default function formattedVariables({
59
64
 
60
65
  let { lineSeparator } = Object.assign({}, defaultFormatting, formatting);
61
66
 
62
- // Some languages are imperative, meaning a variable has to be defined
63
- // before it is used. If `outputReferences` is true, check if the token
64
- // has a reference, and if it does send it to the end of the array.
65
- // We also need to account for nested references, a -> b -> c. They
66
- // need to be defined in reverse order: c, b, a so that the reference always
67
- // comes after the definition
68
- if (outputReferences) {
67
+ const sortInputs = sort ? (Array.isArray(sort) ? sort : [sort]) : [];
68
+
69
+ // reference-safety sorter is an internal concern:
70
+ // we only compute it when outputReferences=true
71
+ const byReference = outputReferences
72
+ ? sortByReference(tokens, { unfilteredTokens: dictionary.unfilteredTokens, usesDtcg })
73
+ : null;
74
+
75
+ /**
76
+ * @param {SortFn} keyOrFn
77
+ * @returns {((a: Token, b: Token) => number) | null}
78
+ */
79
+ const normalize = (keyOrFn) => {
80
+ if (typeof keyOrFn === 'function') return keyOrFn;
81
+
82
+ if (keyOrFn === 'name') return sortByName;
83
+
84
+ // Fail loudly for invalid values (esp. typos)
85
+ if (typeof keyOrFn === 'string') {
86
+ throw new Error(
87
+ `Invalid "sort" option: "${keyOrFn}". ` +
88
+ `Use "name", a comparator function, or an array of those.`,
89
+ );
90
+ }
91
+
92
+ // Non-string non-function values are also invalid
93
+ throw new Error(
94
+ `Invalid "sort" option type: ${typeof keyOrFn}. ` +
95
+ `Use "name", a comparator function, or an array of those.`,
96
+ );
97
+ };
98
+
99
+ /**
100
+ * @param {((a: Token, b: Token) => number) | null} s
101
+ * @returns {s is ((a: Token, b: Token) => number)}
102
+ */
103
+ const isComparator = (s) => s !== null;
104
+
105
+ const requestedSorters = sortInputs.map(normalize).filter(isComparator);
106
+
107
+ // If outputReferences=true, enforce reference-safe ordering first (define-before-use safety).
108
+ // The user-provided sort acts as a tie-breaker on top.
109
+ const comparators = outputReferences
110
+ ? [byReference, ...requestedSorters].filter(isComparator)
111
+ : requestedSorters.filter(isComparator);
112
+
113
+ if (comparators.length > 0) {
69
114
  // note: using the spread operator here so we get a new array rather than
70
115
  // mutating the original
71
- allTokens = [...allTokens].sort(
72
- sortByReference(tokens, { unfilteredTokens: dictionary.unfilteredTokens, usesDtcg }),
73
- );
116
+ allTokens = [...allTokens].sort((a, b) => {
117
+ for (const cmp of comparators) {
118
+ const r = cmp(a, b);
119
+ if (r !== 0) return r;
120
+ }
121
+ return 0;
122
+ });
74
123
  }
75
124
 
76
125
  return allTokens
@@ -193,7 +193,7 @@ const formats = {
193
193
  : options.selector
194
194
  ? [options.selector]
195
195
  : [`:root`];
196
- const { outputReferences, outputReferenceFallbacks, usesDtcg, formatting } = options;
196
+ const { outputReferences, outputReferenceFallbacks, usesDtcg, formatting, sort } = options;
197
197
  const header = await fileHeader({
198
198
  file,
199
199
  formatting: getFormattingCloneWithoutPrefix(formatting),
@@ -219,6 +219,7 @@ const formats = {
219
219
  indentation: indentation.repeat(selector.length),
220
220
  },
221
221
  usesDtcg,
222
+ sort,
222
223
  });
223
224
 
224
225
  return (
@@ -289,7 +290,7 @@ const formats = {
289
290
  */
290
291
  [scssMapDeep]: async function ({ dictionary, options, file }) {
291
292
  // Default the "themeable" option to true for backward compatibility.
292
- const { outputReferences, themeable = true, formatting, usesDtcg } = options;
293
+ const { outputReferences, themeable = true, formatting, usesDtcg, sort } = options;
293
294
  const header = await fileHeader({
294
295
  file,
295
296
  commentStyle: long,
@@ -306,6 +307,7 @@ const formats = {
306
307
  themeable,
307
308
  formatting,
308
309
  usesDtcg,
310
+ sort,
309
311
  }) +
310
312
  '\n' +
311
313
  scssMapDeepTemplate({ dictionary, options })
@@ -326,7 +328,7 @@ const formats = {
326
328
  * ```
327
329
  */
328
330
  [scssVariables]: async function ({ dictionary, options, file }) {
329
- const { outputReferences, themeable = false, formatting, usesDtcg } = options;
331
+ const { outputReferences, themeable = false, formatting, usesDtcg, sort } = options;
330
332
  const header = await fileHeader({
331
333
  file,
332
334
  commentStyle: short,
@@ -342,6 +344,7 @@ const formats = {
342
344
  themeable,
343
345
  formatting,
344
346
  usesDtcg,
347
+ sort,
345
348
  }) +
346
349
  '\n'
347
350
  );
@@ -381,7 +384,7 @@ const formats = {
381
384
  * ```
382
385
  */
383
386
  [lessVariables]: async function ({ dictionary, options, file }) {
384
- const { outputReferences, formatting, usesDtcg } = options;
387
+ const { outputReferences, formatting, usesDtcg, sort } = options;
385
388
  const header = await fileHeader({
386
389
  file,
387
390
  commentStyle: short,
@@ -396,6 +399,7 @@ const formats = {
396
399
  outputReferences,
397
400
  formatting,
398
401
  usesDtcg,
402
+ sort,
399
403
  }) +
400
404
  '\n'
401
405
  );
@@ -435,7 +439,7 @@ const formats = {
435
439
  * ```
436
440
  */
437
441
  [stylusVariables]: async function ({ dictionary, options, file, platform }) {
438
- const { formatting, usesDtcg } = options;
442
+ const { formatting, usesDtcg, sort } = options;
439
443
  const outputReferences = !!platform.options?.outputReferences;
440
444
  const header = await fileHeader({
441
445
  file,
@@ -451,6 +455,7 @@ const formats = {
451
455
  outputReferences,
452
456
  formatting,
453
457
  usesDtcg,
458
+ sort,
454
459
  }) +
455
460
  '\n'
456
461
  );
@@ -1,3 +1,36 @@
1
+ /**
2
+ * Check if a value is a DTCG color object
3
+ * @param {unknown} val
4
+ * @returns {val is DTCGColorValue}
5
+ */
6
+ export function isDTCGColorObject(val: unknown): val is DTCGColorValue;
7
+ /**
8
+ * Get color RGB values from either legacy string format or DTCG object format
9
+ * @param {Token} token
10
+ * @param {Config} options
11
+ * @returns {{ r: number, g: number, b: number, a: number }}
12
+ */
13
+ export function getColorRgb(token: Token, options: Config): {
14
+ r: number;
15
+ g: number;
16
+ b: number;
17
+ a: number;
18
+ };
19
+ /**
20
+ * Get a tinycolor2 Color instance from either legacy string format or DTCG object format
21
+ * This provides backward compatibility for transformers that use tinycolor2 methods
22
+ * @param {Token} token
23
+ * @param {Config} options
24
+ * @returns {ReturnType<typeof Color>}
25
+ */
26
+ export function getColor(token: Token, options: Config): ReturnType<typeof Color>;
27
+ /**
28
+ * Get a ColorJS Color instance from either legacy string format or DTCG object format
29
+ * @param {Token} token
30
+ * @param {Config} options
31
+ * @returns {ColorJS}
32
+ */
33
+ export function getColorJS(token: Token, options: Config): ColorJS;
1
34
  /**
2
35
  * @param {Token} token
3
36
  * @param {Config} options
@@ -354,6 +387,78 @@ declare const _default: {
354
387
  alpha: number;
355
388
  };
356
389
  };
390
+ /**
391
+ * Transforms the value into an OKLCH CSS color function string.
392
+ * Preserves wide-gamut colors without lossy gamut mapping.
393
+ *
394
+ * ```css
395
+ * // Matches: token.type === 'color'
396
+ * // Returns:
397
+ * "oklch(0.7 0.15 180)"
398
+ * "oklch(0.7 0.15 180 / 0.5)"
399
+ * ```
400
+ *
401
+ * @memberof Transforms
402
+ */
403
+ "color/oklch": {
404
+ type: "value";
405
+ filter: typeof isColor;
406
+ transform: (token: import("../../types/DesignToken.d.ts").TransformedToken, _: import("../../types/Config.d.ts").PlatformConfig, options: import("../../types/Config.d.ts").Config) => string;
407
+ };
408
+ /**
409
+ * Transforms the value into an OKLAB CSS color function string.
410
+ * Preserves wide-gamut colors without lossy gamut mapping.
411
+ *
412
+ * ```css
413
+ * // Matches: token.type === 'color'
414
+ * // Returns:
415
+ * "oklab(0.7 -0.1 0.1)"
416
+ * "oklab(0.7 -0.1 0.1 / 0.5)"
417
+ * ```
418
+ *
419
+ * @memberof Transforms
420
+ */
421
+ "color/oklab": {
422
+ type: "value";
423
+ filter: typeof isColor;
424
+ transform: (token: import("../../types/DesignToken.d.ts").TransformedToken, _: import("../../types/Config.d.ts").PlatformConfig, options: import("../../types/Config.d.ts").Config) => string;
425
+ };
426
+ /**
427
+ * Transforms the value into a Display P3 CSS color function string.
428
+ * Preserves wide-gamut colors without lossy gamut mapping.
429
+ *
430
+ * ```css
431
+ * // Matches: token.type === 'color'
432
+ * // Returns:
433
+ * "color(display-p3 0.5 0.5 0.5)"
434
+ * "color(display-p3 0.5 0.5 0.5 / 0.5)"
435
+ * ```
436
+ *
437
+ * @memberof Transforms
438
+ */
439
+ "color/p3": {
440
+ type: "value";
441
+ filter: typeof isColor;
442
+ transform: (token: import("../../types/DesignToken.d.ts").TransformedToken, _: import("../../types/Config.d.ts").PlatformConfig, options: import("../../types/Config.d.ts").Config) => string;
443
+ };
444
+ /**
445
+ * Transforms the value into an LCH CSS color function string.
446
+ * Preserves wide-gamut colors without lossy gamut mapping.
447
+ *
448
+ * ```css
449
+ * // Matches: token.type === 'color'
450
+ * // Returns:
451
+ * "lch(50% 30 180)"
452
+ * "lch(50% 30 180 / 0.5)"
453
+ * ```
454
+ *
455
+ * @memberof Transforms
456
+ */
457
+ "color/lch": {
458
+ type: "value";
459
+ filter: typeof isColor;
460
+ transform: (token: import("../../types/DesignToken.d.ts").TransformedToken, _: import("../../types/Config.d.ts").PlatformConfig, options: import("../../types/Config.d.ts").Config) => string;
461
+ };
357
462
  /**
358
463
  * Transforms the value into a scale-independent pixel (sp) value for font sizes on Android. It will not scale the number.
359
464
  *
@@ -975,9 +1080,12 @@ declare const _default: {
975
1080
  export default _default;
976
1081
  export type Transform = import("../../types/Transform.d.ts").Transform;
977
1082
  export type Token = import("../../types/DesignToken.d.ts").TransformedToken;
1083
+ export type DTCGColorValue = import("../../types/DesignToken.d.ts").DTCGColorValue;
1084
+ export type DTCGColorSpace = import("../../types/DesignToken.d.ts").DTCGColorSpace;
978
1085
  export type PlatformConfig = import("../../types/Config.d.ts").PlatformConfig;
979
1086
  export type Config = import("../../types/Config.d.ts").Config;
980
1087
  import Color from 'tinycolor2';
1088
+ import ColorJS from 'colorjs.io';
981
1089
  /**
982
1090
  * @param {Token} token
983
1091
  * @param {Config} options
@@ -1,4 +1,5 @@
1
1
  import Color from 'tinycolor2';
2
+ import ColorJS from 'colorjs.io';
2
3
  import { join } from 'path-unified/posix';
3
4
  import { snakeCase, kebabCase, camelCase } from 'change-case';
4
5
  import convertToBase64 from '../utils/convertToBase64.js';
@@ -8,6 +9,8 @@ import { transforms, transformTypes } from '../enums/index.js';
8
9
  /**
9
10
  * @typedef {import('../../types/Transform.d.ts').Transform} Transform
10
11
  * @typedef {import('../../types/DesignToken.d.ts').TransformedToken} Token
12
+ * @typedef {import('../../types/DesignToken.d.ts').DTCGColorValue} DTCGColorValue
13
+ * @typedef {import('../../types/DesignToken.d.ts').DTCGColorSpace} DTCGColorSpace
11
14
  * @typedef {import('../../types/Config.d.ts').PlatformConfig} PlatformConfig
12
15
  * @typedef {import('../../types/Config.d.ts').Config} Config
13
16
  */
@@ -15,6 +18,169 @@ import { transforms, transformTypes } from '../enums/index.js';
15
18
  const UNKNOWN_CSS_FONT_PROPS_WARNINGS = GroupMessages.GROUP.UnknownCSSFontProperties;
16
19
  const { value, name, attribute } = transformTypes;
17
20
 
21
+ /**
22
+ * Valid DTCG v2025.10 color spaces
23
+ * @type {Set<string>}
24
+ */
25
+ const DTCG_COLOR_SPACES = new Set([
26
+ 'srgb',
27
+ 'srgb-linear',
28
+ 'display-p3',
29
+ 'a98-rgb',
30
+ 'prophoto-rgb',
31
+ 'rec2020',
32
+ 'xyz-d50',
33
+ 'xyz-d65',
34
+ 'lab',
35
+ 'lch',
36
+ 'oklab',
37
+ 'oklch',
38
+ 'hsl',
39
+ 'hwb',
40
+ ]);
41
+
42
+ /**
43
+ * Map DTCG color space names to colorjs.io color space IDs
44
+ * @type {Record<string, string>}
45
+ */
46
+ const DTCG_TO_COLORJS_SPACE = {
47
+ srgb: 'srgb',
48
+ 'srgb-linear': 'srgb-linear',
49
+ 'display-p3': 'p3',
50
+ 'a98-rgb': 'a98rgb',
51
+ 'prophoto-rgb': 'prophoto',
52
+ rec2020: 'rec2020',
53
+ 'xyz-d50': 'xyz-d50',
54
+ 'xyz-d65': 'xyz-d65',
55
+ lab: 'lab',
56
+ lch: 'lch',
57
+ oklab: 'oklab',
58
+ oklch: 'oklch',
59
+ hsl: 'hsl',
60
+ hwb: 'hwb',
61
+ };
62
+
63
+ /**
64
+ * Check if a value is a DTCG color object
65
+ * @param {unknown} val
66
+ * @returns {val is DTCGColorValue}
67
+ */
68
+ export function isDTCGColorObject(val) {
69
+ return (
70
+ typeof val === 'object' &&
71
+ val !== null &&
72
+ 'colorSpace' in val &&
73
+ typeof val.colorSpace === 'string' &&
74
+ DTCG_COLOR_SPACES.has(val.colorSpace) &&
75
+ 'components' in val &&
76
+ Array.isArray(val.components)
77
+ );
78
+ }
79
+
80
+ /**
81
+ * Convert a DTCG color object to a ColorJS Color instance
82
+ * Handles 'none' values in components and alpha
83
+ * @param {DTCGColorValue} dtcgColor
84
+ * @returns {ColorJS}
85
+ */
86
+ function dtcgToColorJS(dtcgColor) {
87
+ const { colorSpace, components, alpha } = dtcgColor;
88
+
89
+ // Map DTCG color space to colorjs.io color space ID
90
+ const colorjsSpace = DTCG_TO_COLORJS_SPACE[colorSpace] ?? colorSpace;
91
+
92
+ // Convert 'none' values to NaN (as per CSS Color spec)
93
+ const coords = /** @type {[number, number, number]} */ (
94
+ components.map((c) => (c === 'none' ? NaN : c))
95
+ );
96
+ const alphaValue = alpha === 'none' ? NaN : (alpha ?? 1);
97
+
98
+ return new ColorJS(colorjsSpace, coords, alphaValue);
99
+ }
100
+
101
+ /**
102
+ * Get the sRGB representation of a color, with gamut mapping if needed
103
+ * Uses the hex property as fallback if provided and color is out of gamut
104
+ * @param {DTCGColorValue} dtcgColor
105
+ * @returns {{ r: number, g: number, b: number, a: number }}
106
+ */
107
+ function dtcgColorToRgb(dtcgColor) {
108
+ const color = dtcgToColorJS(dtcgColor);
109
+
110
+ // Check if color is in sRGB gamut
111
+ if (!color.inGamut('srgb')) {
112
+ // If hex fallback is provided, use it
113
+ if (dtcgColor.hex) {
114
+ const fallback = Color(dtcgColor.hex).toRgb();
115
+ return fallback;
116
+ }
117
+ // Otherwise, perform gamut mapping
118
+ color.toGamut({ space: 'srgb' });
119
+ }
120
+
121
+ const srgb = color.to('srgb');
122
+ const alpha = isNaN(srgb.alpha) ? 1 : srgb.alpha;
123
+
124
+ return {
125
+ r: Math.round(Math.max(0, Math.min(1, srgb.coords[0])) * 255),
126
+ g: Math.round(Math.max(0, Math.min(1, srgb.coords[1])) * 255),
127
+ b: Math.round(Math.max(0, Math.min(1, srgb.coords[2])) * 255),
128
+ a: alpha,
129
+ };
130
+ }
131
+
132
+ /**
133
+ * Get color RGB values from either legacy string format or DTCG object format
134
+ * @param {Token} token
135
+ * @param {Config} options
136
+ * @returns {{ r: number, g: number, b: number, a: number }}
137
+ */
138
+ export function getColorRgb(token, options) {
139
+ const val = options.usesDtcg ? token.$value : token.value;
140
+
141
+ if (isDTCGColorObject(val)) {
142
+ return dtcgColorToRgb(val);
143
+ }
144
+
145
+ // Legacy format - use tinycolor2
146
+ return Color(val).toRgb();
147
+ }
148
+
149
+ /**
150
+ * Get a tinycolor2 Color instance from either legacy string format or DTCG object format
151
+ * This provides backward compatibility for transformers that use tinycolor2 methods
152
+ * @param {Token} token
153
+ * @param {Config} options
154
+ * @returns {ReturnType<typeof Color>}
155
+ */
156
+ export function getColor(token, options) {
157
+ const val = options.usesDtcg ? token.$value : token.value;
158
+
159
+ if (isDTCGColorObject(val)) {
160
+ const rgb = dtcgColorToRgb(val);
161
+ return Color(rgb);
162
+ }
163
+
164
+ return Color(val);
165
+ }
166
+
167
+ /**
168
+ * Get a ColorJS Color instance from either legacy string format or DTCG object format
169
+ * @param {Token} token
170
+ * @param {Config} options
171
+ * @returns {ColorJS}
172
+ */
173
+ export function getColorJS(token, options) {
174
+ const val = options.usesDtcg ? token.$value : token.value;
175
+
176
+ if (isDTCGColorObject(val)) {
177
+ return dtcgToColorJS(val);
178
+ }
179
+
180
+ // Parse legacy format with ColorJS
181
+ return new ColorJS(val);
182
+ }
183
+
18
184
  /**
19
185
  * @param {string} str
20
186
  * @returns {string}
@@ -33,8 +199,14 @@ const camelOpts = {
33
199
  export function isColor(token, options) {
34
200
  const val = options.usesDtcg ? token.$value : token.value;
35
201
  const type = options.usesDtcg ? token.$type : token.type;
202
+
203
+ if (type !== 'color') return false;
204
+
205
+ // DTCG object format
206
+ if (isDTCGColorObject(val)) return true;
207
+
208
+ // Legacy string format
36
209
  return (
37
- type === 'color' &&
38
210
  Color(val).isValid() &&
39
211
  // exclude gradients from being color transformed
40
212
  ['linear', 'radial', 'conic']
@@ -257,7 +429,7 @@ export default {
257
429
  type: attribute,
258
430
  filter: isColor,
259
431
  transform: function (token, _, options) {
260
- const color = Color(options.usesDtcg ? token.$value : token.value);
432
+ const color = getColor(token, options);
261
433
  return {
262
434
  hex: color.toHex(),
263
435
  rgb: color.toRgb(),
@@ -399,7 +571,7 @@ export default {
399
571
  type: value,
400
572
  filter: isColor,
401
573
  transform: function (token, _, options) {
402
- return Color(options.usesDtcg ? token.$value : token.value).toRgbString();
574
+ return getColor(token, options).toRgbString();
403
575
  },
404
576
  },
405
577
 
@@ -419,7 +591,7 @@ export default {
419
591
  type: value,
420
592
  filter: isColor,
421
593
  transform: function (token, _, options) {
422
- return Color(options.usesDtcg ? token.$value : token.value).toHslString();
594
+ return getColor(token, options).toHslString();
423
595
  },
424
596
  },
425
597
 
@@ -439,7 +611,7 @@ export default {
439
611
  type: value,
440
612
  filter: isColor,
441
613
  transform: function (token, _, options) {
442
- const color = Color(options.usesDtcg ? token.$value : token.value);
614
+ const color = getColor(token, options);
443
615
  const o = color.toHsl();
444
616
  const vals = `${Math.round(o.h)} ${Math.round(o.s * 100)}% ${Math.round(o.l * 100)}%`;
445
617
  if (color.getAlpha() === 1) {
@@ -465,7 +637,7 @@ export default {
465
637
  type: value,
466
638
  filter: isColor,
467
639
  transform: function (token, _, options) {
468
- const color = Color(options.usesDtcg ? token.$value : token.value);
640
+ const color = getColor(token, options);
469
641
  if (color.getAlpha() === 1) {
470
642
  return color.toHexString();
471
643
  } else {
@@ -489,7 +661,7 @@ export default {
489
661
  type: value,
490
662
  filter: isColor,
491
663
  transform: function (token, _, options) {
492
- return Color(options.usesDtcg ? token.$value : token.value).toHex8String();
664
+ return getColor(token, options).toHex8String();
493
665
  },
494
666
  },
495
667
 
@@ -508,7 +680,7 @@ export default {
508
680
  type: value,
509
681
  filter: isColor,
510
682
  transform: function (token, _, options) {
511
- const str = Color(options.usesDtcg ? token.$value : token.value).toHex8();
683
+ const str = getColor(token, options).toHex8();
512
684
  return '#' + str.slice(6) + str.slice(0, 6);
513
685
  },
514
686
  },
@@ -528,7 +700,7 @@ export default {
528
700
  type: value,
529
701
  filter: isColor,
530
702
  transform: function (token, _, options) {
531
- const str = Color(options.usesDtcg ? token.$value : token.value).toHex8();
703
+ const str = getColor(token, options).toHex8();
532
704
  return 'Color(0x' + str.slice(6) + str.slice(0, 6) + ')';
533
705
  },
534
706
  },
@@ -548,7 +720,7 @@ export default {
548
720
  type: value,
549
721
  filter: isColor,
550
722
  transform: function (token, _, options) {
551
- const rgb = Color(options.usesDtcg ? token.$value : token.value).toRgb();
723
+ const rgb = getColor(token, options).toRgb();
552
724
  return (
553
725
  '[UIColor colorWithRed:' +
554
726
  (rgb.r / 255).toFixed(3) +
@@ -581,7 +753,7 @@ export default {
581
753
  type: value,
582
754
  filter: isColor,
583
755
  transform: function (token, _, options) {
584
- const { r, g, b, a } = Color(options.usesDtcg ? token.$value : token.value).toRgb();
756
+ const { r, g, b, a } = getColor(token, options).toRgb();
585
757
  const rFixed = (r / 255.0).toFixed(3);
586
758
  const gFixed = (g / 255.0).toFixed(3);
587
759
  const bFixed = (b / 255.0).toFixed(3);
@@ -604,7 +776,7 @@ export default {
604
776
  type: value,
605
777
  filter: isColor,
606
778
  transform: function (token, _, options) {
607
- const { r, g, b, a } = Color(options.usesDtcg ? token.$value : token.value).toRgb();
779
+ const { r, g, b, a } = getColor(token, options).toRgb();
608
780
  const rFixed = (r / 255.0).toFixed(3);
609
781
  const gFixed = (g / 255.0).toFixed(3);
610
782
  const bFixed = (b / 255.0).toFixed(3);
@@ -628,7 +800,7 @@ export default {
628
800
  type: value,
629
801
  filter: isColor,
630
802
  transform: function (token, _, options) {
631
- const color = Color(options.usesDtcg ? token.$value : token.value);
803
+ const color = getColor(token, options);
632
804
  if (color.getAlpha() === 1) {
633
805
  return color.toHexString();
634
806
  } else {
@@ -659,7 +831,7 @@ export default {
659
831
  type: value,
660
832
  filter: isColor,
661
833
  transform: function (token, _, options) {
662
- let color = Color(options.usesDtcg ? token.$value : token.value).toRgb();
834
+ let color = getColor(token, options).toRgb();
663
835
  return {
664
836
  red: (color.r / 255).toFixed(5),
665
837
  green: (color.g / 255).toFixed(5),
@@ -669,6 +841,130 @@ export default {
669
841
  },
670
842
  },
671
843
 
844
+ /**
845
+ * Transforms the value into an OKLCH CSS color function string.
846
+ * Preserves wide-gamut colors without lossy gamut mapping.
847
+ *
848
+ * ```css
849
+ * // Matches: token.type === 'color'
850
+ * // Returns:
851
+ * "oklch(0.7 0.15 180)"
852
+ * "oklch(0.7 0.15 180 / 0.5)"
853
+ * ```
854
+ *
855
+ * @memberof Transforms
856
+ */
857
+ [transforms.colorOklch]: {
858
+ type: value,
859
+ filter: isColor,
860
+ transform: function (token, _, options) {
861
+ const color = getColorJS(token, options).to('oklch');
862
+ const [l, c, h] = color.coords;
863
+ const alpha = isNaN(color.alpha) ? 1 : color.alpha;
864
+ // Format: oklch(L C H) or oklch(L C H / alpha)
865
+ const lStr = (isNaN(l) ? 0 : l).toFixed(4);
866
+ const cStr = (isNaN(c) ? 0 : c).toFixed(4);
867
+ const hStr = (isNaN(h) ? 0 : h).toFixed(2);
868
+ if (alpha === 1) {
869
+ return `oklch(${lStr} ${cStr} ${hStr})`;
870
+ }
871
+ return `oklch(${lStr} ${cStr} ${hStr} / ${alpha})`;
872
+ },
873
+ },
874
+
875
+ /**
876
+ * Transforms the value into an OKLAB CSS color function string.
877
+ * Preserves wide-gamut colors without lossy gamut mapping.
878
+ *
879
+ * ```css
880
+ * // Matches: token.type === 'color'
881
+ * // Returns:
882
+ * "oklab(0.7 -0.1 0.1)"
883
+ * "oklab(0.7 -0.1 0.1 / 0.5)"
884
+ * ```
885
+ *
886
+ * @memberof Transforms
887
+ */
888
+ [transforms.colorOklab]: {
889
+ type: value,
890
+ filter: isColor,
891
+ transform: function (token, _, options) {
892
+ const color = getColorJS(token, options).to('oklab');
893
+ const [l, a, b] = color.coords;
894
+ const alpha = isNaN(color.alpha) ? 1 : color.alpha;
895
+ // Format: oklab(L a b) or oklab(L a b / alpha)
896
+ const lStr = (isNaN(l) ? 0 : l).toFixed(4);
897
+ const aStr = (isNaN(a) ? 0 : a).toFixed(4);
898
+ const bStr = (isNaN(b) ? 0 : b).toFixed(4);
899
+ if (alpha === 1) {
900
+ return `oklab(${lStr} ${aStr} ${bStr})`;
901
+ }
902
+ return `oklab(${lStr} ${aStr} ${bStr} / ${alpha})`;
903
+ },
904
+ },
905
+
906
+ /**
907
+ * Transforms the value into a Display P3 CSS color function string.
908
+ * Preserves wide-gamut colors without lossy gamut mapping.
909
+ *
910
+ * ```css
911
+ * // Matches: token.type === 'color'
912
+ * // Returns:
913
+ * "color(display-p3 0.5 0.5 0.5)"
914
+ * "color(display-p3 0.5 0.5 0.5 / 0.5)"
915
+ * ```
916
+ *
917
+ * @memberof Transforms
918
+ */
919
+ [transforms.colorP3]: {
920
+ type: value,
921
+ filter: isColor,
922
+ transform: function (token, _, options) {
923
+ const color = getColorJS(token, options).to('p3');
924
+ const [r, g, b] = color.coords;
925
+ const alpha = isNaN(color.alpha) ? 1 : color.alpha;
926
+ // Format: color(display-p3 r g b) or color(display-p3 r g b / alpha)
927
+ const rStr = (isNaN(r) ? 0 : r).toFixed(5);
928
+ const gStr = (isNaN(g) ? 0 : g).toFixed(5);
929
+ const bStr = (isNaN(b) ? 0 : b).toFixed(5);
930
+ if (alpha === 1) {
931
+ return `color(display-p3 ${rStr} ${gStr} ${bStr})`;
932
+ }
933
+ return `color(display-p3 ${rStr} ${gStr} ${bStr} / ${alpha})`;
934
+ },
935
+ },
936
+
937
+ /**
938
+ * Transforms the value into an LCH CSS color function string.
939
+ * Preserves wide-gamut colors without lossy gamut mapping.
940
+ *
941
+ * ```css
942
+ * // Matches: token.type === 'color'
943
+ * // Returns:
944
+ * "lch(50% 30 180)"
945
+ * "lch(50% 30 180 / 0.5)"
946
+ * ```
947
+ *
948
+ * @memberof Transforms
949
+ */
950
+ [transforms.colorLch]: {
951
+ type: value,
952
+ filter: isColor,
953
+ transform: function (token, _, options) {
954
+ const color = getColorJS(token, options).to('lch');
955
+ const [l, c, h] = color.coords;
956
+ const alpha = isNaN(color.alpha) ? 1 : color.alpha;
957
+ // Format: lch(L% C H) or lch(L% C H / alpha)
958
+ const lStr = (isNaN(l) ? 0 : l).toFixed(2);
959
+ const cStr = (isNaN(c) ? 0 : c).toFixed(2);
960
+ const hStr = (isNaN(h) ? 0 : h).toFixed(2);
961
+ if (alpha === 1) {
962
+ return `lch(${lStr}% ${cStr} ${hStr})`;
963
+ }
964
+ return `lch(${lStr}% ${cStr} ${hStr} / ${alpha})`;
965
+ },
966
+ },
967
+
672
968
  /**
673
969
  * Transforms the value into a scale-independent pixel (sp) value for font sizes on Android. It will not scale the number.
674
970
  *
@@ -1515,9 +1811,7 @@ export default {
1515
1811
  type: value,
1516
1812
  filter: isColor,
1517
1813
  transform: function (token, _, options) {
1518
- const str = Color(options.usesDtcg ? token.$value : token.value)
1519
- .toHex8()
1520
- .toUpperCase();
1814
+ const str = getColor(token, options).toHex8().toUpperCase();
1521
1815
  return `Color(0x${str.slice(6)}${str.slice(0, 6)})`;
1522
1816
  },
1523
1817
  },
@@ -1,12 +1,13 @@
1
1
  export { actions } from "./actions.js";
2
- export { logWarningLevels } from "./logWarningLevels.js";
3
- export { logVerbosityLevels } from "./logVerbosityLevels.js";
4
- export { logBrokenReferenceLevels } from "./logBrokenReferenceLevels.js";
5
- export { commentStyles } from "./commentStyles.js";
6
2
  export { commentPositions } from "./commentPositions.js";
3
+ export { commentStyles } from "./commentStyles.js";
7
4
  export { fileHeaderCommentStyles } from "./fileHeaderCommentStyles.js";
8
5
  export { formats } from "./formats.js";
6
+ export { logBrokenReferenceLevels } from "./logBrokenReferenceLevels.js";
7
+ export { logVerbosityLevels } from "./logVerbosityLevels.js";
8
+ export { logWarningLevels } from "./logWarningLevels.js";
9
+ export { propertyFormatNames } from "./propertyFormatNames.js";
10
+ export { builtInSorts } from "./sorts.js";
9
11
  export { transformGroups } from "./transformGroups.js";
10
12
  export { transforms } from "./transforms.js";
11
13
  export { transformTypes } from "./transformTypes.js";
12
- export { propertyFormatNames } from "./propertyFormatNames.js";
@@ -1,12 +1,13 @@
1
1
  export { actions } from './actions.js';
2
- export { logWarningLevels } from './logWarningLevels.js';
3
- export { logVerbosityLevels } from './logVerbosityLevels.js';
4
- export { logBrokenReferenceLevels } from './logBrokenReferenceLevels.js';
5
- export { commentStyles } from './commentStyles.js';
6
2
  export { commentPositions } from './commentPositions.js';
3
+ export { commentStyles } from './commentStyles.js';
7
4
  export { fileHeaderCommentStyles } from './fileHeaderCommentStyles.js';
8
5
  export { formats } from './formats.js';
6
+ export { logBrokenReferenceLevels } from './logBrokenReferenceLevels.js';
7
+ export { logVerbosityLevels } from './logVerbosityLevels.js';
8
+ export { logWarningLevels } from './logWarningLevels.js';
9
+ export { propertyFormatNames } from './propertyFormatNames.js';
10
+ export { builtInSorts } from './sorts.js';
9
11
  export { transformGroups } from './transformGroups.js';
10
12
  export { transforms } from './transforms.js';
11
13
  export { transformTypes } from './transformTypes.js';
12
- export { propertyFormatNames } from './propertyFormatNames.js';
@@ -0,0 +1,3 @@
1
+ export namespace builtInSorts {
2
+ let name: "name";
3
+ }
@@ -0,0 +1,3 @@
1
+ export const builtInSorts = {
2
+ name: /** @type {'name'} */ ('name'),
3
+ };
@@ -52,6 +52,10 @@ export namespace transforms {
52
52
  let assetObjCLiteral: "asset/objC/literal";
53
53
  let assetSwiftLiteral: "asset/swift/literal";
54
54
  let colorHex8flutter: "color/hex8flutter";
55
+ let colorOklch: "color/oklch";
56
+ let colorOklab: "color/oklab";
57
+ let colorP3: "color/p3";
58
+ let colorLch: "color/lch";
55
59
  let contentFlutterLiteral: "content/flutter/literal";
56
60
  let assetFlutterLiteral: "asset/flutter/literal";
57
61
  let sizeFlutterRemToDouble: "size/flutter/remToDouble";
@@ -52,6 +52,10 @@ export const transforms = {
52
52
  assetObjCLiteral: /** @type {'asset/objC/literal'} */ ('asset/objC/literal'),
53
53
  assetSwiftLiteral: /** @type {'asset/swift/literal'} */ ('asset/swift/literal'),
54
54
  colorHex8flutter: /** @type {'color/hex8flutter'} */ ('color/hex8flutter'),
55
+ colorOklch: /** @type {'color/oklch'} */ ('color/oklch'),
56
+ colorOklab: /** @type {'color/oklab'} */ ('color/oklab'),
57
+ colorP3: /** @type {'color/p3'} */ ('color/p3'),
58
+ colorLch: /** @type {'color/lch'} */ ('color/lch'),
55
59
  contentFlutterLiteral: /** @type {'content/flutter/literal'} */ ('content/flutter/literal'),
56
60
  assetFlutterLiteral: /** @type {'asset/flutter/literal'} */ ('asset/flutter/literal'),
57
61
  sizeFlutterRemToDouble: /** @type {'size/flutter/remToDouble'} */ ('size/flutter/remToDouble'),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "style-dictionary",
3
- "version": "5.1.4",
3
+ "version": "5.3.0",
4
4
  "description": "Style once, use everywhere. A build system for creating cross-platform styles.",
5
5
  "keywords": [
6
6
  "style dictionary",
@@ -112,15 +112,17 @@
112
112
  ],
113
113
  "homepage": "https://styledictionary.com",
114
114
  "overrides": {
115
- "tmp": "0.2.5"
115
+ "tmp": "0.2.5",
116
+ "lodash": "4.17.23"
116
117
  },
117
118
  "dependencies": {
118
119
  "@bundled-es-modules/deepmerge": "^4.3.1",
119
- "@bundled-es-modules/glob": "^11.1.0",
120
- "@bundled-es-modules/memfs": "^4.9.4",
120
+ "@bundled-es-modules/glob": "^13.0.1",
121
+ "@bundled-es-modules/memfs": "^4.17.0",
121
122
  "@zip.js/zip.js": "^2.7.44",
122
123
  "chalk": "^5.3.0",
123
124
  "change-case": "^5.3.0",
125
+ "colorjs.io": "^0.5.2",
124
126
  "commander": "^12.1.0",
125
127
  "is-plain-obj": "^4.1.0",
126
128
  "json5": "^2.2.2",
@@ -163,7 +165,7 @@
163
165
  "lint-staged": "^12.3.1",
164
166
  "lit": "^3.1.2",
165
167
  "mdast": "^3.0.0",
166
- "mermaid": "^11.6.0",
168
+ "mermaid": "^10.9.5",
167
169
  "mocha": "^10.2.0",
168
170
  "monaco-editor": "^0.47.0",
169
171
  "npm-run-all": "^4.1.5",
package/types/Config.d.ts CHANGED
@@ -5,6 +5,7 @@ import type { Parser } from './Parser.js';
5
5
  import type { Preprocessor } from './Preprocessor.js';
6
6
  import type { Transform } from './Transform.js';
7
7
  import type { Format, OutputReferences } from './Format.js';
8
+ import type { SortOption } from './Sort.js';
8
9
  import type { Action } from './Action.js';
9
10
  import { logBrokenReferenceLevels, logWarningLevels, logVerbosityLevels } from '../lib/enums/index.js';
10
11
  type logWarningLevels = typeof logWarningLevels;
@@ -26,6 +27,7 @@ export interface LocalOptions {
26
27
  outputReferences?: OutputReferences;
27
28
  outputReferenceFallbacks?: boolean;
28
29
  formatting?: FormattingOverrides;
30
+ sort?: SortOption;
29
31
  [key: string]: any;
30
32
  }
31
33
  export interface GetReferencesOptions {
@@ -60,3 +60,18 @@ export interface Dictionary {
60
60
  unfilteredAllTokens?: TransformedToken[];
61
61
  unfilteredTokenMap?: Map<string, TransformedToken>;
62
62
  }
63
+ /**
64
+ * DTCG v2025.10 color spaces
65
+ * @see https://tr.designtokens.org/format/#color
66
+ */
67
+ export type DTCGColorSpace = 'srgb' | 'srgb-linear' | 'display-p3' | 'a98-rgb' | 'prophoto-rgb' | 'rec2020' | 'xyz-d50' | 'xyz-d65' | 'lab' | 'lch' | 'oklab' | 'oklch' | 'hsl' | 'hwb';
68
+ /**
69
+ * DTCG v2025.10 color value format
70
+ * @see https://tr.designtokens.org/format/#color
71
+ */
72
+ export interface DTCGColorValue {
73
+ colorSpace: DTCGColorSpace;
74
+ components: (number | 'none')[];
75
+ alpha?: number | 'none';
76
+ hex?: string;
77
+ }
@@ -0,0 +1,17 @@
1
+ import type { TransformedToken } from './DesignToken.js';
2
+ import { builtInSorts } from '../lib/enums/sorts.js';
3
+ export type BuiltInSorts = typeof builtInSorts;
4
+ export interface Sort {
5
+ name: string;
6
+ sort: SortFn;
7
+ }
8
+ /**
9
+ * A single sort function - either a built-in sort referenced by name string or a custom comparator function
10
+ * for inline usage
11
+ */
12
+ export type SortFn = string | ((a: TransformedToken, b: TransformedToken) => number);
13
+ /**
14
+ * Sort option for formattedVariables - can be a single sort item or an array of sort items
15
+ * (for chaining multiple sorts as tie-breakers)
16
+ */
17
+ export type SortOption = SortFn | SortFn[];
package/types/index.d.ts CHANGED
@@ -4,6 +4,7 @@ export type { DesignToken, DesignTokens, PreprocessedTokens, TransformedToken, T
4
4
  export type { FileHeader, File, FormattingOptions } from './File.js';
5
5
  export type { Filter } from './Filter.js';
6
6
  export type { Format, FormatFnArguments, FormatFn, OutputReferences } from './Format.js';
7
+ export type { SortOption, SortFn, BuiltInSorts } from './Sort.js';
7
8
  export type { Parser, ParserOptions } from './Parser.js';
8
9
  export type { Preprocessor } from './Preprocessor.js';
9
10
  export type { Transform, NameTransform, AttributeTransform, ValueTransform } from './Transform.js';