@@ -8,7 +8,6 @@ var reduceFunctionCall = require("reduce-function-call")
88 * Constantes
99 */
1010var MAX_STACK = 100 // should be enough for a single calc()...
11- var DECIMAL_PRECISION = 100000 // 5 decimals
1211var NESTED_CALC_RE = / ( \+ | \- | \* | \\ | [ ^ a - z ] | ) ( \s * ) ( \( ) / g
1312
1413/**
@@ -28,103 +27,104 @@ module.exports = reduceCSSCalc
2827 *
2928 * @param {String } value css input
3029 */
31- function reduceCSSCalc ( value ) {
30+ function reduceCSSCalc ( value , decimalPrecision ) {
3231 stack = 0
33- return reduceFunctionCall ( value , / ( (?: \- [ a - z ] + \- ) ? c a l c ) \( / , evaluateExpression )
34- }
32+ decimalPrecision = Math . pow ( 10 , decimalPrecision === undefined ? 5 : decimalPrecision )
33+
34+ /**
35+ * Evaluates an expression
36+ *
37+ * @param {String } expression
38+ * @returns {String }
39+ */
40+ function evaluateExpression ( expression , functionIdentifier , call ) {
41+ if ( stack ++ > MAX_STACK ) {
42+ stack = 0
43+ throw new Error ( "Call stack overflow for " + call )
44+ }
3545
36- /**
37- * Evaluates an expression
38- *
39- * @param {String } expression
40- * @returns {String }
41- */
42- function evaluateExpression ( expression , functionIdentifier , call ) {
43- if ( stack ++ > MAX_STACK ) {
44- stack = 0
45- throw new Error ( "Call stack overflow for " + call )
46- }
46+ if ( expression === "" ) {
47+ throw new Error ( functionIdentifier + "(): '" + call + "' must contain a non-whitespace string" )
48+ }
4749
48- if ( expression === "" ) {
49- throw new Error ( functionIdentifier + "(): '" + call + "' must contain a non-whitespace string" )
50- }
50+ expression = evaluateNestedExpression ( expression , call )
5151
52- expression = evaluateNestedExpression ( expression , call )
52+ var units = getUnitsInExpression ( expression )
5353
54- var units = getUnitsInExpression ( expression )
54+ // If multiple units let the expression be (i.e. browser calc())
55+ if ( units . length > 1 ) {
56+ return functionIdentifier + "(" + expression + ")"
57+ }
5558
56- // If multiple units let the expression be (i.e. browser calc())
57- if ( units . length > 1 ) {
58- return functionIdentifier + "(" + expression + ")"
59- }
59+ var unit = units [ 0 ] || ""
6060
61- var unit = units [ 0 ] || ""
61+ if ( unit === "%" ) {
62+ // Convert percentages to numbers, to handle expressions like: 50% * 50% (will become: 25%):
63+ expression = expression . replace ( / \b [ 0 - 9 \. ] + % / g, function ( percent ) {
64+ return parseFloat ( percent . slice ( 0 , - 1 ) ) * 0.01
65+ } )
66+ }
6267
63- if ( unit === "%" ) {
64- // Convert percentages to numbers, to handle expressions like: 50% * 50% (will become: 25%):
65- expression = expression . replace ( / \b [ 0 - 9 \. ] + % / g, function ( percent ) {
66- return parseFloat ( percent . slice ( 0 , - 1 ) ) * 0.01
67- } )
68- }
68+ // Remove units in expression:
69+ var toEvaluate = expression . replace ( new RegExp ( unit , "g" ) , "" )
70+ var result
6971
70- // Remove units in expression:
71- var toEvaluate = expression . replace ( new RegExp ( unit , "g" ) , "" )
72- var result
72+ try {
73+ result = eval ( toEvaluate )
74+ }
75+ catch ( e ) {
76+ return functionIdentifier + "(" + expression + ")"
77+ }
7378
74- try {
75- result = eval ( toEvaluate )
76- }
77- catch ( e ) {
78- return functionIdentifier + "(" + expression + ")"
79- }
79+ // Transform back to a percentage result:
80+ if ( unit === "%" ) {
81+ result *= 100
82+ }
8083
81- // Transform back to a percentage result:
82- if ( unit === "%" ) {
83- result *= 100
84- }
84+ // adjust rounding shit
85+ // (0.1 * 0.2 === 0.020000000000000004)
86+ result = Math . round ( result * decimalPrecision ) / decimalPrecision
8587
86- // adjust rounding shit
87- // (0.1 * 0.2 === 0.020000000000000004)
88- result = Math . round ( result * DECIMAL_PRECISION ) / DECIMAL_PRECISION
88+ // We don't need units for zero values...
89+ if ( result !== 0 ) {
90+ result += unit
91+ }
8992
90- // We don't need units for zero values...
91- if ( result !== 0 ) {
92- result += unit
93+ return result
9394 }
9495
95- return result
96- }
97-
98- /**
99- * Evaluates nested expressions
100- *
101- * @param {String } expression
102- * @returns {String }
103- */
104- function evaluateNestedExpression ( expression , call ) {
105- var evaluatedPart = ""
106- var nonEvaluatedPart = expression
107- var matches
108- while ( ( matches = NESTED_CALC_RE . exec ( nonEvaluatedPart ) ) ) {
109- if ( matches [ 0 ] . index > 0 ) {
110- evaluatedPart += nonEvaluatedPart . substring ( 0 , matches [ 0 ] . index )
111- }
112-
113- var balancedExpr = balanced ( "(" , ")" , nonEvaluatedPart . substring ( [ 0 ] . index ) )
114- if ( balancedExpr . body === "" ) {
115- throw new Error ( "'" + expression + "' must contain a non-whitespace string" )
96+ /**
97+ * Evaluates nested expressions
98+ *
99+ * @param {String } expression
100+ * @returns {String }
101+ */
102+ function evaluateNestedExpression ( expression , call ) {
103+ var evaluatedPart = ""
104+ var nonEvaluatedPart = expression
105+ var matches
106+ while ( ( matches = NESTED_CALC_RE . exec ( nonEvaluatedPart ) ) ) {
107+ if ( matches [ 0 ] . index > 0 ) {
108+ evaluatedPart += nonEvaluatedPart . substring ( 0 , matches [ 0 ] . index )
109+ }
110+
111+ var balancedExpr = balanced ( "(" , ")" , nonEvaluatedPart . substring ( [ 0 ] . index ) )
112+ if ( balancedExpr . body === "" ) {
113+ throw new Error ( "'" + expression + "' must contain a non-whitespace string" )
114+ }
115+
116+ var evaluated = evaluateExpression ( balancedExpr . body , "" , call )
117+
118+ evaluatedPart += balancedExpr . pre + evaluated
119+ nonEvaluatedPart = balancedExpr . post
116120 }
117121
118- var evaluated = evaluateExpression ( balancedExpr . body , "" , call )
119-
120- evaluatedPart += balancedExpr . pre + evaluated
121- nonEvaluatedPart = balancedExpr . post
122+ return evaluatedPart + nonEvaluatedPart
122123 }
123124
124- return evaluatedPart + nonEvaluatedPart
125+ return reduceFunctionCall ( value , / ( (?: \- [ a - z ] + \- ) ? c a l c ) \( / , evaluateExpression )
125126}
126127
127-
128128/**
129129 * Checks what units are used in an expression
130130 *
0 commit comments