Skip to content

Commit

Permalink
Merge branch 'main' into patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
jorenbroekema authored Oct 2, 2024
2 parents 59a960b + 996fc0e commit c8222e4
Show file tree
Hide file tree
Showing 16 changed files with 394 additions and 165 deletions.
5 changes: 5 additions & 0 deletions .changeset/dirty-grapes-deliver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'style-dictionary': patch
---

Make `defaultMessage` param in FileHeader type optional.
5 changes: 5 additions & 0 deletions .changeset/tall-comics-grow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'style-dictionary': patch
---

(#1305): fix reference sorting in `sortByReference` function for DTCG token format, ensuring token references are declared after their targets
5 changes: 5 additions & 0 deletions .changeset/wicked-pears-eat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'style-dictionary': patch
---

Fix `filterTokens` utility to deal with random metadata properties throughout token groups, without throwing errors.
20 changes: 16 additions & 4 deletions __integration__/__snapshots__/outputReferences.test.snap.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
/* @web/test-runner snapshot v1 */
export const snapshots = {};

snapshots["integration output references should warn the user if filters out references briefly"] =
snapshots["integration output references should warn the user if filters out references briefly"] =
`⚠️ __integration__/build/filteredVariables.css
While building filteredVariables.css, filtered out token references were found; output may be unexpected. Ignore this warning if intentional.
Use log.verbosity "verbose" or use CLI option --verbose for more details.
Refer to: https://styledictionary.com/reference/logging/`;
/* end snapshot integration output references should warn the user if filters out references briefly */

snapshots["integration output references should warn the user if filters out references with a detailed message when using verbose logging"] =
snapshots["integration output references should warn the user if filters out references with a detailed message when using verbose logging"] =
`⚠️ __integration__/build/filteredVariables.css
While building filteredVariables.css, filtered out token references were found; output may be unexpected. Ignore this warning if intentional.
Here are the references that are used but not defined in the file:
Expand All @@ -23,13 +23,13 @@ color.core.blue.0
This is caused when combining a filter and \`outputReferences\`.`;
/* end snapshot integration output references should warn the user if filters out references with a detailed message when using verbose logging */

snapshots["integration output references should not warn the user if filters out references is prevented with outputReferencesFilter"] =
snapshots["integration output references should not warn the user if filters out references is prevented with outputReferencesFilter"] =
`
css
✔︎ __integration__/build/filteredVariables.css`;
/* end snapshot integration output references should not warn the user if filters out references is prevented with outputReferencesFilter */

snapshots["integration output references should allow using outputReferencesTransformed to not output refs when value has been transitively transformed"] =
snapshots["integration output references should allow using outputReferencesTransformed to not output refs when value has been transitively transformed"] =
`/**
* Do not edit directly, this file was auto-generated.
*/
Expand All @@ -41,3 +41,15 @@ snapshots["integration output references should allow using outputReferencesTran
`;
/* end snapshot integration output references should allow using outputReferencesTransformed to not output refs when value has been transitively transformed */

snapshots["integration output references should properly reference tokens in dtcg format"] =
`/**
* Do not edit directly, this file was auto-generated.
*/
:root {
--base: #ff0000;
--referred: var(--base);
}
`;
/* end snapshot integration output references should properly reference tokens in dtcg format */

36 changes: 36 additions & 0 deletions __integration__/outputReferences.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,5 +176,41 @@ describe('integration', async () => {
await sd.buildAllPlatforms();
await expect(stub.lastCall.args.map(cleanConsoleOutput).join('\n')).to.matchSnapshot();
});

it('should properly reference tokens in dtcg format', async () => {
const sd = new StyleDictionary({
tokens: {
base: {
$value: '#FF0000',
$type: 'color',
},
referred: {
$value: '{base}',
$type: 'color',
},
},
platforms: {
css: {
transformGroup: 'css',
buildPath,
files: [
{
destination: 'dtcgOutputRef.css',
format: 'css/variables',
options: {
outputReferences: true,
usesDtcg: true,
},
},
],
},
},
});
await sd.buildAllPlatforms();
const output = fs.readFileSync(resolve(`${buildPath}dtcgOutputRef.css`), {
encoding: 'UTF-8',
});
await expect(output).to.matchSnapshot();
});
});
});
110 changes: 110 additions & 0 deletions __tests__/common/formatHelpers/sortByReference.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* 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 { expect } from 'chai';
import sortByReference from '../../../lib/common/formatHelpers/sortByReference.js';

