style-dictionary 3.0.0 → 3.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 (54) hide show
  1. package/README.md +3 -0
  2. package/bin/style-dictionary +2 -2
  3. package/examples/advanced/assets-base64-embed/package.json +1 -1
  4. package/examples/advanced/auto-rebuild-watcher/package.json +2 -2
  5. package/examples/advanced/component-cti/package.json +1 -1
  6. package/examples/advanced/create-react-app/package.json +3 -3
  7. package/examples/advanced/create-react-native-app/package.json +1 -1
  8. package/examples/advanced/custom-file-header/package.json +1 -1
  9. package/examples/advanced/custom-formats-with-templates/package.json +1 -1
  10. package/examples/advanced/custom-parser/package.json +1 -1
  11. package/examples/advanced/custom-transforms/build.js +1 -1
  12. package/examples/advanced/custom-transforms/package.json +1 -1
  13. package/examples/advanced/format-helpers/package.json +1 -1
  14. package/examples/advanced/format-helpers/sd.config.js +1 -1
  15. package/examples/advanced/matching-build-files/config.js +1 -1
  16. package/examples/advanced/matching-build-files/package.json +1 -1
  17. package/examples/advanced/multi-brand-multi-platform/package.json +1 -1
  18. package/examples/advanced/node-modules-as-config-and-properties/config.js +1 -1
  19. package/examples/advanced/node-modules-as-config-and-properties/package.json +1 -1
  20. package/examples/advanced/npm-module/package.json +1 -1
  21. package/examples/advanced/referencing_aliasing/package.json +1 -1
  22. package/examples/advanced/s3/package.json +1 -1
  23. package/examples/advanced/tokens-deprecation/package.json +1 -1
  24. package/examples/advanced/transitive-transforms/package.json +1 -1
  25. package/examples/advanced/variables-in-outputs/README.md +9 -5
  26. package/examples/advanced/variables-in-outputs/package.json +1 -1
  27. package/examples/advanced/variables-in-outputs/sd.config.js +8 -4
  28. package/examples/advanced/yaml-tokens/package.json +1 -1
  29. package/lib/common/formatHelpers/createPropertyFormatter.js +5 -3
  30. package/lib/common/formatHelpers/fileHeader.js +1 -1
  31. package/lib/common/formatHelpers/formattedVariables.js +4 -3
  32. package/lib/common/formatHelpers/getTypeScriptType.js +77 -0
  33. package/lib/common/formatHelpers/index.js +2 -1
  34. package/lib/common/formats.js +24 -12
  35. package/lib/common/templates/scss/map-deep.template +1 -15
  36. package/lib/common/transforms.js +25 -2
  37. package/lib/extend.js +1 -0
  38. package/lib/utils/combineJSON.js +1 -0
  39. package/lib/utils/createFormatArgs.js +5 -1
  40. package/lib/utils/es6_.js +6 -1
  41. package/lib/utils/jsonc.js +14 -0
  42. package/lib/utils/references/getReferences.js +1 -1
  43. package/lib/utils/resolveObject.js +11 -0
  44. package/package.json +4 -2
  45. package/types/Config.d.ts +2 -2
  46. package/types/File.d.ts +2 -1
  47. package/types/FileHeader.d.ts +1 -1
  48. package/types/Format.d.ts +2 -1
  49. package/types/FormatHelpers.d.ts +1 -1
  50. package/types/Platform.d.ts +1 -0
  51. package/types/TransformGroup.d.ts +1 -2
  52. package/types/_helpers.ts +1 -3
  53. package/types/index.d.ts +25 -4
  54. package/types/index.test-d.ts +4 -0
package/README.md CHANGED
@@ -22,6 +22,9 @@ For detailed usage head to https://amzn.github.io/style-dictionary
22
22
  ## Watch the Demo on Youtube
23
23
  [![Watch the video](/docs/assets/fake_player.png)](http://youtu.be/1HREvonfqhY)
24
24
 
25
+ ## Experiment in the playground
26
+ Try the browser-based Style Dictionary playground: [https://www.style-dictionary-play.dev/](https://www.style-dictionary-play.dev/), built by the folks at [\<div\>RIOTS](https://divriots.com/).
27
+
25
28
  ## Contents
26
29
  * [Installation](#installation)
27
30
  * [Usage](#usage)
@@ -29,7 +29,7 @@ function getConfigPath(options) {
29
29
  process.exit(1);
30
30
  }
31
31
  }
32
-
32
+
33
33
  return configPath;
34
34
  }
35
35
 
@@ -72,7 +72,7 @@ program
72
72
 
73
73
  // error on unknown commands
74
74
  program.on('command:*', function () {
75
- console.error('Invalid command: %s\nSee --help for a list of available commands.', args.join(' '));
75
+ console.error('Invalid command: %s\nSee --help for a list of available commands.', process.argv.slice(2).join(' '));
76
76
  process.exit(1);
77
77
  });
78
78
 
@@ -11,6 +11,6 @@
11
11
  "author": "",
12
12
  "license": "Apache-2.0",
13
13
  "devDependencies": {
14
- "style-dictionary": "3.0.0"
14
+ "style-dictionary": "3.1.0"
15
15
  }
16
16
  }
@@ -10,13 +10,13 @@
10
10
  "scripts": {
11
11
  "build": "node_modules/.bin/style-dictionary build",
12
12
  "clean": "rm -rf build",
13
- "watch": "npm run build && chokidar \"properties/**/*.json\" -c \"npm run build\"",
13
+ "watch": "npm run build && chokidar \"tokens/**/*.json\" -c \"npm run build\"",
14
14
  "test": "echo \"Error: no test specified\" && exit 1"
15
15
  },
16
16
  "author": "",
17
17
  "license": "Apache-2.0",
18
18
  "devDependencies": {
19
19
  "chokidar-cli": "^1.2.0",
20
- "style-dictionary": "3.0.0"
20
+ "style-dictionary": "3.1.0"
21
21
  }
22
22
  }
