-
Notifications
You must be signed in to change notification settings - Fork 576
/
Copy pathflattenTokens.js
64 lines (60 loc) · 2.77 KB
/
flattenTokens.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/*
* Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
* and limitations under the License.
*/
import isPlainObject from 'is-plain-obj';
/**
* @typedef {import('../../types/DesignToken.ts').DesignToken} Token
* @typedef {import('../../types/DesignToken.ts').DesignTokens} Tokens
* @typedef {import('../../types/DesignToken.ts').TransformedToken} TransformedToken
* @typedef {import('../../types/DesignToken.ts').TransformedTokens} TransformedTokens
*/
/**
* @private
* @template {Token | TransformedToken} T
* @template {Tokens | TransformedTokens} U
* @param {U} slice - The plain object you want flattened into an array.
* @param {boolean} [usesDtcg] - Whether or not tokens are using DTCG syntax.
* @param {Array<T>} [result] - Tokens array. This function is recursive therefore this is what gets passed along.
* @param {string[]} [keyMemo] - Memo of keys we're traversing in order of depth
* @return {Array<T>}
*/
function _flattenTokens(slice, usesDtcg, result = [], keyMemo = []) {
for (let key in slice) {
if (Object.hasOwn(slice, key)) {
// Stop either when we encounter a "value" prop or if we find that every prop is not an object, meaning we cannot traverse any further
if (isPlainObject(slice[key]) && Object.hasOwn(slice[key], `${usesDtcg ? '$' : ''}value`)) {
result.push({
.../** @type {T} */ (slice[key]),
// this keeps track of the ancestor keys of the token e.g. 'colors.red.500'
key: `{${[...keyMemo, key].join('.')}}`,
});
} else if (isPlainObject(slice[key])) {
// pass the current slice key to the end of the memo onto the next recursive call
_flattenTokens(slice[key], usesDtcg, result, keyMemo.concat(key));
}
}
}
return result;
}
/**
* Takes an plain javascript object and will make a flat array of all the leaf nodes.
* A leaf node in this context has a 'value' property. Potentially refactor this to
* be more generic.
* @template {Token | TransformedToken} T
* @template {Tokens | TransformedTokens} U
* @param {U} tokens - The plain object you want flattened into an array.
* @param {boolean} [usesDtcg] - Whether or not tokens are using DTCG syntax.
* @return {Array<T>}
*/
export default function flattenTokens(tokens, usesDtcg = false) {
return _flattenTokens(tokens, usesDtcg);
}