style-dictionary 4.0.0-prerelease.1 → 4.0.0-prerelease.2

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/bin/{style-dictionary → style-dictionary.js} +13 -13
  2. package/examples/advanced/auto-rebuild-watcher/package.json +1 -1
  3. package/examples/advanced/create-react-app/package.json +2 -1
  4. package/examples/advanced/create-react-native-app/package.json +5 -1
  5. package/examples/advanced/s3/upload.js +1 -1
  6. package/examples/advanced/yaml-tokens/sd.config.js +1 -1
  7. package/lib/StyleDictionary.js +451 -0
  8. package/lib/buildFile.js +46 -40
  9. package/lib/cleanDir.js +1 -1
  10. package/lib/cleanDirs.js +2 -2
  11. package/lib/cleanFile.js +1 -1
  12. package/lib/common/actions.js +12 -7
  13. package/lib/common/formatHelpers/getTypeScriptType.js +8 -7
  14. package/lib/common/formats.js +6 -6
  15. package/lib/common/templates/compose/object.kt.template.js +1 -1
  16. package/lib/common/templates/css/fonts.css.template.js +1 -1
  17. package/lib/common/templates/ios/singleton.m.template.js +10 -10
  18. package/lib/common/templates/scss/map-deep.template.js +3 -3
  19. package/lib/common/transforms.js +11 -1
  20. package/lib/filterTokens.js +76 -0
  21. package/lib/register/preprocessor.js +39 -0
  22. package/lib/register/transform.js +2 -1
  23. package/lib/register/transformGroup.js +1 -3
  24. package/lib/transform/config.js +26 -21
  25. package/lib/transform/object.js +18 -12
  26. package/lib/transform/{property.js → token.js} +1 -2
  27. package/lib/transform/{propertySetup.js → tokenSetup.js} +17 -17
  28. package/lib/utils/combineJSON.js +22 -12
  29. package/lib/utils/convertToBase64.js +3 -3
  30. package/lib/utils/createDictionary.js +10 -14
  31. package/lib/utils/createFormatArgs.js +1 -5
  32. package/lib/utils/deepExtend.js +15 -18
  33. package/lib/utils/deepmerge.js +14 -0
  34. package/lib/utils/{flattenProperties.js → flattenTokens.js} +10 -10
  35. package/lib/utils/preprocess.js +35 -0
  36. package/lib/utils/references/getName.js +2 -2
  37. package/lib/utils/references/getReferences.js +7 -7
  38. package/lib/utils/resolveObject.js +4 -5
  39. package/package.json +33 -20
  40. package/types/Config.d.ts +3 -2
  41. package/types/Dictionary.d.ts +0 -2
  42. package/types/FormatHelpers.d.ts +12 -23
  43. package/{lib/cleanAllPlatforms.js → types/Preprocessor.d.ts} +6 -17
  44. package/types/index.d.ts +23 -2
  45. package/types/index.test-d.ts +7 -0
  46. package/index-node.js +0 -7
  47. package/index.js +0 -84
  48. package/lib/buildAllPlatforms.js +0 -37
  49. package/lib/buildPlatform.js +0 -67
  50. package/lib/cleanPlatform.js +0 -59
  51. package/lib/exportPlatform.js +0 -131
  52. package/lib/extend.js +0 -162
  53. package/lib/filterProperties.js +0 -92
  54. package/lib/utils/es6_.js +0 -151
@@ -11,25 +11,25 @@
11
11
  * and limitations under the License.
12
12
  */
13
13
 
14
- import { clone, matches } from '../utils/es6_.js';
14
+ import { isPlainObject } from 'is-plain-object';
15
15
  import deepExtend from '../utils/deepExtend.js';
16
16
  import GroupMessages from '../utils/groupMessages.js';
17
17
 
18
- const TEMPLATE_DEPRECATION_WARNINGS = GroupMessages.GROUP.TemplateDeprecationWarnings;
19
18
  const MISSING_TRANSFORM_ERRORS = GroupMessages.GROUP.MissingRegisterTransformErrors;