@@ -15,6 +15,6 @@
15
15
  "author": "",
16
16
  "license": "Apache-2.0",
17
17
  "devDependencies": {
18
- "style-dictionary": "3.0.0"
18
+ "style-dictionary": "3.1.0"
19
19
  }
20
20
  }
@@ -3,14 +3,14 @@
3
3
  "description": "",
4
4
  "version": "1.0.0",
5
5
  "dependencies": {
6
- "node-sass": "^5.0.0",
6
+ "node-sass": "^6.0.1",
7
7
  "react": "^17.0.1",
8
8
  "react-dom": "^17.0.1",
9
9
  "react-scripts": "^4.0.3",
10
- "styled-components": "^5.2.1"
10
+ "styled-components": "^5.3.0"
11
11
  },
12
12
  "devDependencies": {
13
- "style-dictionary": "3.0.0"
13
+ "style-dictionary": "3.1.0"
14
14
  },
15
15
  "resolutions": {
16
16
  "immer": "8.0.1",
@@ -27,7 +27,7 @@
27
27
  "babel-jest": "~25.2.6",
28
28
  "jest": "~25.2.6",
29
29
  "react-test-renderer": "~16.13.1",
30
- "style-dictionary": "3.0.0"
30
+ "style-dictionary": "3.1.0"
31
31
  },
32
32
  "jest": {
33
33
  "preset": "react-native"
@@ -10,6 +10,6 @@
10
10
  "author": "",
11
11
  "license": "ISC",
12
12
  "devDependencies": {
13
- "style-dictionary": "3.0.0"
13
+ "style-dictionary": "3.1.0"
14
14
  }
15
15
  }
@@ -18,6 +18,6 @@
18
18
  "handlebars": "^4.7.7",
19
19
  "lodash": "^4.17.21",
20
20
  "pug": "^3.0.2",
21
- "style-dictionary": "3.0.0"
21
+ "style-dictionary": "3.1.0"
22
22
  }
23
23
  }
@@ -9,6 +9,6 @@
9
9
  "author": "",
10
10
  "license": "Apache-2.0",
11
11
  "devDependencies": {
12
- "style-dictionary": "3.0.0"
12
+ "style-dictionary": "3.1.0"
13
13
  }
14
14
  }
