From 93be4511323e399e336bd2e97a63f0dc49ab2fdc Mon Sep 17 00:00:00 2001 From: Rob Snow Date: Fri, 18 Dec 2020 18:49:11 -0800 Subject: [PATCH] Fix Parse error on custom property fallback --- parser.jison | 11 +++++++---- src/__tests__/index.js | 29 +++++++++++++++++++++++++++++ src/lib/reducer.js | 2 ++ src/lib/stringifier.js | 18 +++++++++++++----- 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/parser.jison b/parser.jison index d7749e8..d467718 100644 --- a/parser.jison +++ b/parser.jison @@ -3,6 +3,7 @@ /* lexical grammar */ %lex %% +(--[0-9a-z-A-Z-]*) return 'CSS_CPROP'; \s+ /* skip whitespace */ "*" return 'MUL'; "/" return 'DIV'; @@ -38,11 +39,12 @@ ([0-9]+("."[0-9]*)?|"."[0-9]+)\b return 'NUMBER'; (calc) return 'NESTED_CALC'; -(var\([^\)]*\)) return 'CSS_VAR'; +(var) return 'CSS_VAR'; ([a-z]+) return 'PREFIX'; "(" return 'LPAREN'; ")" return 'RPAREN'; +"," return 'COMMA'; <> return 'EOF'; @@ -67,8 +69,8 @@ expression | 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; } - | NESTED_CALC LPAREN math_expression RPAREN { $$ = $3; } - | SUB PREFIX SUB NESTED_CALC LPAREN math_expression RPAREN { $$ = $6; } + | NESTED_CALC LPAREN math_expression RPAREN { $$ = { type: 'Calc', value: $3 }; } + | SUB PREFIX SUB NESTED_CALC LPAREN math_expression RPAREN { $$ = { type: 'Calc', value: $6, prefix: $2 }; } | css_variable { $$ = $1; } | css_value { $$ = $1; } | value { $$ = $1; } @@ -80,7 +82,8 @@ expression ; css_variable - : CSS_VAR { $$ = { type: 'CssVariable', value: $1 }; } + : CSS_VAR LPAREN CSS_CPROP RPAREN { $$ = { type: 'CssVariable', value: $3 }; } + | CSS_VAR LPAREN CSS_CPROP COMMA math_expression RPAREN { $$ = { type: 'CssVariable', value: $3, fallback: $5 }; } ; css_value diff --git a/src/__tests__/index.js b/src/__tests__/index.js index ea6d3a3..e525b6d 100644 --- a/src/__tests__/index.js +++ b/src/__tests__/index.js @@ -168,6 +168,35 @@ test( 'calc(var(--popupHeight) / 2)' ) +test( + 'should ignore calc with css variables (7)', + testFixture, + 'calc(var(--popupHeight, var(--defaultHeight, var(--height-150))) / 2)', + 'calc(var(--popupHeight, var(--defaultHeight, var(--height-150))) / 2)' +) + +test( + 'should ignore calc with css variables (8)', + testFixture, + 'calc(var(--popupHeight, var(--defaultHeight, calc(100% - 50px))) / 2)', + 'calc(var(--popupHeight, var(--defaultHeight, calc(100% - 50px))) / 2)' +) + +test( + 'should ignore calc with css variables (9)', + testFixture, + 'calc(var(--popupHeight, var(--defaultHeight, calc(100% - 50px + 25px))) / 2)', + 'calc(var(--popupHeight, var(--defaultHeight, calc(100% - 25px))) / 2)' +) + +test( + 'should ignore calc with css variables (10)', + testFixture, + 'calc(var(--popupHeight, var(--defaultHeight, 150px)) / 2)', + 'calc(var(--popupHeight, var(--defaultHeight, 150px)) / 2)' +) + + test( 'should reduce calc with newline characters', testFixture, diff --git a/src/lib/reducer.js b/src/lib/reducer.js index 17ded8e..cea0634 100644 --- a/src/lib/reducer.js +++ b/src/lib/reducer.js @@ -3,6 +3,8 @@ import convert from './convert' function reduce(node, precision) { if (node.type === "MathExpression") return reduceMathExpression(node, precision) + if (node.type === "Calc") + return reduce(node.value, precision) return node } diff --git a/src/lib/stringifier.js b/src/lib/stringifier.js index 0c8b9ec..6d7d95c 100644 --- a/src/lib/stringifier.js +++ b/src/lib/stringifier.js @@ -28,22 +28,30 @@ function stringify(node, prec) { str += " " + node.operator + " " - if (right.type === 'MathExpression' && order[op] < order[right.operator]) + if (right.type === 'MathExpression' && order[op] < order[right.operator]) { str += "(" + stringify(right, prec) + ")" - else if (right.type === 'MathExpression' && op === "-" && ["+", "-"].includes(right.operator)) { + } else if (right.type === 'MathExpression' && op === "-" && ["+", "-"].includes(right.operator)) { // fix #52 : a-(b+c) = a-b-c right.operator = flip(right.operator); str += stringify(right, prec) - } - else + } else { str += stringify(right, prec) + } return str } case "Value": return round(node.value, prec) case 'CssVariable': - return node.value + if (node.fallback) { + return `var(${node.value}, ${stringify(node.fallback, prec, true)})` + } + return `var(${node.value})` + case 'Calc': + if (node.prefix) { + return `-${node.prefix}-calc(${stringify(node.value, prec)})`; + } + return `calc(${stringify(node.value, prec)})`; default: return round(node.value, prec) + node.unit }