const TRANSFORMED_TOKENS = (usesDtcg) => {
const valueKey = usesDtcg ? '$value' : 'value';
const typeKey = usesDtcg ? '$type' : 'type';

return {
color: {
primary: {
[valueKey]: '#FF0000',
[typeKey]: 'color',
original: {
[valueKey]: '{color.red}',
[typeKey]: 'color',
},
},
red: {
[valueKey]: '#FF0000',
[typeKey]: 'color',
original: {
[valueKey]: '#FF0000',
[typeKey]: 'color',
},
},
},
};
};

describe('common', () => {
describe('formatHelpers', () => {
describe('sortByReference', () => {
[
['default', false, TRANSFORMED_TOKENS(false)],
['dtcg', true, TRANSFORMED_TOKENS(true)],
].forEach(([tokenFormat, usesDtcg, tokens]) => {
it(`should keep order when idx0 has no reference(${tokenFormat})`, () => {
const allTokens = [tokens.color.red, tokens.color.primary];

const sorted = [...allTokens].sort(
sortByReference(tokens, {
usesDtcg,
}),
);

expect(sorted).to.eql([tokens.color.red, tokens.color.primary]);
});
it(`should reorder, if idx0 references idx1 (${tokenFormat})`, () => {
const allTokens = [tokens.color.primary, tokens.color.red];

const sorted = [...allTokens].sort(
sortByReference(tokens, {
usesDtcg,
}),
);

expect(sorted).to.eql([tokens.color.red, tokens.color.primary]);
});
});
it('should reorder when idx0 is undefined', () => {
const tokens = TRANSFORMED_TOKENS(false);
const tokensWithAnUndefinedValue = {
...tokens,
color: { ...tokens.color, primary: undefined },
};
const allTokens = [
tokensWithAnUndefinedValue.color.primary,
tokensWithAnUndefinedValue.color.red,
];

const sorted = [...allTokens].sort(sortByReference(tokensWithAnUndefinedValue));

expect(sorted).to.eql([
tokensWithAnUndefinedValue.color.red,
tokensWithAnUndefinedValue.color.primary,
]);
});
it('should keep order when idx1 is undefined', () => {
const tokens = TRANSFORMED_TOKENS(false);
const tokensWithUndefinedValue = {
...tokens,
color: { ...tokens.color, primary: undefined },
};
const allTokens = [
tokensWithUndefinedValue.color.red,
tokensWithUndefinedValue.color.primary,
];

const sorted = [...allTokens].sort(sortByReference(tokensWithUndefinedValue));

expect(sorted).to.eql([
tokensWithUndefinedValue.color.red,
tokensWithUndefinedValue.color.primary,
]);
});
});
});
});
65 changes: 58 additions & 7 deletions __tests__/filterTokens.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,46 @@ const tokens = {
},
};

const random_meta_tokens = {
description: null,
meta: undefined,
more_meta: [],
foo: {
description: null,
meta: undefined,
more_meta: [],
bar: {
description: null,
meta: undefined,
more_meta: [],
value: 0,
type: 'number',
original: {
value: 0,
},
name: 'foo-bar',
path: ['foo', 'bar'],
},
},
qux: {
description: null,
meta: undefined,
more_meta: [],
value: 0,
type: 'number',
original: {
value: 0,
},
name: 'qux',
path: ['qux'],
},
};