@@ -95,7 +95,7 @@ StyleDictionary.registerTransformGroup({
95
95
 
96
96
  StyleDictionary.registerFormat({
97
97
  name: 'custom/android/xml',
98
- formatter: function(dictionary) {
98
+ formatter: function({ dictionary }) {
99
99
  return dictionary.allTokens.map(function(token) {
100
100
  return `<item name="${token.name}">${token.value}</item>`;
101
101
  }).join('\n');
@@ -15,6 +15,6 @@
15
15
  "author": "",
16
16
  "license": "Apache-2.0",
17
17
  "devDependencies": {
18
- "style-dictionary": "3.0.0"
18
+ "style-dictionary": "3.1.0"
19
19
  }
20
20
  }
@@ -10,6 +10,6 @@
10
10
  "author": "",
11
11
  "license": "Apache-2.0",
12
12
  "devDependencies": {
13
- "style-dictionary": "3.0.0"
13
+ "style-dictionary": "3.1.0"
14
14
  }
15
15
  }
@@ -30,7 +30,7 @@ module.exports = {
30
30
  // proper style. If the file has a custom file header defined, or
31
31
  // showFileHeader option, it will honor those.
32
32
  return fileHeader({file, commentStyle: 'short'}) +
33
- dictionary.allProperties
33
+ dictionary.allTokens
34
34
  // sortByReference returns a function that can be used as to sort
35
35
  // an array. This will sort the array so that references always
36
36
  // come after their instantiation so that there are no errors
@@ -81,7 +81,7 @@ module.exports = {
81
81
 
82
82
  StyleDictionary.registerFormat({
83
83
  name: "custom/cjsmodule",
84
- formatter: function (dictionary) {
84
+ formatter: function({ dictionary }) {
85
85
  return `module.exports = {${dictionary.allTokens.map(
86
86
  (token) => `\n\t${token.name}: "${token.value}"`
87
87
  )}\n};`;
@@ -16,6 +16,6 @@
16
16
  "author": "Kelly Harrop <kn.harrop@gmail.com>",
17
17
  "license": "Apache-2.0",
18
18
  "devDependencies": {
19
- "style-dictionary": "3.0.0"
19
+ "style-dictionary": "3.1.0"
20
20
  }
21
21
  }
@@ -15,6 +15,6 @@
15
15
  "author": "",
16
16
  "license": "Apache-2.0",
17
17
  "devDependencies": {
18
- "style-dictionary": "3.0.0"
18
+ "style-dictionary": "3.1.0"
19
19
  }
20
20
  }
@@ -18,7 +18,7 @@ StyleDictionary.registerTransform({
18
18
 
19
19
  StyleDictionary.registerFormat({
20
20
  name: 'myRegisteredFormat',
21
- formatter: (dictionary) => {
21
+ formatter: ({ dictionary }) => {
22
22
  return dictionary.allTokens.map((token) => token.value).join('\n');
23
23
  }
24
24
  })
@@ -19,7 +19,7 @@
19
19
  },
20
20
  "homepage": "https://github.com/dbanksdesign/style-dictionary-node#readme",
21
21
  "devDependencies": {
22
- "style-dictionary": "3.0.0",
22
+ "style-dictionary": "3.1.0",
23
23
  "tinycolor2": "^1.4.1"
24
24
  }
25
25
  }
@@ -16,6 +16,6 @@
16
16
  "author": "",
17
17
  "license": "Apache-2.0",
18
18
  "devDependencies": {
19
- "style-dictionary": "3.0.0"
19
+ "style-dictionary": "3.1.0"
20
20
  }
21
21
  }
@@ -15,6 +15,6 @@
15
15
  "author": "",
16
16
  "license": "Apache-2.0",
17
17
  "devDependencies": {
18
- "style-dictionary": "3.0.0"
18
+ "style-dictionary": "3.1.0"
19
19
  }
20
20
  }
@@ -15,6 +15,6 @@
15
15
  "devDependencies": {
16
16
  "aws-sdk": "^2.7.21",
17
17
  "fs-extra": "^1.0.0",
18
- "style-dictionary": "3.0.0"
18
+ "style-dictionary": "3.1.0"
19
19
  }
20
20
  }
@@ -16,6 +16,6 @@
16
16
  "license": "Apache-2.0",
17
17
  "devDependencies": {
18
18
  "lodash": "^4.17.11",
19
- "style-dictionary": "3.0.0"
19
+ "style-dictionary": "3.1.0"
20
20
  }
21
21
  }
@@ -11,6 +11,6 @@
11
11
  "license": "ISC",
12
12
  "devDependencies": {
13
13
  "chroma-js": "^2.1.0",
14
- "style-dictionary": "3.0.0"
14
+ "style-dictionary": "3.1.0"
15
15
  }
16
16
  }
@@ -24,17 +24,21 @@ The `sd.config.js` file has everything you need to see. The tokens included in t
24
24
  Here is an example that shows how to get an alias's name within a custom format:
25
25
  ```javascript
26
26
  //...
27
- function(dictionary) {
27
+ function({ dictionary }) {
28
28
  return dictionary.allTokens.map(token => {
29
29
  let value = JSON.stringify(token.value);
30
30
  // the `dictionary` object now has `usesReference()` and
31
31
  // `getReferences()` methods. `usesReference()` will return true if
32
32
  // the value has a reference in it. `getReferences()` will return
33
- // an array of references to the whole tokens so that you can access its
34
- // name or any other attributes.
33
+ // an array of references to the whole tokens so that you can access their
34
+ // names or any other attributes.
35
35
  if (dictionary.usesReference(token.original.value)) {
36
- const reference = dictionary.getReferences(token.original.value);
37
- value = reference.name;
36
+ const refs = dictionary.getReferences(token.original.value);
37
+ refs.forEach(ref => {
38
+ value = value.replace(ref.value, function() {
39
+ return `${ref.name}`;
40
+ });
41
+ });
38
42
  }
39
43
  return `export const ${token.name} = ${value};`
40
44
  }).join(`\n`)
@@ -10,6 +10,6 @@
10
10
  "author": "",
11
11
  "license": "MIT",
12
12
  "devDependencies": {
13
- "style-dictionary": "3.0.0"
13
+ "style-dictionary": "3.1.0"
14
14
  }
15
15
  }
@@ -9,11 +9,15 @@ module.exports = {
9
9
  // the `dictionary` object now has `usesReference()` and
10
10
  // `getReferences()` methods. `usesReference()` will return true if
11
11
  // the value has a reference in it. `getReferences()` will return
12
- // an array of references to the whole tokens so that you can access its
13
- // name or any other attributes.
12
+ // an array of references to the whole tokens so that you can access
13
+ // their names or any other attributes.
14
14
  if (dictionary.usesReference(token.original.value)) {
15
- const reference = dictionary.getReferences(token.original.value);
16
- value = reference.name;
15
+ const refs = dictionary.getReferences(token.original.value);
16
+ refs.forEach(ref => {
17
+ value = value.replace(ref.value, function() {
18
+ return `${ref.name}`;
19
+ });
20
+ });
17
21
  }
18
22
  }
19
23
 
@@ -9,7 +9,7 @@
9
9
  "author": "",
10
10
  "license": "Apache-2.0",
11
11
  "devDependencies": {
12
- "style-dictionary": "3.0.0",
12
+ "style-dictionary": "3.1.0",
13
13
  "yaml": "^1.10.0"
14
14
  }
15
15
  }
@@ -45,9 +45,10 @@ const defaultFormatting = {
45
45
  * @param {Dictionary} options.dictionary - The dictionary object sent to the formatter function
46
46
  * @param {String} options.format - Available formats are: 'css', 'sass', 'less', and 'stylus'. If you want to customize the format and can't use one of those predefined formats, use the `formatting` option
47
47
  * @param {Object} options.formatting - Custom formatting properties that define parts of a declaration line in code. The configurable strings are: prefix, indentation, separator, suffix, and commentStyle. Those are used to generate a line like this: `${indentation}${prefix}${prop.name}${separator} ${prop.value}${suffix}`
48
+ * @param {Boolean} options.themeable [false] - Whether tokens should default to being themeable.
48
49
  * @returns {Function}
49
50
  */
50
- function createPropertyFormatter({outputReferences, dictionary, format, formatting={}}) {
51
+ function createPropertyFormatter({ outputReferences, dictionary, format, formatting = {}, themeable = false }) {
51
52
  let {prefix, commentStyle, indentation, separator, suffix} = Object.assign({}, defaultFormatting, formatting);
52
53
 
53
54
  switch(format) {
@@ -117,7 +118,8 @@ function createPropertyFormatter({outputReferences, dictionary, format, formatti
117
118
 
118
119
  to_ret_prop += prop.attributes.category === 'asset' ? `"${value}"` : value;
119
120
 
120
- if (format == 'sass' && prop.themeable === true) {
121
+ const themeable_prop = typeof prop.themeable === 'boolean' ? prop.themeable : themeable;
122
+ if (format === 'sass' && themeable_prop) {
121
123
  to_ret_prop += ' !default';
122
124
  }
123
125
 
@@ -135,4 +137,4 @@ function createPropertyFormatter({outputReferences, dictionary, format, formatti
135
137
  }
136
138
  }
137
139
 
138
- module.exports = createPropertyFormatter;
140
+ module.exports = createPropertyFormatter;
@@ -38,7 +38,7 @@ const defaultFormatting = {
38
38
  * StyleDictionary.registerFormat({
39
39
  * name: 'myCustomFormat',
40
40
  * formatter: function({ dictionary, file }) {
41
- * return fileHeader({file, 'short') +
41
+ * return fileHeader({file, commentStyle: 'short'}) +
42
42
  * dictionary.allTokens.map(token => `${token.name} = ${token.value}`)
43
43
  * .join('\n');
44
44
  * }
@@ -27,6 +27,7 @@ const defaultFormatting = {
27
27
  * @param {Object} options.dictionary - The dictionary object that gets passed to the formatter method.
28
28
  * @param {Boolean} options.outputReferences - Whether or not to output references
29
29
  * @param {Object} options.formatting - Custom formatting properties that define parts of a declaration line in code. This will get passed to `formatHelpers.createPropertyFormatter` and used for the `lineSeparator` between lines of code.
30
+ * @param {Boolean} options.themeable [false] - Whether tokens should default to being themeable.
30
31
  * @returns {String}
31
32
  * @example
32
33
  * ```js
@@ -38,7 +39,7 @@ const defaultFormatting = {
38
39
  * });
39
40
  * ```
40
41
  */
41
- function formattedVariables({format, dictionary, outputReferences=false, formatting={}}) {
42
+ function formattedVariables({ format, dictionary, outputReferences = false, formatting = {}, themeable = false}) {
42
43
  let {allTokens} = dictionary;
43
44
 
44
45
  let {lineSeparator} = Object.assign({}, defaultFormatting, formatting);
@@ -56,9 +57,9 @@ function formattedVariables({format, dictionary, outputReferences=false, formatt
56
57
  }
57
58
 
58
59
  return allTokens
59
- .map(createPropertyFormatter({ outputReferences, dictionary, format, formatting }))
60
+ .map(createPropertyFormatter({ outputReferences, dictionary, format, formatting, themeable }))
60
61
  .filter(function(strVal) { return !!strVal })
61
62
  .join(lineSeparator);
62
63
  }
63
64
 
64
- module.exports = formattedVariables;
65
+ module.exports = formattedVariables;
@@ -0,0 +1,77 @@
1
+ /*
2
+ * Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with
5
+ * the License. A copy of the License is located at
6
+ *
7
+ * http://www.apache.org/licenses/LICENSE-2.0
8
+ *
9
+ * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
10
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
11
+ * and limitations under the License.
12
+ */
13
+ const { unique } = require('../../utils/es6_');
14
+
15
+ /**
16
+ * Given some value, returns a basic valid TypeScript type for that value.
17
+ * Supports numbers, strings, booleans, arrays and objects of any of those types.
18
+ *
19
+ * @memberof module:formatHelpers
20
+ * @example
21
+ * ```javascript
22
+ * StyleDictionary.registerFormat({
23
+ * name: 'myCustomFormat',
24
+ * formatter: function({ dictionary, options }) {
25
+ * return dictionary.allProperties.map(function(prop) {
26
+ * var to_ret_prop = 'export const ' + prop.name + ' : ' + getTypeScriptType(prop.value) + ';';
27
+ * if (prop.comment)
28
+ * to_ret_prop = to_ret_prop.concat(' // ' + prop.comment);
29
+ * return to_ret_prop;
30
+ * }).join('\n');
31
+ * }
32
+ * });
33
+ *
34
+ * @param {*} value A value to check the type of.
35
+ * @return {String} A valid name for a TypeScript type.
36
+ * ```
37
+ */
38
+ function getTypeScriptType(value) {
39
+ if (Array.isArray(value)) return getArrayType(value)
40
+ if (typeof value === 'object') return getObjectType(value)
41
+ if (['string', 'number', 'boolean'].includes(typeof value)) return typeof value
42
+
43
+ return 'any'
44
+ }
45
+
46
+ /**
47
+ * @param {Object} value An object with uknown type properties
48
+ * @returns {String} A representation of the type model for the passed object
49
+ */
50
+ function getObjectType(value) {
51
+ const entries = Object.entries(value)
52
+ return `{ ${entries.map(([key, property], index) => {
53
+ const isLast = entries.length === index + 1
54
+ return `${key}: ${getTypeScriptType(property)}${!isLast ? ', ' : ''}`
55
+ }).join('')} }`
56
+ }
57
+
58
+ /**
59
+ * @param {Array} value An array to check each property of
60
+ * @returns {String} A valid type for the passed array and it's items
61
+ */
62
+ function getArrayType(passedArray) {
63
+ if (passedArray.length > 0) {
64
+ const firstValueType = getTypeScriptType(passedArray[0]);
65
+ if (passedArray.every((v) => getTypeScriptType(v) === firstValueType)) {
66
+ return firstValueType + '[]';
67
+ } else {
68
+ return `(${unique(passedArray.map((item, index) => {
69
+ const isLast = passedArray.length === index + 1;
70
+ return `${getTypeScriptType(item)}${!isLast ? ' | ' : ''}`
71
+ })).join('')})[]`
72
+ }
73
+ }
74
+ return 'any[]';
75
+ }
76
+
77
+ module.exports = getTypeScriptType;
@@ -15,10 +15,11 @@
15
15
  *
16
16
  * @module formatHelpers
17
17
  */
18
- module.exports = {
18
+ module.exports = {
19
19
  createPropertyFormatter: require('./createPropertyFormatter'),
20
20
  fileHeader: require('./fileHeader'),
21
21
  formattedVariables: require('./formattedVariables'),
22
+ getTypeScriptType: require('./getTypeScriptType'),
22
23
  iconsWithPrefix: require('./iconsWithPrefix'),
23
24
  sortByReference: require('./sortByReference'),
24
25
  sortByName: require('./sortByName'),
@@ -15,7 +15,7 @@ const fs = require('fs');
15
15
  const path = require('path');
16
16
  const _template = require('lodash/template');
17
17
  const GroupMessages = require('../utils/groupMessages');
18
- const { fileHeader, formattedVariables, iconsWithPrefix, minifyDictionary, sortByReference, createPropertyFormatter, sortByName } = require('./formatHelpers');
18
+ const { fileHeader, formattedVariables, getTypeScriptType, iconsWithPrefix, minifyDictionary, sortByReference, createPropertyFormatter, sortByName } = require('./formatHelpers');
19
19
 
20
20
  const SASS_MAP_FORMAT_DEPRECATION_WARNINGS = GroupMessages.GROUP.SassMapFormatDeprecationWarnings;
21
21
 
@@ -32,6 +32,7 @@ module.exports = {
32
32
  * @param {Object} options
33
33
  * @param {Boolean} [options.showFileHeader=true] - Whether or not to include a comment that has the build date
34
34
  * @param {Boolean} [options.outputReferences=false] - Whether or not to keep [references](/#/formats?id=references-in-output-files) (a -> b -> c) in the output.
35
+ * @param {string} [options.selector] - Override the root css selector
35
36
  * @example
36
37
  * ```css
37
38
  * :root {
@@ -83,6 +84,9 @@ module.exports = {
83
84
  *
84
85
  * @memberof Formats
85
86
  * @kind member
87
+ * @param {Object} options
88
+ * @param {Boolean} [options.outputReferences=false] - Whether or not to keep [references](/#/formats?id=references-in-output-files) (a -> b -> c) in the output.
89
+ * @param {Boolean} [options.themeable=true] - Whether or not tokens should default to being themeable, if not otherwise specified per token.
86
90
  * @example
87
91
  * ```scss
88
92
  * $color-background-base: #f0f0f0 !default;
@@ -99,8 +103,15 @@ module.exports = {
99
103
  * ```
100
104
  */
101
105
  'scss/map-deep': function({dictionary, options, file}) {
102
- const template = _template(fs.readFileSync(__dirname + '/templates/scss/map-deep.template'));
103
- return template({dictionary, file, options, fileHeader});
106
+ const mapTemplate = _template(fs.readFileSync(__dirname + '/templates/scss/map-deep.template'));
107
+
108
+ // Default the "themeable" option to true for backward compatibility.
109
+ const { outputReferences, themeable = true } = options;
110
+ return '\n' +
111
+ fileHeader({ file, commentStyle: 'long' }) +
112
+ formattedVariables({ format: 'sass', dictionary, outputReferences, themeable })
113
+ + '\n' +
114
+ mapTemplate({dictionary, file});
104
115
  },
105
116
 
106
117
  // This will soon be removed, is left here only for backwards compatibility
@@ -119,6 +130,7 @@ module.exports = {
119
130
  * @param {Object} options
120
131
  * @param {Boolean} [options.showFileHeader=true] - Whether or not to include a comment that has the build date
121
132
  * @param {Boolean} [options.outputReferences=false] - Whether or not to keep [references](/#/formats?id=references-in-output-files) (a -> b -> c) in the output.
133
+ * @param {Boolean} [options.themeable=false] - Whether or not tokens should default to being themeable, if not otherwise specified per token.
122
134
  * @example
123
135
  * ```scss
124
136
  * $color-background-base: #f0f0f0;
@@ -126,9 +138,9 @@ module.exports = {
126
138
  * ```
127
139
  */
128
140
  'scss/variables': function({dictionary, options, file}) {
129
- const { outputReferences } = options;
141
+ const { outputReferences, themeable = false } = options;
130
142
  return fileHeader({file, commentStyle: 'short'}) +
131
- formattedVariables({format: 'sass', dictionary, outputReferences});
143
+ formattedVariables({format: 'sass', dictionary, outputReferences, themeable});
132
144
  },
133
145
 
134
146
  /**
@@ -393,7 +405,7 @@ module.exports = {
393
405
  'typescript/es6-declarations': function({dictionary, file}) {
394
406
  return fileHeader({file}) +
395
407
  dictionary.allProperties.map(function(prop) {
396
- var to_ret_prop = 'export const ' + prop.name + ' : string;';
408
+ var to_ret_prop = 'export const ' + prop.name + ' : ' + getTypeScriptType(prop.value) + ';';
397
409
  if (prop.comment)
398
410
  to_ret_prop = to_ret_prop.concat(' // ' + prop.comment);
399
411
  return to_ret_prop;
@@ -445,7 +457,7 @@ module.exports = {
445
457
  * const JsonToTS = require('json-to-ts');
446
458
  * StyleDictionaryPackage.registerFormat({
447
459
  * name: 'typescript/accurate-module-declarations',
448
- * formatter: function(dictionary) {
460
+ * formatter: function({ dictionary }) {
449
461
  * return 'declare const root: RootObject\n' +
450
462
  * 'export default root\n' +
451
463
  * JsonToTS(dictionary.properties).join('\n');
@@ -641,9 +653,9 @@ declare const ${moduleName}: ${JSON.stringify(treeWalker(dictionary.tokens), nul
641
653
  * ```xml
642
654
  * <?xml version="1.0" encoding="UTF-8"?>
643
655
  * <resources>
644
- * <integer name="time_duration_short">1000</string>
645
- * <integer name="time_duration_medium">2000</string>
646
- * <integer name="time_duration_long">4000</string>
656
+ * <integer name="time_duration_short">1000</integer>
657
+ * <integer name="time_duration_medium">2000</integer>
658
+ * <integer name="time_duration_long">4000</integer>
647
659
  * ```
648
660
  */
649
661
  'android/integers': function({dictionary, options, file}) {
@@ -900,7 +912,7 @@ declare const ${moduleName}: ${JSON.stringify(treeWalker(dictionary.tokens), nul
900
912
  * @example
901
913
  * ```swift
902
914
  * public class StyleDictionary {
903
- * public static let colorBackgroundDanger = UIColor(red: 1.000, green: 0.918, blue: 0.914, alpha:1)
915
+ * public static let colorBackgroundDanger = UIColor(red: 1.000, green: 0.918, blue: 0.914, alpha: 1)
904
916
  * }
905
917
  * ```
906
918
  */
@@ -1164,4 +1176,4 @@ declare const ${moduleName}: ${JSON.stringify(treeWalker(dictionary.tokens), nul
1164
1176
  // Mark which formats are nested
1165
1177
  module.exports['json/nested'].nested = true;
1166
1178
  module.exports['javascript/module'].nested = true;
1167
- module.exports['javascript/object'].nested = true;
1179
+ module.exports['javascript/object'].nested = true;
@@ -13,21 +13,7 @@
13
13
  // express or implied. See the License for the specific language governing
14
14
  // permissions and limitations under the License.
15
15
  %>
16
- <%= fileHeader({file, commentStyle: 'long'}) %><%
17
- // output the list of tokens as Sass variables
18
- //
19
- dictionary.allTokens.forEach(function(prop) {
20
- var output = '';
21
- output += '$' + prop.name + ': ' + (prop.attributes.category==='asset' ? '"'+prop.value+'"' : prop.value) + ' !default;'
22
- if(prop.comment) {
23
- output += ' // ' + prop.comment;
24
- }
25
- output += '\n';
26
- print(output);
27
- });
28
-
29
- print('\n');
30
-
16
+ <%
31
17
  // output the list of tokens as a Sass nested map
32
18
  // (the values are pointing to the variables)
33
19
  //
@@ -457,7 +457,7 @@ module.exports = {
457
457
  * ```swift
458
458
  * // Matches: token.attributes.category === 'color'
459
459
  * // Returns:
460
- * UIColor(red: 0.667, green: 0.667, blue: 0.667, alpha:0.6)
460
+ * UIColor(red: 0.667, green: 0.667, blue: 0.667, alpha: 0.6)
461
461
  * ```
462
462
  *
463
463
  * @memberof Transforms
@@ -470,7 +470,30 @@ module.exports = {
470
470
  const rFixed = (r / 255.0).toFixed(3);
471
471
  const gFixed = (g / 255.0).toFixed(3);
472
472
  const bFixed = (b / 255.0).toFixed(3);
473
- return `UIColor(red: ${rFixed}, green: ${gFixed}, blue: ${bFixed}, alpha:${a})`;
473
+ return `UIColor(red: ${rFixed}, green: ${gFixed}, blue: ${bFixed}, alpha: ${a})`;
474
+ }
475
+ },
476
+
477
+ /**
478
+ * Transforms the value into an UIColor swift class for iOS
479
+ *
480
+ * ```swift
481
+ * // Matches: token.attributes.category === 'color'
482
+ * // Returns:
483
+ * Color(red: 0.667, green: 0.667, blue: 0.667, opacity: 0.6)
484
+ * ```
485
+ *
486
+ * @memberof Transforms
487
+ */
488
+ 'color/ColorSwiftUI': {
489
+ type: 'value',
490
+ matcher: isColor,
491
+ transformer: function (token) {
492
+ const { r, g, b, a } = Color(token.value).toRgb();
493
+ const rFixed = (r / 255.0).toFixed(3);
494
+ const gFixed = (g / 255.0).toFixed(3);
495
+ const bFixed = (b / 255.0).toFixed(3);
496
+ return `Color(red: ${rFixed}, green: ${gFixed}, blue: ${bFixed}, opacity: ${a})`;
474
497
  }
475
498
  },
476
499
 
package/lib/extend.js CHANGED
@@ -12,6 +12,7 @@
12
12
  */
13
13
 
14
14
  require('json5/lib/register');
15
+ require.extensions[".jsonc"] = require("./utils/jsonc").register;
15
16
 
16
17
  var combineJSON = require('./utils/combineJSON'),
17
18
  deepExtend = require('./utils/deepExtend'),
@@ -12,6 +12,7 @@
12
12
  */
13
13
 
14
14
  require('json5/lib/register');
15
+ require.extensions[".jsonc"] = require("./jsonc").register;
15
16
 
16
17
  var glob = require('glob'),
17
18
  deepExtend = require('./deepExtend'),
@@ -14,7 +14,7 @@
14
14
  const deepExtend = require('./deepExtend');
15
15
 
16
16
  function createFormatArgs({ dictionary, platform, file = {} }) {
17
- const {allProperties, properties, usesReference, getReferences} = dictionary;
17
+ const {allProperties, properties, allTokens, tokens, usesReference, getReferences} = dictionary;
18
18
  // This will merge platform and file-level configuration
19
19
  // where the file configuration takes precedence
20
20
  const {options} = platform;
@@ -26,6 +26,10 @@ function createFormatArgs({ dictionary, platform, file = {} }) {
26
26
  getReferences,
27
27
  allProperties,
28
28
  properties,
29
+ // adding tokens and allTokens as the new way starting in v3,
30
+ // keeping properties and allProperties around for backwards-compatibility
31
+ allTokens,
32
+ tokens,
29
33
  platform,
30
34
  file,
31
35
  options: file.options || {}
package/lib/utils/es6_.js CHANGED
@@ -101,7 +101,7 @@ const assign = function () {
101
101
 
102
102
  /* global Set */
103
103
  const pull = function (arr, ...removeList){
104
- var removeSet = new Set(removeList)
104
+ var removeSet = new Set(removeList)
105
105
  for (let i=arr.length-1;i>=0;i--) {
106
106
  if (removeSet.has(arr[i])) {
107
107
  arr.splice(i, 1)
@@ -109,6 +109,10 @@ const pull = function (arr, ...removeList){
109
109
  }
110
110
  }
111
111
 
112
+ const unique = function (arr){
113
+ return [...new Set(arr)]
114
+ }
115
+
112
116
  const upperFirst = function (str) {
113
117
  return str ? str[0].toUpperCase() + str.substr(1) : ''
114
118
  }
@@ -157,4 +161,5 @@ module.exports = {
157
161
  kebabCase: ChangeCase.paramCase,
158
162
  pull: pull,
159
163
  matches: matches,
164
+ unique: unique,
160
165
  }
@@ -0,0 +1,14 @@
1
+ const fs = require("fs");
2
+ const jsonc = require("jsonc-parser");
3
+
4
+ module.exports = {
5
+ register(module, filename) {
6
+ const content = fs.readFileSync(filename, "utf8");
7
+ try {
8
+ module.exports = jsonc.parse(content);
9
+ } catch (err) {
10
+ err.message = filename + ": " + err.message;
11
+ throw err;
12
+ }
13
+ },
14
+ };
@@ -67,7 +67,7 @@ function getReferences(value) {
67
67
  // function which iterates over the object to see if there is a reference
68
68
  if (typeof value === 'object') {
69
69
  for (const key in value) {
70
- if (value.hasOwnProperty(key)) {
70
+ if (value.hasOwnProperty(key) && typeof value[key] === 'string') {
71
71
  value[key].replace(regex, findReference);
72
72
  }
73
73
  }
@@ -94,8 +94,19 @@ function compile_value(value, stack) {
94
94
  // Find what the value is referencing
95
95
  const pathName = getPath(variable, options);
96
96
  const context = getName(current_context, options);
97
+ const refHasValue = pathName[pathName.length-1] === 'value';
97
98
  ref = resolveReference(pathName, updated_object);
98
99
 
100
+ // If the reference doesn't end in 'value'
101
+ // and
102
+ // the reference points to someplace that has a `value` attribute
103
+ // we should take the '.value' of the reference
104
+ // per the W3C draft spec where references do not have .value
105
+ // https://design-tokens.github.io/community-group/format/#aliases-references
106
+ if (!refHasValue && ref && ref.hasOwnProperty('value')) {
107
+ ref = ref.value;
108
+ }
109
+
99
110
  if (typeof ref !== 'undefined') {
100
111
  if (typeof ref === 'string') {
101
112
  to_ret = value.replace(match, ref);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "style-dictionary",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "Style once, use everywhere. A build system for creating cross-platform styles.",
5
5
  "keywords": [
6
6
  "style dictionary",
@@ -79,6 +79,7 @@
79
79
  ],
80
80
  "transform": {
81
81
  "^.+\\.json5$": "json5-jest",
82
+ "^.+\\.jsonc$": "json5-jest",
82
83
  "^.+\\.jsx?$": "babel-jest"
83
84
  }
84
85
  },
@@ -141,9 +142,10 @@
141
142
  "jsdoc-escape-at": "^1.0.1",
142
143
  "jsdoc-to-markdown": "^7.0.1",
143
144
  "json5-jest": "^1.0.1",
145
+ "jsonc-parser": "^3.0.0",
144
146
  "less": "^3.11.2",
145
147
  "lint-staged": "^10.2.7",
146
- "node-sass": "^4.14.1",
148
+ "node-sass": "^6.0.1",
147
149
  "standard-version": "^9.0.0",
148
150
  "stylus": "^0.54.8",
149
151
  "tsd": "^0.15.1",
package/types/Config.d.ts CHANGED
@@ -16,7 +16,7 @@ import { Transform } from './Transform';
16
16
  import { TransformGroup } from './TransformGroup';
17
17
  import { Filter } from './Filter';
18
18
  import { FileHeader } from './FileHeader';
19
- import { Format } from './Format';
19
+ import { Formatter } from './Format';
20
20
  import { Action } from './Action';
21
21
  import { Platform } from './Platform';
22
22
  import { DesignTokens } from './DesignToken';
@@ -25,7 +25,7 @@ export interface Config {
25
25
  parsers?: Parser[];
26
26
  transform?: Record<string, Transform>;
27
27
  transformGroup?: Record<string, TransformGroup>;
28
- format?: Record<string, Format>;
28
+ format?: Record<string, Formatter>;
29
29
  filter?: Record<string, Filter>;
30
30
  fileHeader?: Record<string, FileHeader>;
31
31
  action?: Record<string, Action>;
package/types/File.d.ts CHANGED
@@ -15,8 +15,9 @@ import { Options } from './Options';
15
15
  import { TransformedToken } from './TransformedToken';
16
16
 
17
17
  export interface File {
18
+ className?: string;
18
19
  destination: string;
19
20
  format?: string;
20
21
  filter?: string | Partial<TransformedToken> | ((token: TransformedToken) => boolean);
21
22
  options?: Options;
22
- }
23
+ }
@@ -11,4 +11,4 @@
11
11
  * and limitations under the License.
12
12
  */
13
13
 
14
- export type FileHeader = (defaultMessage: string) => string[];
14
+ export type FileHeader = (defaultMessage: string[]) => string[];
package/types/Format.d.ts CHANGED
@@ -42,5 +42,6 @@ export interface FormatterArguments {
42
42
  export type Formatter = (arguments: FormatterArguments) => string;
43
43
 
44
44
  export interface Format {
45
+ name: string;
45
46
  formatter: Formatter;
46
- }
47
+ }
@@ -39,7 +39,7 @@ export interface CommentFormatting {
39
39
 
40
40
  export interface FileHeaderArgs {
41
41
  file: File;
42
- commentStyle: string;
42
+ commentStyle?: string;
43
43
  formatting?: CommentFormatting;
44
44
  }
45
45
 
@@ -17,6 +17,7 @@ import { File } from './File';
17
17
  export interface Platform {
18
18
  transformGroup?: string;
19
19
  transforms?: string[];
20
+ basePxFontSize?: number;
20
21
  prefix?: string;
21
22
  buildPath?: string;
22
23
  files?: File[];
@@ -12,6 +12,5 @@
12
12
  */
13
13
 
14
14
  export interface TransformGroup {
15
- name: string;
16
- transforms: string[];
15
+ transforms: Array<string>;
17
16
  }
package/types/_helpers.ts CHANGED
@@ -11,6 +11,4 @@
11
11
  * and limitations under the License.
12
12
  */
13
13
 
14
- type Named<T> = T & { name: string; };
15
-
16
- export { Named }
14
+ export type Named<T> = T & { name: string; };
package/types/index.d.ts CHANGED
@@ -28,7 +28,7 @@ import {Platform as _Platform} from './Platform';
28
28
  import {Transform as _Transform} from './Transform';
29
29
  import {TransformedToken as _TransformedToken, TransformedTokens as _TransformedTokens} from './TransformedToken';
30
30
  import {TransformGroup as _TransformGroup} from './TransformGroup';
31
- import {Named} from './_helpers';
31
+ import {Named as _Named} from './_helpers';
32
32
 
33
33
  // Because this library is used in Node and needs to be accessible
34
34
  // as a CommonJS module, we are declaring it as a namespace so that
@@ -51,6 +51,7 @@ declare namespace StyleDictionary {
51
51
  type TransformedToken = _TransformedToken;
52
52
  type TransformedTokens = _TransformedTokens;
53
53
  type TransformGroup = _TransformGroup;
54
+ type Named<T> = _Named<T>
54
55
 
55
56
  interface Core {
56
57
  VERSION: string;
@@ -61,7 +62,7 @@ declare namespace StyleDictionary {
61
62
  options: Config;
62
63
 
63
64
  transform: Record<string, Transform>;
64
- transformGroup: Record<string, TransformGroup>;
65
+ transformGroup: Record<string, TransformGroup['transforms']>;
65
66
  format: Record<string, Format>;
66
67
  action: Record<string, Action>;
67
68
  filter: Record<string, Filter>;
@@ -162,10 +163,30 @@ declare namespace StyleDictionary {
162
163
  */
163
164
  registerFilter(filter: Named<Filter>): this;
164
165
 
166
+ /**
167
+ * Add a custom file header to Style Dictionary. File headers are used to write a
168
+ * custom messasge on top of the generated files.
169
+ * @param {String} fileHeader.name The name of the file header to be added
170
+ * @param {Function} fileHeader.fileHeader The file header function
171
+ * @example
172
+ * ```js
173
+ * StyleDictionary.registerFileHeader({
174
+ * name: 'custmoHeader',
175
+ * fileHeader: function(defaultMessage) {
176
+ * return return [
177
+ * `hello`,
178
+ * ...defaultMessage
179
+ * ]
180
+ * }
181
+ * })
182
+ * ```
183
+ */
184
+ registerFileHeader(fileHeader: Named<{ fileHeader: FileHeader }>): this;
185
+
165
186
  /**
166
187
  * Adds a custom parser to parse style dictionary files. This allows you to modify
167
188
  * the design token data before it gets to Style Dictionary or write your
168
- * token files in a language other than JSON, JSON5, or CommonJS modules.
189
+ * token files in a language other than JSON, JSONC, JSON5, or CommonJS modules.
169
190
  *
170
191
  * @param {Regex} parser.pattern - A file path regular expression to match which files this parser should be be used on. This is similar to how webpack loaders work. `/\.json$/` will match any file ending in '.json', for example.
171
192
  * @param {Function} parser.parse - Function to parse the file contents. Takes 1 argument, which is an object with 2 attributes: contents which is the string of the file contents and filePath. The function should return a plain Javascript object.
@@ -305,4 +326,4 @@ declare namespace StyleDictionary {
305
326
  }
306
327
 
307
328
  declare var StyleDictionary: StyleDictionary.Core;
308
- export = StyleDictionary;
329
+ export = StyleDictionary;
@@ -142,6 +142,10 @@ expectAssignable<StyleDictionary.File>({
142
142
  });
143
143
 
144
144
 
145
+ expectAssignable<StyleDictionary.Platform>({
146
+ basePxFontSize: 16,
147
+ });
148
+
145
149
  expectAssignable<StyleDictionary.Platform>({
146
150
  transformGroup: `css`,
147
151
  });