style-dictionary 4.1.2 → 4.1.4

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 (36) 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 +1 -1
  8. package/examples/advanced/matching-build-files/package.json +1 -1
  9. package/examples/advanced/multi-brand-multi-platform/package.json +1 -1
  10. package/examples/advanced/node-modules-as-config-and-properties/package.json +1 -1
  11. package/examples/advanced/npm-module/package.json +1 -1
  12. package/examples/advanced/referencing_aliasing/package.json +1 -1
  13. package/examples/advanced/s3/package.json +1 -1
  14. package/examples/advanced/tokens-deprecation/package.json +1 -1
  15. package/examples/advanced/transitive-transforms/package.json +1 -1
  16. package/examples/advanced/variables-in-outputs/package.json +1 -1
  17. package/examples/advanced/yaml-tokens/package.json +1 -1
  18. package/lib/StyleDictionary.js +4 -2
  19. package/lib/common/formatHelpers/fileHeader.js +1 -1
  20. package/lib/common/formatHelpers/formattedVariables.js +1 -1
  21. package/lib/common/formatHelpers/sortByReference.d.ts +3 -6
  22. package/lib/common/formatHelpers/sortByReference.js +49 -45
  23. package/lib/common/formats.js +4 -4
  24. package/lib/common/transformGroups.js +2 -2
  25. package/lib/filterTokens.js +17 -15
  26. package/lib/resolve.js +2 -1
  27. package/lib/utils/combineJSON.js +3 -2
  28. package/lib/utils/convertToBase64.d.ts +3 -3
  29. package/lib/utils/convertToBase64.js +31 -8
  30. package/lib/utils/isNode.d.ts +1 -0
  31. package/lib/utils/isNode.js +1 -0
  32. package/lib/utils/preprocess.d.ts +4 -2
  33. package/lib/utils/preprocess.js +2 -1
  34. package/package.json +2 -1
  35. package/types/File.d.ts +1 -1
  36. package/types/Preprocessor.d.ts +2 -2
@@ -12,6 +12,6 @@
12
12
  "author": "",
13
13
  "license": "Apache-2.0",
14
14
  "devDependencies": {
15
- "style-dictionary": "^4.1.2"
15
+ "style-dictionary": "^4.1.4"
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.1.2"
15
+ "style-dictionary": "^4.1.4"
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.1.2"
32
+ "style-dictionary": "^4.1.4"
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.1.2"
13
+ "style-dictionary": "^4.1.4"
14
14
  }
15
15
  }
@@ -16,6 +16,6 @@
16
16
  "author": "",
17
17
  "license": "Apache-2.0",
18
18
  "devDependencies": {
19
- "style-dictionary": "^4.1.2"
19
+ "style-dictionary": "^4.1.4"
20
20
  }
21
21
  }
@@ -9,6 +9,6 @@
9
9
  },
10
10
  "license": "Apache-2.0",
11
11
  "devDependencies": {
12
- "style-dictionary": "^4.1.2"
12
+ "style-dictionary": "^4.1.4"
13
13
  }
14
14
  }
@@ -10,6 +10,6 @@
10
10
  "author": "",
11
11
  "license": "Apache-2.0",
12
12
  "devDependencies": {
13
- "style-dictionary": "^4.1.2"
13
+ "style-dictionary": "^4.1.4"
14
14
  }
15
15
  }
@@ -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.1.2"
20
+ "style-dictionary": "^4.1.4"
21
21
  }
22
22
  }
@@ -16,6 +16,6 @@
16
16
  "author": "",
17
17
  "license": "Apache-2.0",
18
18
  "devDependencies": {
19
- "style-dictionary": "^4.1.2"
19
+ "style-dictionary": "^4.1.4"
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.1.2",
23
+ "style-dictionary": "^4.1.4",
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.1.2"
20
+ "style-dictionary": "^4.1.4"
21
21
  }
22
22
  }
@@ -16,6 +16,6 @@
16
16
  "author": "",
