Skip to content

Commit

Permalink
fix: preserve brackets around functions
Browse files Browse the repository at this point in the history
Modify the parser to track parenthesized expressions.
Keep the parentheses if a function is inside.

Fix #113
Fix #115
  • Loading branch information
ludofischer committed Jan 10, 2022
1 parent 50a0c4e commit 0b70a1d
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 3 deletions.
19 changes: 19 additions & 0 deletions src/__tests__/index.js
Expand Up @@ -735,6 +735,25 @@ test(
testValue('calc(100% - calc(10px - 2vw))', 'calc(100% - 10px + 2vw)')
);

test(
'should preserve division precedence',
testValue(
'calc(100%/(var(--aspect-ratio)))',
'calc(100%/(var(--aspect-ratio)))'
)
);

test(
'should preserve division precedence (2)',
testValue(
`calc(
(var(--fluid-screen) - ((var(--fluid-min-width) / 16) * 1rem)) /
((var(--fluid-max-width) / 16) - (var(--fluid-min-width) / 16))
)`,
'calc((var(--fluid-screen) - var(--fluid-min-width)/16*1rem)/(var(--fluid-max-width)/16 - var(--fluid-min-width)/16))'
)
);

test('precision for calc', testValue('calc(100% / 3 * 3)', '100%'));

test(
Expand Down
9 changes: 9 additions & 0 deletions src/lib/reducer.js
Expand Up @@ -100,6 +100,8 @@ function collectAddSubItems(preOperator, node, collected, precision) {
collected.push({node: reducedNode, preOperator});
}
}
} else if (node.type === 'ParenthesizedExpression') {
collectAddSubItems(preOperator, node.content, collected, precision);
} else {
collected.push({node, preOperator});
}
Expand Down Expand Up @@ -286,6 +288,7 @@ function convertNodesUnits(left, right, precision) {
/**
* @param {import('../parser').CalcNode} node
* @param {number} precision
* @return {import('../parser').CalcNode}
*/
function reduce(node, precision) {
if (node.type === "MathExpression") {
Expand All @@ -305,6 +308,12 @@ function reduce(node, precision) {
return node;
}

if (node.type === 'ParenthesizedExpression') {
if (node.content.type !== 'Function') {
return reduce(node.content, precision);
}
}

return node;
}

Expand Down
4 changes: 4 additions & 0 deletions src/lib/stringifier.js
Expand Up @@ -20,6 +20,8 @@ function round(value, prec) {
/**
* @param {number | false} prec
* @param {import('../parser').CalcNode} node
*
* @return {string}
*/
function stringify(node, prec) {
switch (node.type) {
Expand All @@ -46,6 +48,8 @@ function stringify(node, prec) {
return round(node.value, prec).toString();
case 'Function':
return node.value.toString();
case 'ParenthesizedExpression':
return `(${stringify(node.content, prec)})`;
default:
return round(node.value, prec) + node.unit;
}
Expand Down
7 changes: 6 additions & 1 deletion src/parser.d.ts
Expand Up @@ -5,6 +5,11 @@ export interface MathExpression {
operator: '*' | '+' | '-' | '/';
}

export interface ParenthesizedExpression {
type: 'ParenthesizedExpression';
content: CalcNode;
}

export interface DimensionExpression {
type:
| 'LengthValue'
Expand Down Expand Up @@ -37,7 +42,7 @@ export interface FunctionExpression {

export type ValueExpression = DimensionExpression | NumberExpression;

export type CalcNode = MathExpression | ValueExpression | FunctionExpression;
export type CalcNode = MathExpression | ValueExpression | FunctionExpression | ParenthesizedExpression;

export interface Parser {
parse: (arg: string) => CalcNode;
Expand Down
2 changes: 1 addition & 1 deletion src/parser.jison
Expand Up @@ -74,7 +74,7 @@ expression
| math_expression SUB math_expression { $$ = { type: 'MathExpression', operator: $2, left: $1, right: $3 }; }
| math_expression MUL math_expression { $$ = { type: 'MathExpression', operator: $2, left: $1, right: $3 }; }
| math_expression DIV math_expression { $$ = { type: 'MathExpression', operator: $2, left: $1, right: $3 }; }
| LPAREN math_expression RPAREN { $$ = $2; }
| LPAREN math_expression RPAREN { $$ = { type: 'ParenthesizedExpression', content: $2 }; }
| function { $$ = $1; }
| dimension { $$ = $1; }
| number { $$ = $1; }
Expand Down
3 changes: 2 additions & 1 deletion types/lib/reducer.d.ts
Expand Up @@ -6,5 +6,6 @@ export type Collectible = {
/**
* @param {import('../parser').CalcNode} node
* @param {number} precision
* @return {import('../parser').CalcNode}
*/
declare function reduce(node: import('../parser').CalcNode, precision: number): import("../parser").MathExpression | import("../parser").DimensionExpression | import("../parser").NumberExpression | import("../parser").FunctionExpression;
declare function reduce(node: import('../parser').CalcNode, precision: number): import('../parser').CalcNode;

0 comments on commit 0b70a1d

Please sign in to comment.