const random_meta_dictionary = {
tokens: random_meta_tokens,
allTokens: flattenTokens(random_meta_tokens),
};

const falsy_values = {
kept: kept,
not_kept: not_kept,
Expand Down Expand Up @@ -115,29 +155,40 @@ describe('filterTokens', () => {
});

it('should work with a filter function', async () => {
const filter = (property) => property.path.includes('size');
const filter = (token) => token.path.includes('size');
const filteredDictionary = await filterTokens(dictionary, filter);
filteredDictionary.allTokens.forEach((property) => {
expect(property).to.not.equal(colorRed);
expect(property).not.to.not.equal(colorBlue);
filteredDictionary.allTokens.forEach((token) => {
expect(token).to.not.equal(colorRed);
expect(token).not.to.not.equal(colorBlue);
});
expect(filteredDictionary.allTokens).to.eql([sizeSmall, sizeLarge]);
expect(filteredDictionary.tokens).to.have.property('size');
expect(filteredDictionary.tokens).to.not.have.property('color');
});

it('should work with falsy values and a filter function', async () => {
const filter = (property) => property.path.includes('kept');
const filter = (token) => token.path.includes('kept');

const filteredDictionary = await filterTokens(falsy_dictionary, filter);
filteredDictionary.allTokens.forEach((property) => {
expect(property).to.not.equal(not_kept);
filteredDictionary.allTokens.forEach((token) => {
expect(token).to.not.equal(not_kept);
});
expect(filteredDictionary.allTokens).to.eql([kept]);
expect(filteredDictionary.tokens).to.have.property('kept');
expect(filteredDictionary.tokens).to.not.have.property('not_kept');
});

it('should work with random metadata props inside tokens / token groups', async () => {
const filter = (token) => {
return token.path.includes('bar');
};

const filteredDictionary = await filterTokens(random_meta_dictionary, filter);
expect(filteredDictionary.allTokens).to.eql([random_meta_tokens.foo.bar]);
expect(filteredDictionary.tokens).to.have.nested.property('foo.bar');
expect(filteredDictionary.tokens).to.not.have.property('qux');
});

it('should work with async filters', async () => {
const filtered = await filterTokens(dictionary, async (token) => {
await new Promise((resolve) => setTimeout(resolve, 100));
Expand Down
2 changes: 1 addition & 1 deletion __tests__/utils/reference/resolveReferences.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ describe('utils', () => {
});

describe('ignorePaths', () => {
it('should not resolve values containing constiables in ignored paths', () => {
it('should not resolve values containing variables in ignored paths', () => {
const obj = {
foo: { value: 'bar' },
bar: {
Expand Down
2 changes: 1 addition & 1 deletion __tests__/utils/resolveObject.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ describe('utils', () => {
});

describe('ignorePaths', () => {
it('should not resolve values containing constiables in ignored paths', () => {
it('should not resolve values containing variables in ignored paths', () => {
const test = resolveObject(
{
foo: { value: 'bar' },
Expand Down
2 changes: 1 addition & 1 deletion lib/common/formatHelpers/fileHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export default async function fileHeader({ file, commentStyle, formatting = {},
/**
* @type {FileHeader}
*/
let fn = (arr) => arr;
let fn = (arr) => arr ?? [];
if (file?.options?.fileHeader && typeof file?.options?.fileHeader !== 'string') {
fn = file.options.fileHeader;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/common/formatHelpers/formattedVariables.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export default function formattedVariables({
// note: using the spread operator here so we get a new array rather than
// mutating the original
allTokens = [...allTokens].sort(
sortByReference(tokens, { unfilteredTokens: dictionary.unfilteredTokens }),
sortByReference(tokens, { unfilteredTokens: dictionary.unfilteredTokens, usesDtcg }),
);
}

Expand Down
Loading

0 comments on commit c8222e4

Please sign in to comment.