17
17
  "license": "Apache-2.0",
18
18
  "devDependencies": {
19
- "style-dictionary": "^4.1.2"
19
+ "style-dictionary": "^4.1.4"
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.1.2"
19
+ "style-dictionary": "^4.1.4"
20
20
  }
21
21
  }
@@ -16,6 +16,6 @@
16
16
  "author": "",
17
17
  "license": "Apache-2.0",
18
18
  "devDependencies": {
19
- "style-dictionary": "^4.1.2"
19
+ "style-dictionary": "^4.1.4"
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": "^4.1.2"
15
+ "style-dictionary": "^4.1.4"
16
16
  }
17
17
  }
@@ -11,6 +11,6 @@
11
11
  "author": "",
12
12
  "license": "MIT",
13
13
  "devDependencies": {
14
- "style-dictionary": "^4.1.2"
14
+ "style-dictionary": "^4.1.4"
15
15
  }
16
16
  }
@@ -10,7 +10,7 @@
10
10
  "author": "",
11
11
  "license": "Apache-2.0",
12
12
  "devDependencies": {
13
- "style-dictionary": "^4.1.2",
13
+ "style-dictionary": "^4.1.4",
14
14
  "yaml": "^1.10.0"
15
15
  }
16
16
  }
@@ -39,6 +39,7 @@ import filterTokens from './filterTokens.js';
39
39
  import cleanFiles from './cleanFiles.js';
40
40
  import cleanDirs from './cleanDirs.js';
41
41
  import cleanActions from './cleanActions.js';
42
+ import { isNode } from './utils/isNode.js';
42
43
 
43
44
  /**
44
45
  * @typedef {import('../types/Volume.ts').Volume} Volume
@@ -78,7 +79,7 @@ export default class StyleDictionary extends Register {
78
79
  // Placeholder is transformed on prepublish -> see scripts/inject-version.js
79
80
  // 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
81
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#browser_compatibility
81
- static VERSION = '4.1.2';
82
+ static VERSION = '4.1.4';
82
83
 
83
84
  /** @returns {Config} */
