From 2e8576e1a1047fdec6777e56c5b12536d30c92ad Mon Sep 17 00:00:00 2001 From: jorenbroekema Date: Thu, 12 Oct 2023 12:05:09 +0200 Subject: [PATCH] fix: no unnecessary type change in resolveMath --- .changeset/mighty-worms-sell.md | 5 ++ src/checkAndEvaluateMath.ts | 9 ++- test/integration/output-references.test.ts | 60 +++++++++++++++++++ .../tokens/output-references.tokens.json | 30 ++++++++++ test/spec/checkAndEvaluateMath.spec.ts | 8 +++ 5 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 .changeset/mighty-worms-sell.md create mode 100644 test/integration/output-references.test.ts create mode 100644 test/integration/tokens/output-references.tokens.json diff --git a/.changeset/mighty-worms-sell.md b/.changeset/mighty-worms-sell.md new file mode 100644 index 0000000..de9df43 --- /dev/null +++ b/.changeset/mighty-worms-sell.md @@ -0,0 +1,5 @@ +--- +'@tokens-studio/sd-transforms': patch +--- + +resolveMath no longer unnecessarily changes the token type to number if the token value is a string without any expressions to resolve. diff --git a/src/checkAndEvaluateMath.ts b/src/checkAndEvaluateMath.ts index 1e8d2a2..a4648b6 100644 --- a/src/checkAndEvaluateMath.ts +++ b/src/checkAndEvaluateMath.ts @@ -79,6 +79,11 @@ function parseAndReduce(expr: string): string | boolean | number { // Remove it here so we can evaluate expressions like 16px + 24px const calcParsed = parse(unitlessExpr, { allowInlineCommnets: false }); + // No expression to evaluate, just return it (in case of number as string e.g. '10') + if (calcParsed.nodes.length === 1 && calcParsed.nodes[0].type === 'Number') { + return expr; + } + // Attempt to reduce the math expression const reduced = reduceExpression(calcParsed); let unit; @@ -111,10 +116,10 @@ function parseAndReduce(expr: string): string | boolean | number { export function checkAndEvaluateMath( expr: string | number | boolean | undefined, ): string | number | boolean | undefined { - if (expr === undefined || typeof expr === 'boolean') { + if (typeof expr !== 'string') { return expr; } - const exprs = splitMultiIntoSingleValues(`${expr}`); + const exprs = splitMultiIntoSingleValues(expr); const reducedExprs = exprs.map(_expr => parseAndReduce(_expr)); if (reducedExprs.length === 1) { return reducedExprs[0]; diff --git a/test/integration/output-references.test.ts b/test/integration/output-references.test.ts new file mode 100644 index 0000000..ac0d51b --- /dev/null +++ b/test/integration/output-references.test.ts @@ -0,0 +1,60 @@ +import { expect } from '@esm-bundle/chai'; +import StyleDictionary from 'style-dictionary'; +import { promises } from 'fs'; +import path from 'path'; +import { cleanup, init } from './utils.js'; + +const outputDir = 'test/integration/tokens/'; +const outputFileName = 'vars.css'; +const outputFilePath = path.resolve(outputDir, outputFileName); + +const cfg = { + source: ['test/integration/tokens/output-references.tokens.json'], + platforms: { + css: { + transforms: ['ts/resolveMath', 'name/cti/kebab'], + prefix: 'sd', + buildPath: outputDir, + files: [ + { + destination: outputFileName, + format: 'css/variables', + options: { + outputReferences: true, + }, + }, + ], + }, + }, +}; + +let dict: StyleDictionary.Core | undefined; + +describe('outputReferences integration', () => { + beforeEach(() => { + if (dict) { + cleanup(dict); + } + dict = init(cfg); + }); + + afterEach(() => { + if (dict) { + cleanup(dict); + } + }); + + it('supports outputReferences with resolveMath', async () => { + const file = await promises.readFile(outputFilePath, 'utf-8'); + console.log(file); + expect(file).to.include(`--sd-my-base-token: 11;`); + expect(file).to.include(`--sd-my-reference-token: var(--sd-my-base-token);`); + }); + + // Pending Style-Dictionary v3 release with the new outputReferences fixes + it.skip('supports outputReferences with resolveMath when evaluating an expression', async () => { + const file = await promises.readFile(outputFilePath, 'utf-8'); + expect(file).to.include(`--sd-transformed-base-token: 4;`); + expect(file).to.include(`--sd-transformed-reference-token: 5 * var(--sd-my-base-token);`); + }); +}); diff --git a/test/integration/tokens/output-references.tokens.json b/test/integration/tokens/output-references.tokens.json new file mode 100644 index 0000000..a3ad7c3 --- /dev/null +++ b/test/integration/tokens/output-references.tokens.json @@ -0,0 +1,30 @@ +{ + "my": { + "base": { + "token": { + "value": "11", + "type": "spacing" + } + }, + "reference": { + "token": { + "value": "{my.base.token}", + "type": "spacing" + } + } + }, + "transformed": { + "base": { + "token": { + "value": "4", + "type": "spacing" + } + }, + "reference": { + "token": { + "value": "{my.base.token} * 5", + "type": "spacing" + } + } + } +} diff --git a/test/spec/checkAndEvaluateMath.spec.ts b/test/spec/checkAndEvaluateMath.spec.ts index 8118f5d..2c47c0d 100644 --- a/test/spec/checkAndEvaluateMath.spec.ts +++ b/test/spec/checkAndEvaluateMath.spec.ts @@ -64,6 +64,14 @@ describe('check and evaluate math', () => { ); }); + it('does not unnecessarily change the type of the value', () => { + expect(checkAndEvaluateMath(11)).to.equal(11); + // qchanges to number because the expression is a math expression evaluating to a number result + expect(checkAndEvaluateMath('11 * 5')).to.equal(55); + // keeps it as string because there is no math expression to evaluate, so just keep it as is + expect(checkAndEvaluateMath('11')).to.equal('11'); + }); + it('supports values that contain spaces and strings, e.g. a date format', () => { expect(checkAndEvaluateMath(`dd/MM/yyyy 'om' HH:mm`)).to.equal(`dd/MM/yyyy 'om' HH:mm`); });