Skip to content

Commit c8e5203

Browse files
Razinskyjorenbroekema
authored andcommitted
feat: add mathFractionDigits option resolveMath transform, default from 3 to 4
1 parent b454787 commit c8e5203

File tree

5 files changed

+70
-7
lines changed

5 files changed

+70
-7
lines changed

.changeset/two-jokes-give.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@tokens-studio/sd-transforms': minor
3+
---
4+
5+
Allow changing the resolve math transform amount of decimals to round for using platform options `mathFractionDigits`, change default value from 3 to 4.

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,26 @@ This transform checks and evaluates math expressions
487487

488488
**matches**: All tokens that have string values.
489489

490+
You can adjust to how many decimals the result should be rounded using `PlatformConfig.mathFractionDigits`:
491+
492+
```json
493+
{
494+
"source": ["tokens.json"],
495+
"platforms": {
496+
"css": {
497+
"mathFractionDigits": 3,
498+
"transformGroup": "tokens-studio",
499+
"files": [
500+
{
501+
"format": "css/variables",
502+
"destination": "output.css"
503+
}
504+
]
505+
}
506+
}
507+
}
508+
```
509+
490510
#### before
491511

492512
```json

src/checkAndEvaluateMath.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { DesignToken } from 'style-dictionary/types';
22
import { Parser } from 'expr-eval-fork';
33
import { parse, reduceExpression } from '@bundled-es-modules/postcss-calc-ast-parser';
44

5+
const defaultFractionDigits = 4;
56
const mathChars = ['+', '-', '*', '/'];
67

78
const parser = new Parser();
@@ -74,7 +75,7 @@ function splitMultiIntoSingleValues(expr: string): string[] {
7475
return [expr];
7576
}
7677

77-
function parseAndReduce(expr: string): string | number {
78+
function parseAndReduce(expr: string, fractionDigits = defaultFractionDigits): string | number {
7879
let result: string | number = expr;
7980

8081
let evaluated;
@@ -127,12 +128,15 @@ function parseAndReduce(expr: string): string | number {
127128
}
128129

129130
// the outer Number() gets rid of insignificant trailing zeros of decimal numbers
130-
const reducedTo3Fixed = Number(Number.parseFloat(`${result}`).toFixed(3));
131-
result = resultUnit ? `${reducedTo3Fixed}${resultUnit}` : reducedTo3Fixed;
131+
const reducedToFixed = Number(Number.parseFloat(`${result}`).toFixed(fractionDigits));
132+
result = resultUnit ? `${reducedToFixed}${resultUnit}` : reducedToFixed;
132133
return result;
133134
}
134135

135-
export function checkAndEvaluateMath(token: DesignToken): DesignToken['value'] {
136+
export function checkAndEvaluateMath(
137+
token: DesignToken,
138+
fractionDigits?: number,
139+
): DesignToken['value'] {
136140
const expr = token.$value ?? token.value;
137141
const type = token.$type ?? token.type;
138142

@@ -145,7 +149,7 @@ export function checkAndEvaluateMath(token: DesignToken): DesignToken['value'] {
145149
return expr;
146150
}
147151
const exprs = splitMultiIntoSingleValues(expr);
148-
const reducedExprs = exprs.map(_expr => parseAndReduce(_expr));
152+
const reducedExprs = exprs.map(_expr => parseAndReduce(_expr, fractionDigits));
149153
if (reducedExprs.length === 1) {
150154
return reducedExprs[0];
151155
}

src/register.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export async function register(sd: typeof StyleDictionary, transformOpts?: Trans
7373
type: 'value',
7474
transitive: true,
7575
filter: token => ['string', 'object'].includes(typeof (token.$value ?? token.value)),
76-
transform: token => checkAndEvaluateMath(token),
76+
transform: (token, config) => checkAndEvaluateMath(token, config.options?.mathFractionDigits),
7777
});
7878

7979
sd.registerTransform({

test/spec/checkAndEvaluateMath.spec.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { expect } from 'chai';
22
import { checkAndEvaluateMath } from '../../src/checkAndEvaluateMath.js';
33
import { runTransformSuite } from '../suites/transform-suite.spec.js';
4+
import { cleanup, init } from '../integration/utils.js';
5+
import { TransformedToken } from 'style-dictionary/types';
46

57
runTransformSuite(checkAndEvaluateMath as (value: unknown) => unknown, {});
68

@@ -15,7 +17,7 @@ describe('check and evaluate math', () => {
1517
expect(checkAndEvaluateMath({ value: '4 * 7rem', type: 'dimension' })).to.equal('28rem');
1618
expect(
1719
checkAndEvaluateMath({ value: '(15 + 20 - 17 * 8 / 3) * 7px', type: 'dimension' }),
18-
).to.equal('-72.333px');
20+
).to.equal('-72.3333px');
1921
});
2022

2123
it('supports expression of type number', () => {
@@ -110,6 +112,38 @@ describe('check and evaluate math', () => {
110112
);
111113
});
112114

115+
it('allows a `mathFractionDigits` option to control the rounding of values in math', async () => {
116+
const dict = await init({
117+
tokens: {
118+
foo: {
119+
value: '5',
120+
type: 'dimension',
121+
},
122+
bar: {
123+
value: '{foo} / 16',
124+
type: 'dimension',
125+
},
126+
},
127+
platforms: {
128+
css: {
129+
transformGroup: 'tokens-studio',
130+
options: {
131+
mathFractionDigits: 3,
132+
},
133+
files: [
134+
{
135+
format: 'css/variables',
136+
destination: 'foo.css',
137+
},
138+
],
139+
},
140+
},
141+
});
142+
const enrichedTokens = await dict?.exportPlatform('css'); // platform to parse for is 'css' in this case
143+
cleanup(dict);
144+
expect((enrichedTokens?.bar as TransformedToken).value).to.eql('0.313px');
145+
});
146+
113147
it('supports boolean values', () => {
114148
expect(checkAndEvaluateMath({ value: false, type: 'boolean' })).to.equal(false);
115149
expect(checkAndEvaluateMath({ value: true, type: 'boolean' })).to.equal(true);

0 commit comments

Comments
 (0)