UNPKG

style-dictionary

Version:

Style once, use everywhere. A build system for creating cross-platform styles.

102 lines (88 loc) 3.25 kB
/* * 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 usesReferences from '../../utils/references/usesReferences.js'; import { getReferences } from '../../utils/references/getReferences.js'; /** * @typedef {import('../../../types/DesignToken.d.ts').TransformedTokens} Tokens * @typedef {import('../../../types/DesignToken.d.ts').TransformedToken} Token */ const A_COMES_FIRST = -1; const B_COMES_FIRST = 1; /** * A function that returns a sorting function to be used with Array.sort that * will sort the allTokens array based on references. This is to make sure * if you use output references that you never use a reference before it is * defined. * @memberof module:formatHelpers * @name sortByReference * @example * ```javascript * dictionary.allTokens.sort(sortByReference(dictionary)) * ``` * @param {Tokens} tokens * @param {{unfilteredTokens?: Tokens, usesDtcg?: boolean}} [opts] * @returns {(a: Token, b: Token) => number} */ export default function sortByReference(tokens, { unfilteredTokens, usesDtcg } = {}) { const valueKey = usesDtcg ? '$value' : 'value'; /** * The sorter function is recursive to account for multiple levels of nesting * @param {Token} a * @param {Token} b * @returns {number} */ function sorter(a, b) { if (typeof a === 'undefined') { return A_COMES_FIRST; } if (typeof b === 'undefined') { return B_COMES_FIRST; } const aUsesRefs = a.original && usesReferences(a.original[valueKey]); const bUsesRefs = b.original && usesReferences(b.original[valueKey]); // -----BOTH REFERENCE----- if (aUsesRefs && bUsesRefs) { // Collect references for 'a' and 'b' const aRefs = getReferences(a.original[valueKey], tokens, { unfilteredTokens, warnImmediately: false, }); const bRefs = getReferences(b.original[valueKey], tokens, { unfilteredTokens, warnImmediately: false, }); // 'a' references 'b' -> 'b' should come first if (aRefs.some((aRef) => aRef.name === b.name)) { return B_COMES_FIRST; } // 'b' references 'a' -> 'a' should come first if (bRefs.some((bRef) => bRef.name === a.name)) { return A_COMES_FIRST; } // 'a' and 'b' reference, but not each other. Recurse to next level return sorter(aRefs[0], bRefs[0]); } // ----- ONLY ONE REFERENCES ----- // 'a' references, 'b' doesn't -> 'b' should come first if (aUsesRefs) { return B_COMES_FIRST; } // 'b' references, 'a' doesn't -> 'a' should come first if (bUsesRefs) { return A_COMES_FIRST; } // no references, keep existing order return 0; } return sorter; }