84
85
  get options() {
@@ -227,7 +228,7 @@ export default class StyleDictionary extends Register {
227
228
  );
228
229
  } else {
229
230
  let _filePath = cfgFilePath;
230
- if (typeof window !== 'object' && process?.platform === 'win32') {
231
+ if (isNode && process?.platform === 'win32') {
231
232
  // Windows FS compatibility. If in browser, we use an FS shim which doesn't require this Windows workaround
232
233
  _filePath = new URL(`file:///${_filePath}`).href;
233
234
  }
@@ -442,6 +443,7 @@ export default class StyleDictionary extends Register {
442
443
  platformProcessedTokens,
443
444
  platformConfig.preprocessors,
444
445
  this.hooks.preprocessors,
446
+ platformConfig,
445
447
  );
446
448
  if (this.shouldRunExpansion(platformConfig.expand)) {
447
449
  platformProcessedTokens = expandTokens(platformProcessedTokens, this.options, platformConfig);
@@ -67,7 +67,7 @@ export default async function fileHeader({ file, commentStyle, formatting = {},
67
67
  /**
68
68
  * @type {FileHeader}
69
69
  */
70
- let fn = (arr) => arr;
70
+ let fn = (arr) => arr ?? [];
71
71
  if (file?.options?.fileHeader && typeof file?.options?.fileHeader !== 'string') {
72
72
  fn = file.options.fileHeader;
73
73
  }
@@ -80,7 +80,7 @@ export default function formattedVariables({
80
80
  // note: using the spread operator here so we get a new array rather than
81
81
  // mutating the original
82
82
  allTokens = [...allTokens].sort(
83
- sortByReference(tokens, { unfilteredTokens: dictionary.unfilteredTokens }),
83
+ sortByReference(tokens, { unfilteredTokens: dictionary.unfilteredTokens, usesDtcg }),
84
84
  );
85
85
  }
86
86
 
@@ -1,7 +1,3 @@
1
- /**
2
- * @typedef {import('../../../types/DesignToken.ts').TransformedTokens} Tokens
3
- * @typedef {import('../../../types/DesignToken.ts').TransformedToken} Token
4
- */
5
1
  /**
6
2
  * A function that returns a sorting function to be used with Array.sort that
7
3
  * will sort the allTokens array based on references. This is to make sure
@@ -14,11 +10,12 @@
14
10
  * dictionary.allTokens.sort(sortByReference(dictionary))
15
11
  * ```
16
12
  * @param {Tokens} tokens
17
- * @param {{unfilteredTokens?: Tokens}} [opts]
13
+ * @param {{unfilteredTokens?: Tokens, usesDtcg?: boolean}} [opts]
18
14
  * @returns {(a: Token, b: Token) => number}
19
15
  */
20
- export default function sortByReference(tokens: Tokens, opts?: {
16
+ export default function sortByReference(tokens: Tokens, { unfilteredTokens, usesDtcg }?: {
21
17
  unfilteredTokens?: Tokens;
18
+ usesDtcg?: boolean;
22
19
  } | undefined): (a: Token, b: Token) => number;
23
20
  export type Tokens = import("../../../types/DesignToken.ts").TransformedTokens;
24
21
  export type Token = import("../../../types/DesignToken.ts").TransformedToken;
@@ -19,6 +19,9 @@ import { getReferences } from '../../utils/references/getReferences.js';
19
19
  * @typedef {import('../../../types/DesignToken.ts').TransformedToken} Token
20
20
  */
21
21
 
22
+ const A_COMES_FIRST = -1;
23
+ const B_COMES_FIRST = 1;
24
+
22
25
  /**
23
26
  * A function that returns a sorting function to be used with Array.sort that
24
27
  * will sort the allTokens array based on references. This is to make sure
@@ -31,66 +34,67 @@ import { getReferences } from '../../utils/references/getReferences.js';
31
34
  * dictionary.allTokens.sort(sortByReference(dictionary))
32
35
  * ```
33
36
  * @param {Tokens} tokens
34
- * @param {{unfilteredTokens?: Tokens}} [opts]
37
+ * @param {{unfilteredTokens?: Tokens, usesDtcg?: boolean}} [opts]
35
38
  * @returns {(a: Token, b: Token) => number}
36
39
  */
37
- export default function sortByReference(tokens, opts) {
40
+ export default function sortByReference(tokens, { unfilteredTokens, usesDtcg } = {}) {
41
+ const valueKey = usesDtcg ? '$value' : 'value';
42
+
38
43
  /**
39
44
  * The sorter function is recursive to account for multiple levels of nesting
40
45
  * @param {Token} a
41
46
  * @param {Token} b
42
- * @returns
47
+ * @returns {number}
43
48
  */
44
49
  function sorter(a, b) {
45
- const aComesFirst = -1;
46
- const bComesFirst = 1;
47
-
48
- // return early if a or b ar undefined
49
50
  if (typeof a === 'undefined') {
50
- return aComesFirst;
51
- } else if (typeof b === 'undefined') {
52
- return bComesFirst;
51
+ return A_COMES_FIRST;
52
+ }
53
+ if (typeof b === 'undefined') {
54
+ return B_COMES_FIRST;
53
55
  }
54
56
 
55
- // If token a uses a reference and token b doesn't, b might come before a
56
- // read on..
57
- if (a.original && usesReferences(a.original.value)) {
58
- // Both a and b have references, we need to see if they reference each other
59
- if (b.original && usesReferences(b.original.value)) {
60
- const aRefs = getReferences(a.original.value, tokens, {
61
- unfilteredTokens: opts?.unfilteredTokens,
62
- warnImmediately: false,
63
- });
64
- const bRefs = getReferences(b.original.value, tokens, {
65
- unfilteredTokens: opts?.unfilteredTokens,
66
- warnImmediately: false,
67
- });
68
-
69
- aRefs.forEach((aRef) => {
70
- // a references b, we want b to come first
71
- if (aRef.name === b.name) {
72
- return bComesFirst;
73
- }
74
- });
57
+ const aUsesRefs = a.original && usesReferences(a.original[valueKey]);
58
+ const bUsesRefs = b.original && usesReferences(b.original[valueKey]);
75
59
 
76
- bRefs.forEach((bRef) => {
77
- // ditto but opposite
78
- if (bRef.name === a.name) {
79
- return aComesFirst;
80
- }
81
- });
60
+ // -----BOTH REFERENCE-----
61
+ if (aUsesRefs && bUsesRefs) {
62
+ // Collect references for 'a' and 'b'
63
+ const aRefs = getReferences(a.original[valueKey], tokens, {
64
+ unfilteredTokens,
65
+ warnImmediately: false,
66
+ });
67
+ const bRefs = getReferences(b.original[valueKey], tokens, {
68
+ unfilteredTokens,
69
+ warnImmediately: false,
70
+ });
82
71
 
83
- // both a and b have references and don't reference each other
84
- // we go further down the rabbit hole (reference chain)
85
- return sorter(aRefs[0], bRefs[0]);
86
- } else {
87
- // a has a reference and b does not:
88
- return bComesFirst;
72
+ // 'a' references 'b' -> 'b' should come first
73
+ if (aRefs.some((aRef) => aRef.name === b.name)) {
74
+ return B_COMES_FIRST;
75
+ }
76
+ // 'b' references 'a' -> 'a' should come first
77
+ if (bRefs.some((bRef) => bRef.name === a.name)) {
78
+ return A_COMES_FIRST;
89
79
  }
90
- // a does not have a reference it should come first regardless if b has one
91
- } else {
92
- return aComesFirst;
80
+
81
+ // 'a' and 'b' reference, but not each other. Recurse to next level
82
+ return sorter(aRefs[0], bRefs[0]);
83
+ }
84
+
85
+ // ----- ONLY ONE REFERENCES -----
86
+ // 'a' references, 'b' doesn't -> 'b' should come first
87
+ if (aUsesRefs) {
88
+ return B_COMES_FIRST;
93
89
  }
90
+
91
+ // 'b' references, 'a' doesn't -> 'a' should come first
92
+ if (bUsesRefs) {
93
+ return A_COMES_FIRST;
94
+ }
95
+
96
+ // no references, keep existing order
97
+ return 0;
94
98
  }
95
99
 
96
100
  return sorter;
@@ -1190,7 +1190,7 @@ declare const ${moduleName}: ${JSON.stringify(treeWalker(dictionary.tokens), nul
1190
1190
 
1191
1191
  let sortedTokens;
1192
1192
  if (outputReferences) {
1193
- sortedTokens = [...allTokens].sort(sortByReference(tokens, { unfilteredTokens }));
1193
+ sortedTokens = [...allTokens].sort(sortByReference(tokens, { unfilteredTokens, usesDtcg }));
1194
1194
  } else {
1195
1195
  sortedTokens = [...allTokens].sort(sortByName);
1196
1196
  }
@@ -1238,7 +1238,7 @@ declare const ${moduleName}: ${JSON.stringify(treeWalker(dictionary.tokens), nul
1238
1238
 
1239
1239
  let sortedTokens;
1240
1240
  if (outputReferences) {
1241
- sortedTokens = [...allTokens].sort(sortByReference(tokens, { unfilteredTokens }));
1241
+ sortedTokens = [...allTokens].sort(sortByReference(tokens, { unfilteredTokens, usesDtcg }));
1242
1242
  } else {
1243
1243
  sortedTokens = [...allTokens].sort(sortByName);
1244
1244
  }
@@ -1297,7 +1297,7 @@ declare const ${moduleName}: ${JSON.stringify(treeWalker(dictionary.tokens), nul
1297
1297
 
1298
1298
  let sortedTokens;
1299
1299
  if (outputReferences) {
1300
- sortedTokens = [...allTokens].sort(sortByReference(tokens, { unfilteredTokens }));
1300
+ sortedTokens = [...allTokens].sort(sortByReference(tokens, { unfilteredTokens, usesDtcg }));
1301
1301
  } else {
1302
1302
  sortedTokens = [...allTokens].sort(sortByName);
1303
1303
  }
@@ -1520,7 +1520,7 @@ declare const ${moduleName}: ${JSON.stringify(treeWalker(dictionary.tokens), nul
1520
1520
 
1521
1521
  let sortedTokens;
1522
1522
  if (outputReferences) {
1523
- sortedTokens = [...allTokens].sort(sortByReference(tokens, { unfilteredTokens }));
1523
+ sortedTokens = [...allTokens].sort(sortByReference(tokens, { unfilteredTokens, usesDtcg }));
1524
1524
  } else {
1525
1525
  sortedTokens = [...allTokens].sort(sortByName);
1526
1526
  }
@@ -275,7 +275,7 @@ export default {
275
275
  * [attribute/cti](/reference/hooks/transforms/predefined#attributecti)
276
276
  * [name/camel](/reference/hooks/transforms/predefined#nameccamel)
277
277
  * [color/hex8flutter](/reference/hooks/transforms/predefined#colorhex8flutter)
278
- * [size/flutter/remToDouble](/reference/hooks/transforms/predefined#sizeflutterremToDouble)
278
+ * [size/flutter/remToDouble](/reference/hooks/transforms/predefined#sizeflutterremtodouble)
279
279
  * [content/flutter/literal](/reference/hooks/transforms/predefined#contentflutterliteral)
280
280
  * [asset/flutter/literal](/reference/hooks/transforms/predefined#assetflutterliteral)
281
281
  *
@@ -295,7 +295,7 @@ export default {
295
295
  * [attribute/cti](/reference/hooks/transforms/predefined#attributecti)
296
296
  * [name/camel](/reference/hooks/transforms/predefined#namecamel)
297
297
  * [color/hex8flutter](/reference/hooks/transforms/predefined#colorhex8flutter)
298
- * [size/flutter/remToDouble](/reference/hooks/transforms/predefined#sizeflutterremToDouble)
298
+ * [size/flutter/remToDouble](/reference/hooks/transforms/predefined#sizeflutterremtodouble)
299
299
  * [content/flutter/literal](/reference/hooks/transforms/predefined#contentflutterliteral)
300
300
  * [asset/flutter/literal](/reference/hooks/transforms/predefined#assetflutterliteral)
301
301
  *
@@ -48,25 +48,27 @@ async function filterTokenObject(tokens, filter, options) {
48
48
  // out
49
49
  const result = await Object.entries(tokens ?? []).reduce(async (_acc, [key, token]) => {
50
50
  const acc = await _acc;
51
- const tokenValue = options.usesDtcg ? token.$value : token.value;
52
51
  // If the token is not an object, we don't know what it is. We return it as-is.
53
52
  if (!isPlainObject(token)) {
54
53
  return acc;
55
- // If the token has a `value` member we know it's a property, pass it to
56
- // the filter function and either include it in the final `acc` object or
57
- // exclude it (by returning the `acc` object without it added).
58
- } else if (typeof tokenValue !== 'undefined') {
59
- const filtered = await asyncFilter(/** @type {Token[]} */ ([token]), filter, options);
60
- return filtered.length === 0 ? acc : { ...acc, [key]: token };
61
- // If we got here we have an object that is not a property. We'll assume
62
- // it's an object containing multiple tokens and recursively filter it
63
- // using the `filterTokenObject` function.
64
54
  } else {
65
- const filtered = await filterTokenObject(token, filter, options);
66
- // If the filtered object is not empty then add it to the final `acc`
67
- // object. If it is empty then every property inside of it was filtered
68
- // out, then exclude it entirely from the final `acc` object.
69
- return Object.entries(filtered || {}).length < 1 ? acc : { ...acc, [key]: filtered };
55
+ const tokenValue = options.usesDtcg ? token.$value : token.value;
56
+ if (typeof tokenValue === 'undefined') {
57
+ // If we got here we have an object that is not a token. We'll assume
58
+ // it's token group containing multiple tokens and recursively filter it
59
+ // using the `filterTokenObject` function.
60
+ const filtered = await filterTokenObject(token, filter, options);
61
+ // If the filtered object is not empty then add it to the final `acc`
62
+ // object. If it is empty then every token inside of it was filtered
63
+ // out, then exclude it entirely from the final `acc` object.
64
+ return Object.entries(filtered || {}).length < 1 ? acc : { ...acc, [key]: filtered };
65
+ } else {
66
+ // If the token has a `value` member we know it's a token, pass it to
67
+ // the filter function and either include it in the final `acc` object or
68
+ // exclude it (by returning the `acc` object without it added).
69
+ const filtered = await asyncFilter(/** @type {Token[]} */ ([token]), filter, options);
70
+ return filtered.length === 0 ? acc : { ...acc, [key]: token };
71
+ }
70
72
  }
71
73
  }, {});
72
74
  return result;
package/lib/resolve.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { posix, win32 } from 'path-unified';
2
+ import { isNode } from './utils/isNode.js';
2
3
 
3
4
  /**
4
5
  * If we're on Windows AND we're not in browser context, use win32 resolve (with \'s)
@@ -11,7 +12,7 @@ export const resolve = (path, customVolumeUsed = false) => {
11
12
  if (customVolumeUsed) {
12
13
  return path;
13
14
  }
14
- if (process?.platform === 'win32' && typeof window !== 'object') {
15
+ if (isNode && process?.platform === 'win32') {
15
16
  return win32.resolve(path);
16
17
  }
17
18
  return posix.resolve(path);
@@ -18,6 +18,7 @@ import { fs } from 'style-dictionary/fs';
18
18
  import { resolve } from '../resolve.js';
19
19
  import deepExtend from './deepExtend.js';
20
20
  import { detectDtcgSyntax } from './detectDtcgSyntax.js';
21
+ import { isNode } from './isNode.js';
21
22
 
22
23
  /**
23
24
  * @typedef {import('../../types/Volume.ts').Volume} Volume
@@ -76,7 +77,7 @@ export default async function combineJSON(
76
77
  files = files.concat(new_files);
77
78
  }
78
79
 
79
- if (typeof window === 'object') {
80
+ if (!isNode) {
80
81
  // adjust for browser env glob results have leading slash
81
82
  // make sure we dont remove these in Node, that would break absolute paths!!
82
83
  files = files.map((f) => f.replace(/^\//, ''));
@@ -101,7 +102,7 @@ export default async function combineJSON(
101
102
  if (['.js', '.mjs'].includes(extname(filePath))) {
102
103
  let resolvedPath = resolve(filePath, vol?.__custom_fs__);
103
104
  // eslint-disable-next-line no-undef
104
- if (typeof window !== 'object' && process?.platform === 'win32') {
105
+ if (isNode && process?.platform === 'win32') {
105
106
  // Windows FS compatibility. If in browser, we use an FS shim which doesn't require this Windows workaround
106
107
  resolvedPath = new URL(`file:///${resolvedPath}`).href;
107
108
  }
@@ -2,11 +2,11 @@
2
2
  * @typedef {import('../../types/Volume.ts').Volume} Volume
3
3
  * Takes a file and converts it to a base64 string.
4
4
  * @private
5
- * @param {String} filePath - Path to the file you want base64'd
5
+ * @param {string} filePath - Path to the file you want base64'd
6
6
  * @param {Volume} [vol]
7
- * @returns {String}
7
+ * @returns {Promise<string>}
8
8
  */
9
- export default function convertToBase64(filePath: string, vol?: import("../../types/Volume.ts").Volume | undefined): string;
9
+ export default function convertToBase64(filePath: string, vol?: import("../../types/Volume.ts").Volume | undefined): Promise<string>;
10
10
  /**
11
11
  * Takes a file and converts it to a base64 string.
12
12
  */
@@ -13,20 +13,43 @@
13
13
 
14
14
  import { fs } from 'style-dictionary/fs';
15
15
  import { resolve } from '../resolve.js';
16
+ import { isNode } from './isNode.js';
17
+
18
+ /**
19
+ * @param {Buffer} buffer
20
+ * @returns {string|Promise<string>}
21
+ */
22
+ function toBase64(buffer) {
23
+ if (isNode) {
24
+ // Node.js environment
25
+ return buffer.toString('base64');
26
+ } else {
27
+ // Browser environment
28
+ return new Promise((resolve, reject) => {
29
+ const blob = new Blob([buffer], { type: 'application/octet-stream' });
30
+ const reader = new FileReader();
31
+ reader.onloadend = () => {
32
+ const base64String = /** @type {string } */ (reader.result).split(',')[1];
33
+ resolve(base64String);
34
+ };
35
+ reader.onerror = reject;
36
+ reader.readAsDataURL(blob);
37
+ });
38
+ }
39
+ }
16
40
 
17
41
  /**
18
42
  * @typedef {import('../../types/Volume.ts').Volume} Volume
19
43
  * Takes a file and converts it to a base64 string.
20
44
  * @private
21
- * @param {String} filePath - Path to the file you want base64'd
45
+ * @param {string} filePath - Path to the file you want base64'd
22
46
  * @param {Volume} [vol]
23
- * @returns {String}
47
+ * @returns {Promise<string>}
24
48
  */
25
- export default function convertToBase64(filePath, vol = fs) {
49
+ export default async function convertToBase64(filePath, vol = fs) {
26
50
  if (typeof filePath !== 'string') throw new Error('Token filePath name must be a string');
27
-
28
- const body = /** @type {string} */ (
29
- vol.readFileSync(resolve(filePath, vol.__custom_fs__), 'utf-8')
30
- );
31
- return btoa(body);
51
+ // typecast to Buffer because we know that without specifying encoding, this returns a Buffer
52
+ // @ts-expect-error requires encoding options, this is a mistake in memfs types definition
53
+ const body = /** @type {Buffer} */ (vol.readFileSync(resolve(filePath, vol.__custom_fs__)));
54
+ return toBase64(body);
32
55
  }
@@ -0,0 +1 @@
1
+ export const isNode: boolean;
@@ -0,0 +1 @@
1
+ export const isNode = typeof window === 'undefined';
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * @typedef {import('../../types/DesignToken.ts').PreprocessedTokens} PreprocessedTokens
3
3
  * @typedef {import('../../types/Config.ts').Config} Config
4
+ * @typedef {import('../../types/Config.ts').PlatformConfig} PlatformConfig
4
5
  * @typedef {import('../../types/Preprocessor.ts').Preprocessor} Preprocessor
5
6
  */
6
7
  /**
@@ -10,10 +11,11 @@
10
11
  * @param {PreprocessedTokens} tokens
11
12
  * @param {string[]} [appliedPreprocessors]
12
13
  * @param {Record<string, Preprocessor['preprocessor']>} [preprocessorObj]
13
- * @param {Config} [options]
14
+ * @param {Config|PlatformConfig} [options]
14
15
  * @returns {Promise<PreprocessedTokens>}
15
16
  */
16
- export function preprocess(tokens: PreprocessedTokens, appliedPreprocessors?: string[] | undefined, preprocessorObj?: Record<string, (dictionary: import("../../types/DesignToken.ts").PreprocessedTokens, options: import("../../types/Config.ts").Config) => import("../../types/DesignToken.ts").PreprocessedTokens | Promise<import("../../types/DesignToken.ts").PreprocessedTokens>> | undefined, options?: import("../../types/Config.ts").Config | undefined): Promise<PreprocessedTokens>;
17
+ export function preprocess(tokens: PreprocessedTokens, appliedPreprocessors?: string[] | undefined, preprocessorObj?: Record<string, (dictionary: import("../../types/DesignToken.ts").PreprocessedTokens, options: import("../../types/Config.ts").Config | import("../../types/Config.ts").PlatformConfig) => import("../../types/DesignToken.ts").PreprocessedTokens | Promise<import("../../types/DesignToken.ts").PreprocessedTokens>> | undefined, options?: import("../../types/Config.ts").Config | import("../../types/Config.ts").PlatformConfig | undefined): Promise<PreprocessedTokens>;
17
18
  export type PreprocessedTokens = import("../../types/DesignToken.ts").PreprocessedTokens;
18
19
  export type Config = import("../../types/Config.ts").Config;
20
+ export type PlatformConfig = import("../../types/Config.ts").PlatformConfig;
19
21
  export type Preprocessor = import("../../types/Preprocessor.ts").Preprocessor;
@@ -14,6 +14,7 @@
14
14
  /**
15
15
  * @typedef {import('../../types/DesignToken.ts').PreprocessedTokens} PreprocessedTokens
16
16
  * @typedef {import('../../types/Config.ts').Config} Config
17
+ * @typedef {import('../../types/Config.ts').PlatformConfig} PlatformConfig
17
18
  * @typedef {import('../../types/Preprocessor.ts').Preprocessor} Preprocessor
18
19
  */
19
20
 
@@ -24,7 +25,7 @@
24
25
  * @param {PreprocessedTokens} tokens
25
26
  * @param {string[]} [appliedPreprocessors]
26
27
  * @param {Record<string, Preprocessor['preprocessor']>} [preprocessorObj]
27
- * @param {Config} [options]
28
+ * @param {Config|PlatformConfig} [options]
28
29
  * @returns {Promise<PreprocessedTokens>}
29
30
  */
30
31
  export async function preprocess(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "style-dictionary",
3
- "version": "4.1.2",
3
+ "version": "4.1.4",
4
4
  "description": "Style once, use everywhere. A build system for creating cross-platform styles.",
5
5
  "keywords": [
6
6
  "style dictionary",
@@ -156,6 +156,7 @@
156
156
  "prettier": "^3.0.3",
157
157
  "sass": "^1.69.5",
158
158
  "sharp": "^0.32.5",
159
+ "starlight-links-validator": "^0.12.1",
159
160
  "stylus": "^0.56.0",
160
161
  "typescript": "^5.3.3",
161
162
  "unist-util-visit": "^5.0.0",
package/types/File.d.ts CHANGED
@@ -16,7 +16,7 @@ export interface FormattingOverrides {
16
16
  footer?: string;
17
17
  fileHeaderTimestamp?: boolean;
18
18
  }
19
- export type FileHeader = (defaultMessage: string[], options?: Config) => Promise<string[]> | string[];
19
+ export type FileHeader = (defaultMessage?: string[], options?: Config) => Promise<string[]> | string[];
20
20
  export interface File {
21
21
  destination?: string;
22
22
  format?: string | FormatFn;
@@ -1,6 +1,6 @@
1
1
  import type { PreprocessedTokens } from './DesignToken.ts';
2
- import type { Config } from './Config.ts';
2
+ import type { Config, PlatformConfig } from './Config.ts';
3
3
  export type Preprocessor = {
4
4
  name: string;
5
- preprocessor: (dictionary: PreprocessedTokens, options: Config) => PreprocessedTokens | Promise<PreprocessedTokens>;
5
+ preprocessor: (dictionary: PreprocessedTokens, options: Config | PlatformConfig) => PreprocessedTokens | Promise<PreprocessedTokens>;
6
6
  };