diff --git a/.changeset/hot-planets-whisper.md b/.changeset/hot-planets-whisper.md index 1364cb6..ad1f508 100644 --- a/.changeset/hot-planets-whisper.md +++ b/.changeset/hot-planets-whisper.md @@ -1,5 +1,8 @@ --- -"@tokens-studio/sd-transforms": patch +'@tokens-studio/sd-transforms': minor --- -fix for checkAndEvaluateMath as it currently crashed on boolean expressions +checkAndEvaluateMath to not stringify if not needed: + +- for single math expressions resolving to a floating number without unit, we can keep it as a `Number` +- for expressions such as `false` or `true` (`Boolean`), keep as `Boolean` type diff --git a/package-lock.json b/package-lock.json index 87b8d2e..ac03783 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@tokens-studio/sd-transforms", - "version": "0.10.3", + "version": "0.10.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@tokens-studio/sd-transforms", - "version": "0.10.3", + "version": "0.10.5", "license": "MIT", "dependencies": { "@tokens-studio/types": "^0.2.4", diff --git a/src/checkAndEvaluateMath.ts b/src/checkAndEvaluateMath.ts index 91b8a26..401831e 100644 --- a/src/checkAndEvaluateMath.ts +++ b/src/checkAndEvaluateMath.ts @@ -72,7 +72,7 @@ function splitMultiIntoSingleValues(expr: string): string[] { return [expr]; } -function parseAndReduce(expr: string): string { +function parseAndReduce(expr: string): string | boolean | number { // We check for px unit, then remove it const hasPx = expr.match('px'); let unitlessExpr = expr.replace(/px/g, ''); @@ -96,19 +96,26 @@ function parseAndReduce(expr: string): string { } catch (ex) { return expr; } + + const formatted = + typeof evaluated === 'number' ? Number.parseFloat(evaluated.toFixed(3)) : evaluated; // Put back the px unit if needed and if reduced doesn't come with one - return `${typeof evaluated === 'number' ? Number.parseFloat(evaluated.toFixed(3)) : evaluated}${ - unit ?? (hasPx ? 'px' : '') - }`; + const formattedUnit = unit ?? (hasPx ? 'px' : ''); + + // This ensures stringification is not done when not needed (e.g. type number or boolean kept intact) + return formattedUnit ? `${formatted}${formattedUnit}` : formatted; } export function checkAndEvaluateMath( expr: string | number | boolean | undefined, -): string | undefined { +): string | number | boolean | undefined { if (expr === undefined) { return expr; } const exprs = splitMultiIntoSingleValues(`${expr}`); const reducedExprs = exprs.map(_expr => parseAndReduce(_expr)); + if (reducedExprs.length === 1) { + return reducedExprs[0]; + } return reducedExprs.join(' '); } diff --git a/src/css/transformBorder.ts b/src/css/transformBorder.ts index a72e61b..e37151f 100644 --- a/src/css/transformBorder.ts +++ b/src/css/transformBorder.ts @@ -16,7 +16,7 @@ export function transformBorderForCSS( } let { color, width } = border; const { style } = border; - width = transformDimension(checkAndEvaluateMath(width)); + width = transformDimension(checkAndEvaluateMath(width) as number | string | undefined); color = transformHEXRGBaForCSS(color); return `${isNothing(width) ? '' : width} ${isNothing(style) ? '' : style} ${ isNothing(color) ? '' : color diff --git a/src/css/transformShadow.ts b/src/css/transformShadow.ts index 05fd8eb..505532b 100644 --- a/src/css/transformShadow.ts +++ b/src/css/transformShadow.ts @@ -16,10 +16,10 @@ export function transformShadowForCSS( } let { x, y, blur, spread } = shadow; const { color, type } = shadow; - x = transformDimension(checkAndEvaluateMath(x)); - y = transformDimension(checkAndEvaluateMath(y)); - blur = transformDimension(checkAndEvaluateMath(blur)); - spread = transformDimension(checkAndEvaluateMath(spread)); + x = transformDimension(checkAndEvaluateMath(x) as number | string | undefined); + y = transformDimension(checkAndEvaluateMath(y) as number | string | undefined); + blur = transformDimension(checkAndEvaluateMath(blur) as number | string | undefined); + spread = transformDimension(checkAndEvaluateMath(spread) as number | string | undefined); return `${type === 'innerShadow' ? 'inset ' : ''}${isNothing(x) ? 0 : x} ${ isNothing(y) ? 0 : y } ${isNothing(blur) ? 0 : blur}${isNothing(spread) ? ' ' : ` ${spread} `}${ diff --git a/src/css/transformTypography.ts b/src/css/transformTypography.ts index dbfcb40..d23429e 100644 --- a/src/css/transformTypography.ts +++ b/src/css/transformTypography.ts @@ -49,8 +49,8 @@ export function transformTypographyForCSS( let { fontFamily, fontWeight, fontSize, lineHeight } = value; const { fontStyle } = value; - fontSize = transformDimension(checkAndEvaluateMath(fontSize)); - lineHeight = checkAndEvaluateMath(lineHeight); + fontSize = transformDimension(checkAndEvaluateMath(fontSize) as number | string | undefined); + lineHeight = checkAndEvaluateMath(lineHeight) as number | string | undefined; fontWeight = transformFontWeights(fontWeight); fontFamily = processFontFamily(fontFamily as string | undefined); diff --git a/test/spec/checkAndEvaluateMath.spec.ts b/test/spec/checkAndEvaluateMath.spec.ts index 19196b1..32550d0 100644 --- a/test/spec/checkAndEvaluateMath.spec.ts +++ b/test/spec/checkAndEvaluateMath.spec.ts @@ -8,14 +8,14 @@ describe('check and evaluate math', () => { it('checks and evaluates math expressions', () => { expect(checkAndEvaluateMath('4*1.5px 4*1.5px 4*1.5px')).to.equal('6px 6px 6px'); expect(checkAndEvaluateMath('4px')).to.equal('4px'); - expect(checkAndEvaluateMath('4 * 7')).to.equal('28'); + expect(checkAndEvaluateMath('4 * 7')).to.equal(28); expect(checkAndEvaluateMath('4 * 7px')).to.equal('28px'); expect(checkAndEvaluateMath('4 * 7rem')).to.equal('28rem'); expect(checkAndEvaluateMath('(15 + 20 - 17 * 8 / 3) * 7px')).to.equal('-72.333px'); }); it('supports expression of type number', () => { - expect(checkAndEvaluateMath(10)).to.equal('10'); + expect(checkAndEvaluateMath(10)).to.equal(10); }); it('can evaluate math expressions where more than one token has a unit, in case of px', () => { @@ -51,11 +51,11 @@ describe('check and evaluate math', () => { }); it('supports expr-eval expressions', () => { - expect(checkAndEvaluateMath('roundTo(4 / 7, 1)')).to.equal('0.6'); + expect(checkAndEvaluateMath('roundTo(4 / 7, 1)')).to.equal(0.6); expect(checkAndEvaluateMath('8 * 14px roundTo(4 / 7, 1)')).to.equal('112px 0.6'); expect(checkAndEvaluateMath('roundTo(4 / 7, 1) 8 * 14px')).to.equal('0.6 112px'); expect(checkAndEvaluateMath('min(10, 24, 5, 12, 6) 8 * 14px')).to.equal('5 112px'); - expect(checkAndEvaluateMath('ceil(roundTo(16/1.2,0)/2)*2')).to.equal('14'); + expect(checkAndEvaluateMath('ceil(roundTo(16/1.2,0)/2)*2')).to.equal(14); }); it('does not unnecessarily remove wrapped quotes around font-family values', () => { @@ -70,6 +70,6 @@ describe('check and evaluate math', () => { it('supports boolean values', () => { expect(checkAndEvaluateMath(false)).to.equal(false); - expect(checkAndEvaluateMath(true)).to.equal(false); + expect(checkAndEvaluateMath(true)).to.equal(true); }); });