20
19
 
21
20
  /**
22
- * Takes a platform config object and returns a new one
21
+ * Takes a platform platformConfig object and returns a new one
23
22
  * that has filters, transforms, formats, and actions
24
23
  * mapped properly.
25
24
  * @private
26
- * @param {Object} config
25
+ * @param {Object} platformConfig
27
26
  * @param {Object} dictionary
28
27
  * @param {Object} platformName (only used for error messaging)
29
28
  * @returns {Object}
30
29
  */
31
- export default function transformConfig(config, dictionary, platformName) {
32
- const to_ret = clone(config);
30
+ export default function transformConfig(platformConfig, dictionary, platformName) {
31
+ const to_ret = { ...platformConfig }; // structuredClone not suitable due to config being able to contain Function() etc.
32
+ to_ret.log = platformConfig.log ?? dictionary.log;
33
33
 
34
34
  // The platform can define either a transformGroup or an array
35
35
  // of transforms. If given a transformGroup that doesn't exist,
@@ -82,8 +82,8 @@ None of ${transform_warnings} match the name of a registered transform.
82
82
  }
83
83
 
84
84
  // Apply registered fileHeaders onto the platform options
85
- if (config.options && config.options.fileHeader) {
86
- const fileHeader = config.options.fileHeader;
85
+ if (platformConfig.options && platformConfig.options.fileHeader) {
86
+ const fileHeader = platformConfig.options.fileHeader;
87
87
  if (typeof fileHeader === 'string') {
88
88
  if (dictionary.fileHeader[fileHeader]) {
89
89
  to_ret.options.fileHeader = dictionary.fileHeader[fileHeader];
@@ -97,7 +97,7 @@ None of ${transform_warnings} match the name of a registered transform.
97
97
  }
98
98
  }
99
99
 
100
- to_ret.files = (config.files || []).map(function (file) {
100
+ to_ret.files = (platformConfig.files || []).map(function (file) {
101
101
  const ext = { options: {} };
102
102
  if (file.options && file.options.fileHeader) {
103
103
  const fileHeader = file.options.fileHeader;
@@ -122,6 +122,21 @@ None of ${transform_warnings} match the name of a registered transform.
122
122
  throw new Error("Can't find filter: " + file.filter);
123
123
  }
124
124
  } else if (typeof file.filter === 'object') {
125
+ // Recursively go over the object keys of filter object and
126
+ // return a filter Function that filters tokens
127
+ // by the specified object keys.
128
+ const matchFn = function (inputObj, testObj) {
129
+ if (isPlainObject(testObj)) {
130
+ return Object.keys(testObj).every((key) => matchFn(inputObj[key], testObj[key]));
131
+ } else {
132
+ return inputObj == testObj;
133
+ }
134
+ };
135
+ const matches = function (matchObj) {
136
+ let cloneObj = { ...matchObj }; // shallow clone, structuredClone not suitable because obj can contain "Function()"
137
+ let matchesFn = (inputObj) => matchFn(inputObj, cloneObj);
138
+ return matchesFn;
139
+ };
125
140
  ext.filter = matches(file.filter);
126
141
  } else if (typeof file.filter === 'function') {
127
142
  ext.filter = file.filter;
@@ -130,17 +145,7 @@ None of ${transform_warnings} match the name of a registered transform.
130
145
  }
131
146
  }
132
147
 
133
- if (file.template) {
134
- if (dictionary.format[file.template]) {
135
- GroupMessages.add(
136
- TEMPLATE_DEPRECATION_WARNINGS,
137
- `${file.destination} (template: ${file.template})`,
138
- );
139
- ext.format = dictionary.format[file.template];
140
- } else {
141
- throw new Error("Can't find template: " + file.template);
142
- }
143
- } else if (file.format) {
148
+ if (file.format) {
144
149
  if (dictionary.format[file.format]) {
145
150
  ext.format = dictionary.format[file.format];
146
151
  } else {
@@ -152,7 +157,7 @@ None of ${transform_warnings} match the name of a registered transform.
152
157
  return deepExtend([{}, file, ext]);
153
158
  });
154
159
 
155
- to_ret.actions = (config.actions || []).map(function (action) {
160
+ to_ret.actions = (platformConfig.actions || []).map(function (action) {
156
161
  if (typeof dictionary.action[action].undo !== 'function') {
157
162
  console.warn(action + ' action does not have a clean function!');
158
163
  }
@@ -11,11 +11,11 @@
11
11
  * and limitations under the License.
12
12
  */
13
13
 
14
- import { isPlainObject, pull } from '../utils/es6_.js';
14
+ import { isPlainObject } from 'is-plain-object';
15
15
  import usesValueReference from '../utils/references/usesReference.js';
16
16
  import getName from '../utils/references/getName.js';
17
- import transformProperty from './property.js';
18
- import propertySetup from './propertySetup.js';
17
+ import transformToken from './token.js';
18
+ import tokenSetup from './tokenSetup.js';
19
19
 
20
20
  /**
21
21
  * Applies transforms on all tokens. This
@@ -26,7 +26,7 @@ import propertySetup from './propertySetup.js';
26
26
  * @private
27
27
  * @param {Object} obj
28
28
  * @param {Object} options
29
- * @param {Object} [transformationContext={}]
29
+ * @param {Object} [ctx={}]
30
30
  * @param {Array} [path=[]]
31
31
  * @param {Object} [transformedObj={}]
32
32
  * @returns {Object}
@@ -34,13 +34,12 @@ import propertySetup from './propertySetup.js';
34
34
  export default function transformObject(
35
35
  obj,
36
36
  options,
37
- transformationContext = {},
37
+ { transformedPropRefs = [], deferredPropValueTransforms = [] } = {},
38
38
  path,
39
39
  transformedObj,
40
40
  ) {
41
41
  transformedObj = transformedObj || {};
42
42
  path = path || [];
43
- const { transformedPropRefs = [], deferredPropValueTransforms = [] } = transformationContext;
44
43
 
45
44
  for (const name in obj) {
46
45
  if (!obj.hasOwnProperty(name)) {
@@ -68,9 +67,9 @@ export default function transformObject(
68
67
  continue;
69
68
  }
70
69
 
71
- // Note: propertySetup won't re-run if property has already been setup
70
+ // Note: tokenSetup won't re-run if property has already been setup
72
71
  // it is safe to run this multiple times on the same property.
73
- const setupProperty = propertySetup(objProp, name, path);
72
+ const setupProperty = tokenSetup(objProp, name, path);
74
73
 
75
74
  // If property has a reference, defer its transformations until later
76
75
  if (usesValueReference(setupProperty.value, options)) {
@@ -86,9 +85,16 @@ export default function transformObject(
86
85
 
87
86
  // If we got here, the property hasn't been transformed yet and
88
87
  // does not use a value reference. Transform the property now and assign it.
89
- transformedObj[name] = transformProperty(setupProperty, options);
90
- // Remove the property path from the deferred transform list
91
- pull(deferredPropValueTransforms, pathName);
88
+ transformedObj[name] = transformToken(setupProperty, options);
89
+
90
+ // Remove the property path from the deferred transform list, starting from end of array
91
+ for (let i = deferredPropValueTransforms.length - 1; i >= 0; i--) {
92
+ if (deferredPropValueTransforms[i] === pathName) {
93
+ // Important to use .splice and mutate the original array all the way up
94
+ deferredPropValueTransforms.splice(i, 1);
95
+ }
96
+ }
97
+
92
98
  // Add the property path to the transformed list so we don't transform it again.
93
99
  transformedPropRefs.push(pathName);
94
100
  } else if (isObj) {
@@ -96,7 +102,7 @@ export default function transformObject(
96
102
  transformedObj[name] = transformObject(
97
103
  objProp,
98
104
  options,
99
- transformationContext,
105
+ { transformedPropRefs, deferredPropValueTransforms },
100
106
  path,
101
107
  transformedObj[name],
102
108
  );
@@ -11,7 +11,6 @@
11
11
  * and limitations under the License.
12
12
  */
13
13
 
14
- import { clone } from '../utils/es6_.js';
15
14
  import usesReference from '../utils/references/usesReference.js';
16
15
 
17
16
  /**
@@ -23,7 +22,7 @@ import usesReference from '../utils/references/usesReference.js';
23
22
  * @returns {Object} - A new property object with transforms applied.
24
23
  */
25
24
  export default function transformProperty(property, options) {
26
- const to_ret = clone(property);
25
+ const to_ret = structuredClone(property);
27
26
  const transforms = options.transforms;
28
27
 
29
28
  for (let i = 0; i < transforms.length; i++) {
@@ -11,34 +11,34 @@
11
11
  * and limitations under the License.
12
12
  */
13
13
 
14
+ import { isPlainObject } from 'is-plain-object';
14
15
  import deepExtend from '../utils/deepExtend.js';
15
- import { isPlainObject, isString, isArray, clone } from '../utils/es6_.js';
16
16
 
17
17
  /**
18
- * Takes a property object, a leaf node in a properties object, and
19
- * returns a new object that has some properties set. It clones the
18
+ * Takes a token object, a leaf node in a tokens object, and
19
+ * returns a new object that has some tokens set. It clones the
20
20
  * original object for safekeeping, adds a name, adds an attributes object,
21
21
  * and a path array.
22
22
  * @private
23
- * @param {Object} property - the property object to setup
24
- * @param {String} name - The name of the property, which will should be its key in the object.
25
- * @param {Array} path - The path of keys to get to the property from the top level of the properties object.
23
+ * @param {Object} token - the token object to setup
24
+ * @param {String} name - The name of the token, which will should be its key in the object.
25
+ * @param {Array} path - The path of keys to get to the token from the top level of the tokens object.
26
26
  * @returns {Object} - A new object that is setup and ready to go.
27
27
  */
28
- export default function propertySetup(property, name, path) {
29
- if (!property && !isPlainObject(property)) throw new Error('Property object must be an object');
30
- if (!name || !isString(name)) throw new Error('Name must be a string');
31
- if (!path || !isArray(path)) throw new Error('Path must be an array');
28
+ export default function tokenSetup(token, name, path) {
29
+ if (!token && !isPlainObject(token)) throw new Error('Property object must be an object');
30
+ if (!name || !(typeof name === 'string')) throw new Error('Name must be a string');
31
+ if (!path || !Array.isArray(path)) throw new Error('Path must be an array');
32
32
 
33
- let to_ret = property;
33
+ let to_ret = token;
34
34
 
35
35
  // Only do this once
36
- if (!property.original) {
37
- // Initial property setup
38
- // Keep the original object properties like it was in file (whitout additional data)
36
+ if (!token.original) {
37
+ // Initial token setup
38
+ // Keep the original object tokens like it was in file (whitout additional data)
39
39
  // so we can key off them in the transforms
40
- to_ret = deepExtend([{}, property]);
41
- let to_ret_original = deepExtend([{}, property]);
40
+ to_ret = deepExtend([{}, token]);
41
+ let to_ret_original = deepExtend([{}, token]);
42
42
  delete to_ret_original.filePath;
43
43
  delete to_ret_original.isSource;
44
44
 
@@ -49,7 +49,7 @@ export default function propertySetup(property, name, path) {
49
49
  to_ret.attributes = to_ret.attributes || {};
50
50
  // An array of the path down the object tree; we will use it to build readable names
51
51
  // like color_font_base
52
- to_ret.path = clone(path);
52
+ to_ret.path = structuredClone(path);
53
53
  }
54
54
 
55
55
  return to_ret;
@@ -14,8 +14,8 @@
14
14
  import JSON5 from 'json5';
15
15
  import glob from '@bundled-es-modules/glob';
16
16
  import path from '@bundled-es-modules/path-browserify';
17
+ import { fs } from 'style-dictionary/fs';
17
18
  import deepExtend from './deepExtend.js';
18
- import { fs } from '../../fs.js';
19
19
 
20
20
  function traverseObj(obj, fn) {
21
21
  for (let key in obj) {
@@ -33,41 +33,51 @@ function traverseObj(obj, fn) {
33
33
  * @param {String[]} arr - Array of paths to json (or node modules that export objects) files
34
34
  * @param {Boolean} [deep=false] - If it should perform a deep merge
35
35
  * @param {Function} collision - A function to be called when a name collision happens that isn't a normal deep merge of objects
36
- * @param {Boolean} [source=true] - If json files are "sources", tag properties
36
+ * @param {Boolean} [source=true] - If json files are "sources", tag tokens
37
37
  * @param {Object[]} [parsers=[]] - Custom file parsers
38
38
  * @returns {Object}
39
39
  */
40
- export default function combineJSON(arr, deep, collision, source, parsers = []) {
40
+ export default async function combineJSON(arr, deep, collision, source, parsers = []) {
41
41
  const to_ret = {};
42
42
  let files = [];
43
43
 
44
44
  for (let i = 0; i < arr.length; i++) {
45
- const new_files = glob.sync(arr[i], { fs });
45
+ const new_files = glob.sync(arr[i], { fs }).sort();
46
46
  files = files.concat(new_files);
47
47
  }
48
48
 
49
+ // adjust for browser env glob results have leading slash
50
+ files = files.map((f) => f.replace(/^\//, ''));
51
+
49
52
  for (let i = 0; i < files.length; i++) {
50
53
  const filePath = files[i];
51
- const resolvedPath = path.isAbsolute(files[i])
52
- ? files[i]
53
- : path.resolve(process.cwd(), files[i]);
54
54
  let file_content = null;
55
-
56
55
  try {
57
56
  // Iterate over custom parsers, if the file path matches the parser's
58
57
  // pattern regex, use it's parse function to generate the object
59
58
  parsers.forEach(({ pattern, parse }) => {
60
- if (resolvedPath.match(pattern)) {
59
+ if (filePath.match(pattern)) {
61
60
  file_content = parse({
62
- contents: fs.readFileSync(resolvedPath, { encoding: 'UTF-8' }),
63
- filePath: resolvedPath,
61
+ contents: fs.readFileSync(filePath, { encoding: 'UTF-8' }),
62
+ filePath,
64
63
  });
65
64
  }
66
65
  });
67
66
 
68
67
  // If there is no file_content then no custom parser ran on that file
69
68
  if (!file_content) {
70
- file_content = deepExtend([file_content, JSON5.parse(fs.readFileSync(resolvedPath))]);
69
+ let parsedFile;
70
+ if (['.js', '.mjs'].includes(path.extname(filePath))) {
71
+ const fileToImport = path.resolve(
72
+ typeof window === 'object' ? '' : process.cwd(),
73
+ filePath,
74
+ );
75
+ parsedFile = (await import(fileToImport)).default;
76
+ } else {
77
+ parsedFile = JSON5.parse(fs.readFileSync(filePath));
78
+ }
79
+
80
+ file_content = deepExtend([file_content, parsedFile]);
71
81
  }
72
82
  } catch (e) {
73
83
  e.message = 'Failed to load or parse JSON or JS Object: ' + e.message;
@@ -11,7 +11,7 @@
11
11
  * and limitations under the License.
12
12
  */
13
13
 
14
- import { fs } from '../../fs.js';
14
+ import { fs } from 'style-dictionary/fs';
15
15
 
16
16
  /**
17
17
  * Takes a file and converts it to a base64 string.
@@ -22,6 +22,6 @@ import { fs } from '../../fs.js';
22
22
  export default function convertToBase64(filePath) {
23
23
  if (typeof filePath !== 'string') throw new Error('filePath name must be a string');
24
24
 
25
- const body = fs.readFileSync(filePath, 'binary');
26
- return Buffer.from(body, 'binary').toString('base64');
25
+ const body = fs.readFileSync(filePath);
26
+ return btoa(body);
27
27
  }
@@ -11,15 +11,15 @@
11
11
  * and limitations under the License.
12
12
  */
13
13
 
14
- import flattenProperties from './flattenProperties.js';
14
+ import flattenTokens from './flattenTokens.js';
15
15
  import getReferences from './references/getReferences.js';
16
16
  import usesReference from './references/usesReference.js';
17
17
 
18
18
  /**
19
19
  *
20
20
  * @typedef Dictionary
21
- * @property {Object} tokens - Replacement for `properties`
22
- * @property {Array} allTokens - Replacement for `allProperties`
21
+ * @property {Object} $tokens
22
+ * @property {Array} allTokens
23
23
  * @property {Dictionary.getReferences} getReferences
24
24
  * @property {Dictionary.usesReference} usesReference
25
25
  */
@@ -27,19 +27,15 @@ import usesReference from './references/usesReference.js';
27
27
  /**
28
28
  * Creates the dictionary object that is passed to formats and actions.
29
29
  * @param {Object} args
30
- * @param {Object} args.properties
30
+ * @param {Object} args.tokens
31
31
  * @returns {Dictionary}
32
32
  */
33
- export default function createDictionary({ properties }) {
34
- const allProperties = flattenProperties(properties);
33
+ export default function createDictionary({ tokens }) {
34
+ const allTokens = flattenTokens(tokens);
35
35
  return {
36
- properties,
37
- allProperties,
38
- // adding tokens and allTokens as the new way starting in v3,
39
- // keeping properties and allProperties around for backwards-compatibility
40
- tokens: properties,
41
- allTokens: allProperties,
42
- getReferences: getReferences,
43
- usesReference: usesReference,
36
+ tokens,
37
+ allTokens,
38
+ getReferences,
39
+ usesReference,
44
40
  };
45
41
  }
@@ -14,7 +14,7 @@
14
14
  import deepExtend from './deepExtend.js';
15
15
 
16
16
  export default function createFormatArgs({ dictionary, platform, file = {} }) {
17
- const { allProperties, properties, allTokens, tokens, usesReference, getReferences } = dictionary;
17
+ const { 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;
@@ -24,10 +24,6 @@ export default function createFormatArgs({ dictionary, platform, file = {} }) {
24
24
  dictionary,
25
25
  usesReference,
26
26
  getReferences,
27
- allProperties,
28
- properties,
29
- // adding tokens and allTokens as the new way starting in v3,
30
- // keeping properties and allProperties around for backwards-compatibility
31
27
  allTokens,
32
28
  tokens,
33
29
  platform,
@@ -11,9 +11,11 @@
11
11
  * and limitations under the License.
12
12
  */
13
13
 
14
- import { isPlainObject, isArray } from './es6_.js';
14
+ import { isPlainObject } from 'is-plain-object';
15
15
 
16
16
  /**
17
+ * TODO: see if we can use deepmerge instead of maintaining our own utility
18
+ *
17
19
  * Performs an deep extend on the objects, from right to left.
18
20
  * @private
19
21
  * @param {Object[]} objects - An array of JS objects
@@ -24,15 +26,7 @@ import { isPlainObject, isArray } from './es6_.js';
24
26
  export default function deepExtend(objects, collision, path) {
25
27
  if (objects == null) return {};
26
28
 
27
- var src,
28
- copyIsArray,
29
- copy,
30
- name,
31
- options,
32
- clone,
33
- target = objects[0] || {},
34
- i = 1,
35
- length = objects.length;
29
+ let target = objects[0] || {};
36
30
 
37
31
  path = path || [];
38
32
 
@@ -41,33 +35,36 @@ export default function deepExtend(objects, collision, path) {
41
35
  target = {};
42
36
  }
43
37
 
44
- for (; i < length; i++) {
38
+ for (let i = 1; i < objects.length; i++) {
39
+ const options = objects[i];
45
40
  // Only deal with non-null/undefined values
46
- if ((options = objects[i]) != null) {
41
+ if (options != null) {
47
42
  // Extend the base object
48
- for (name in options) {
43
+ for (const name in options) {
49
44
  // Not everything extends from Object in browser context, so bind from Object just in case
50
45
  if (!Object.hasOwnProperty.bind(options)(name)) continue;
51
46
  if (name === '__proto__') continue;
52
47
 
53
- src = target[name];
54
- copy = options[name];
48
+ const src = target[name];
49
+ const copy = options[name];
55
50
 
56
51
  // Prevent never-ending loop
57
52
  if (target === copy) {
58
53
  continue;
59
54
  }
60
55
 
56
+ let copyIsArray = Array.isArray(copy);
61
57
  // Recurse if we're merging plain objects or arrays
62
- if (copy && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) {
58
+ if (copy && (isPlainObject(copy) || copyIsArray)) {
59
+ let clone;
63
60
  if (copyIsArray) {
64
61
  copyIsArray = false;
65
- clone = src && isArray(src) ? src : [];
62
+ clone = src && Array.isArray(src) ? src : [];
66
63
  } else {
67
64
  clone = src && isPlainObject(src) ? src : {};
68
65
  }
69
66
 
70
- var nextPath = path.slice(0);
67
+ const nextPath = path.slice(0);
71
68
  nextPath.push(name);
72
69
 
73
70
  // Never move original objects, clone them
@@ -0,0 +1,14 @@
1
+ import _deepmerge from '@bundled-es-modules/deepmerge';
2
+ import { isPlainObject } from 'is-plain-object';
3
+
4
+ /**
5
+ * Wrapper around deepmerge that merges only plain objects and arrays
6
+ * @param {Object} target
7
+ * @param {Object} source
8
+ */
9
+ export const deepmerge = (target, source) => {
10
+ return _deepmerge(target, source, {
11
+ // Merge if object is array or a plain object (so not merging functions/class instances together)
12
+ isMergeableObject: (obj) => Array.isArray(obj) || isPlainObject(obj),
13
+ });
14
+ };
@@ -11,27 +11,27 @@
11
11
  * and limitations under the License.
12
12
  */
13
13
 
14
- import { isPlainObject } from './es6_.js';
14
+ import { isPlainObject } from 'is-plain-object';
15
15
 
16
16
  /**
17
17
  * Takes an plain javascript object and will make a flat array of all the leaf nodes.
18
18
  * A leaf node in this context has a 'value' property. Potentially refactor this to
19
19
  * be more generic.
20
20
  * @private
21
- * @param {Object} properties - The plain object you want flattened into an array.
22
- * @param {Array} [to_ret=[]] - Properties array. This function is recursive therefore this is what gets passed along.
21
+ * @param {Object} tokens - The plain object you want flattened into an array.
22
+ * @param {Array} [to_ret=[]] - Tokens array. This function is recursive therefore this is what gets passed along.
23
23
  * @return {Array}
24
24
  */
25
- export default function flattenProperties(properties, to_ret) {
25
+ export default function flattenTokens(tokens, to_ret) {
26
26
  to_ret = to_ret || [];
27
27
 
28
- for (var name in properties) {
29
- if (properties.hasOwnProperty(name)) {
28
+ for (var name in tokens) {
29
+ if (tokens.hasOwnProperty(name)) {
30
30
  // TODO: this is a bit fragile and arbitrary to stop when we get to a 'value' property.
31
- if (isPlainObject(properties[name]) && 'value' in properties[name]) {
32
- to_ret.push(properties[name]);
33
- } else if (isPlainObject(properties[name])) {
34
- flattenProperties(properties[name], to_ret);
31
+ if (isPlainObject(tokens[name]) && 'value' in tokens[name]) {
32
+ to_ret.push(tokens[name]);
33
+ } else if (isPlainObject(tokens[name])) {
34
+ flattenTokens(tokens[name], to_ret);
35
35
  }
36
36
  }
37
37
  }
@@ -0,0 +1,35 @@
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
+
14
+ /**
15
+ * Run all registered preprocessors on the dictionary,
16
+ * returning the preprocessed dictionary in each step.
17
+ *
18
+ * @typedef {import('../../types/DesignToken').DesignTokens} DesignTokens
19
+ * @typedef {import('../../types/Preprocessor').Preprocessor} Preprocessor
20
+ *
21
+ * @param {DesignTokens} tokens
22
+ * @param {Preprocessor[]} preprocessorObj
23
+ * @returns {Promise<DesignTokens>}
24
+ */
25
+ export async function preprocess(tokens, preprocessorObj = {}) {
26
+ let processedTokens = tokens;
27
+
28
+ const preprocessors = Object.values(preprocessorObj);
29
+ if (preprocessors.length > 0) {
30
+ for (const preprocessor of preprocessors) {
31
+ processedTokens = await preprocessor(processedTokens);
32
+ }
33
+ }
34
+ return processedTokens;
35
+ }
@@ -22,8 +22,8 @@ import defaults from './defaults.js';
22
22
  * @returns {string} - The paths name
23
23
  */
24
24
  export default function getName(path, opts = {}) {
25
- const options = Object.assign({}, defaults, opts);
26
- if (!path || !(path instanceof Array)) {
25
+ const options = { ...defaults, ...opts };
26
+ if (!Array.isArray(path)) {
27
27
  throw new Error('Getting name for path failed. Path must be an array');
28
28
  }
29
29
  return path.join(options.separator);
@@ -33,7 +33,6 @@ import GroupMessages from '../groupMessages.js';
33
33
  */
34
34
  export default function getReferences(value, references = []) {
35
35
  // `this` is the dictionary object passed to formats and actions
36
- const self = this;
37
36
  const regex = createReferenceRegex({});
38
37
 
39
38
  // this will update the references array with the referenced tokens it finds.
@@ -44,10 +43,11 @@ export default function getReferences(value, references = []) {
44
43
  // Find what the value is referencing
45
44
  const pathName = getPath(variable);
46
45
 
47
- let ref = resolveReference(pathName, self.properties);
46
+ let ref = resolveReference(pathName, this.tokens);
47
+
48
48
  if (!ref) {
49
- // fall back on _properties as it is unfiltered
50
- ref = resolveReference(pathName, self._properties);
49
+ // fall back on _tokens as it is unfiltered
50
+ ref = resolveReference(pathName, this._tokens);
51
51
  // and warn the user about this
52
52
  GroupMessages.add(GroupMessages.GROUP.FilteredOutputReferences, variable);
53
53
  }
@@ -56,7 +56,7 @@ export default function getReferences(value, references = []) {
56
56
 
57
57
  if (typeof value === 'string') {
58
58
  // function inside .replace runs multiple times if there are multiple matches
59
- value.replace(regex, findReference);
59
+ value.replace(regex, findReference.bind(this));
60
60
  }
61
61
 
62
62
  // If the token's value is an object, run the replace reference
@@ -65,11 +65,11 @@ export default function getReferences(value, references = []) {
65
65
  if (typeof value === 'object') {
66
66
  for (const key in value) {
67
67
  if (value.hasOwnProperty(key) && typeof value[key] === 'string') {
68
- value[key].replace(regex, findReference);
68
+ value[key].replace(regex, findReference.bind(this));
69
69
  }
70
70
  // if it is an object, we go further down the rabbit hole
71
71
  if (value.hasOwnProperty(key) && typeof value[key] === 'object') {
72
- self.getReferences(value[key], references);
72
+ this.getReferences(value[key], references);
73
73
  }
74
74
  }
75
75
  }