postcss-calc 7.0.4 → 7.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/lib/reducer.js +182 -228
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/dist/lib/reducer.js
CHANGED
|
@@ -9,10 +9,6 @@ var _convertUnit = _interopRequireDefault(require("./convertUnit"));
|
|
|
9
9
|
|
|
10
10
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
11
|
|
|
12
|
-
function isEqual(left, right) {
|
|
13
|
-
return left.type === right.type && left.value === right.value;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
12
|
function isValueType(type) {
|
|
17
13
|
switch (type) {
|
|
18
14
|
case 'LengthValue':
|
|
@@ -40,204 +36,132 @@ function flip(operator) {
|
|
|
40
36
|
return operator === '+' ? '-' : '+';
|
|
41
37
|
}
|
|
42
38
|
|
|
43
|
-
function
|
|
44
|
-
|
|
45
|
-
node.value = -node.value;
|
|
46
|
-
} else if (node.type === 'MathExpression') {
|
|
47
|
-
if (node.operator === '*' || node.operator === '/') {
|
|
48
|
-
node.left = flipValue(node.left);
|
|
49
|
-
} else {
|
|
50
|
-
node.left = flipValue(node.left);
|
|
51
|
-
node.right = flipValue(node.right);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return node;
|
|
39
|
+
function isAddSubOperator(operator) {
|
|
40
|
+
return operator === '+' || operator === '-';
|
|
56
41
|
}
|
|
57
42
|
|
|
58
|
-
function
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return node.left;
|
|
63
|
-
} // 0 + something => something
|
|
43
|
+
function collectAddSubItems(preOperator, node, collected, precision) {
|
|
44
|
+
if (!isAddSubOperator(preOperator)) {
|
|
45
|
+
throw new Error(`invalid operator ${preOperator}`);
|
|
46
|
+
}
|
|
64
47
|
|
|
48
|
+
var type = node.type;
|
|
65
49
|
|
|
66
|
-
if (isValueType(
|
|
67
|
-
|
|
68
|
-
|
|
50
|
+
if (isValueType(type)) {
|
|
51
|
+
var itemIndex = collected.findIndex(function (x) {
|
|
52
|
+
return x.node.type === type;
|
|
53
|
+
});
|
|
69
54
|
|
|
55
|
+
if (itemIndex >= 0) {
|
|
56
|
+
if (node.value === 0) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
70
59
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
// value - value
|
|
60
|
+
var _covertNodesUnits = covertNodesUnits(collected[itemIndex].node, node, precision),
|
|
61
|
+
reducedNode = _covertNodesUnits.left,
|
|
62
|
+
current = _covertNodesUnits.right;
|
|
75
63
|
|
|
64
|
+
if (collected[itemIndex].preOperator === '-') {
|
|
65
|
+
collected[itemIndex].preOperator = '+';
|
|
66
|
+
reducedNode.value *= -1;
|
|
67
|
+
}
|
|
76
68
|
|
|
77
|
-
|
|
78
|
-
|
|
69
|
+
if (preOperator === "+") {
|
|
70
|
+
reducedNode.value += current.value;
|
|
71
|
+
} else {
|
|
72
|
+
reducedNode.value -= current.value;
|
|
73
|
+
} // make sure reducedNode.value >= 0
|
|
79
74
|
|
|
80
|
-
var _covertNodesUnits = covertNodesUnits(node.left, node.right, precision),
|
|
81
|
-
left = _covertNodesUnits.left,
|
|
82
|
-
right = _covertNodesUnits.right;
|
|
83
75
|
|
|
84
|
-
|
|
85
|
-
|
|
76
|
+
if (reducedNode.value >= 0) {
|
|
77
|
+
collected[itemIndex] = {
|
|
78
|
+
node: reducedNode,
|
|
79
|
+
preOperator: '+'
|
|
80
|
+
};
|
|
81
|
+
} else {
|
|
82
|
+
reducedNode.value *= -1;
|
|
83
|
+
collected[itemIndex] = {
|
|
84
|
+
node: reducedNode,
|
|
85
|
+
preOperator: '-'
|
|
86
|
+
};
|
|
87
|
+
}
|
|
86
88
|
} else {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (node.right.type === 'MathExpression' && (node.right.operator === '+' || node.right.operator === '-')) {
|
|
95
|
-
// something - (something + something) => something - something - something
|
|
96
|
-
// something - (something - something) => something - something + something
|
|
97
|
-
if ((node.right.operator === '+' || node.right.operator === '-') && node.operator === '-') {
|
|
98
|
-
node.right.operator = flip(node.right.operator);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (isValueType(node.left.type)) {
|
|
102
|
-
// value + (value + something) => value + something
|
|
103
|
-
// value + (value - something) => value - something
|
|
104
|
-
// value - (value + something) => value - something
|
|
105
|
-
// value - (value - something) => value + something
|
|
106
|
-
if (node.left.type === node.right.left.type) {
|
|
107
|
-
var _left = node.left,
|
|
108
|
-
_operator = node.operator,
|
|
109
|
-
_right = node.right;
|
|
110
|
-
node.left = reduce({
|
|
111
|
-
type: 'MathExpression',
|
|
112
|
-
operator: _operator,
|
|
113
|
-
left: _left,
|
|
114
|
-
right: _right.left
|
|
89
|
+
// make sure node.value >= 0
|
|
90
|
+
if (node.value >= 0) {
|
|
91
|
+
collected.push({
|
|
92
|
+
node,
|
|
93
|
+
preOperator
|
|
115
94
|
});
|
|
116
|
-
|
|
117
|
-
node.
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
// something - (something + value) => dimension - something
|
|
122
|
-
// something - (something - value) => dimension - something
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (node.left.type === node.right.right.type) {
|
|
126
|
-
var _left2 = node.left,
|
|
127
|
-
_right2 = node.right;
|
|
128
|
-
node.left = reduce({
|
|
129
|
-
type: 'MathExpression',
|
|
130
|
-
operator: _right2.operator,
|
|
131
|
-
left: _left2,
|
|
132
|
-
right: _right2.right
|
|
95
|
+
} else {
|
|
96
|
+
node.value *= -1;
|
|
97
|
+
collected.push({
|
|
98
|
+
node,
|
|
99
|
+
preOperator: flip(preOperator)
|
|
133
100
|
});
|
|
134
|
-
node.right = _right2.left;
|
|
135
|
-
return reduce(node, precision);
|
|
136
101
|
}
|
|
137
102
|
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
_left3.left = reduce({
|
|
151
|
-
type: 'MathExpression',
|
|
152
|
-
operator: _operator2,
|
|
153
|
-
left: _left3.left,
|
|
154
|
-
right: _right3
|
|
155
|
-
}, precision);
|
|
156
|
-
return reduce(_left3, precision);
|
|
157
|
-
} // (something + dimension) + dimension => something + dimension
|
|
158
|
-
// (something - dimension) + dimension => something - dimension
|
|
159
|
-
// (something + dimension) - dimension => something + dimension
|
|
160
|
-
// (something - dimension) - dimension => something - dimension
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if (node.right.type === node.left.right.type) {
|
|
164
|
-
var _left4 = node.left,
|
|
165
|
-
_operator3 = node.operator,
|
|
166
|
-
_right4 = node.right;
|
|
167
|
-
|
|
168
|
-
if (_left4.operator === '-') {
|
|
169
|
-
_left4.operator = _operator3 === '-' ? '-' : '+';
|
|
170
|
-
_left4.right = reduce({
|
|
171
|
-
type: 'MathExpression',
|
|
172
|
-
operator: _operator3 === '-' ? '+' : '-',
|
|
173
|
-
left: _right4,
|
|
174
|
-
right: _left4.right
|
|
175
|
-
}, precision);
|
|
103
|
+
} else if (type === "MathExpression") {
|
|
104
|
+
if (isAddSubOperator(node.operator)) {
|
|
105
|
+
collectAddSubItems(preOperator, node.left, collected, precision);
|
|
106
|
+
var collectRightOperator = preOperator === '-' ? flip(node.operator) : node.operator;
|
|
107
|
+
collectAddSubItems(collectRightOperator, node.right, collected, precision);
|
|
108
|
+
} else {
|
|
109
|
+
// * or /
|
|
110
|
+
var _reducedNode = reduce(node, precision); // prevent infinite recursive call
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
if (_reducedNode.type !== "MathExpression" || isAddSubOperator(_reducedNode.operator)) {
|
|
114
|
+
collectAddSubItems(preOperator, _reducedNode, collected, precision);
|
|
176
115
|
} else {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
right: _right4
|
|
182
|
-
}, precision);
|
|
116
|
+
collected.push({
|
|
117
|
+
node: _reducedNode,
|
|
118
|
+
preOperator
|
|
119
|
+
});
|
|
183
120
|
}
|
|
121
|
+
}
|
|
122
|
+
} else {
|
|
123
|
+
collected.push({
|
|
124
|
+
node,
|
|
125
|
+
preOperator
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
184
129
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
130
|
+
function reduceAddSubExpression(node, precision) {
|
|
131
|
+
var collected = [];
|
|
132
|
+
collectAddSubItems('+', node, collected, precision);
|
|
133
|
+
var withoutZeroItem = collected.filter(function (item) {
|
|
134
|
+
return !(isValueType(item.node.type) && item.node.value === 0);
|
|
135
|
+
});
|
|
136
|
+
var firstNonZeroItem = withoutZeroItem[0]; // could be undefined
|
|
137
|
+
// prevent producing "calc(-var(--a))" or "calc()"
|
|
138
|
+
// which is invalid css
|
|
139
|
+
|
|
140
|
+
if (!firstNonZeroItem || firstNonZeroItem.preOperator === '-' && !isValueType(firstNonZeroItem.node.type)) {
|
|
141
|
+
var firstZeroItem = collected.find(function (item) {
|
|
142
|
+
return isValueType(item.node.type) && item.node.value === 0;
|
|
143
|
+
});
|
|
144
|
+
withoutZeroItem.unshift(firstZeroItem);
|
|
145
|
+
} // make sure the preOperator of the first item is +
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
if (withoutZeroItem[0].preOperator === '-' && isValueType(withoutZeroItem[0].node.type)) {
|
|
149
|
+
withoutZeroItem[0].node.value *= -1;
|
|
150
|
+
withoutZeroItem[0].preOperator = '+';
|
|
151
|
+
}
|
|
189
152
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
// (expr1 - something) + (expr2 + something) => expr1 + expr2
|
|
200
|
-
// (expr1 + something) + (expr2 - something) => expr1 + expr2
|
|
201
|
-
// (expr1 - something) - (expr2 + something) => expr1 + expr2
|
|
202
|
-
// (expr1 + something) - (expr2 - something) => expr1 + expr2
|
|
203
|
-
if (isEqual(node.left.right, node.right.right)) {
|
|
204
|
-
var newNodes = covertNodesUnits(node.left.left, node.right.left, precision);
|
|
205
|
-
node.left = newNodes.left;
|
|
206
|
-
node.right = newNodes.right;
|
|
207
|
-
return reduce(node, precision);
|
|
208
|
-
} // (expr1 - something) + (something + expr2) => expr1 + expr2
|
|
209
|
-
// (expr1 + something) + (something - expr2) => expr1 + expr2
|
|
210
|
-
// (expr1 - something) - (something + expr2) => expr1 + expr2
|
|
211
|
-
// (expr1 + something) - (something - expr2) => expr1 + expr2
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
if (isEqual(node.left.right, node.right.left)) {
|
|
215
|
-
var _newNodes = covertNodesUnits(node.left.left, node.right.right, precision);
|
|
216
|
-
|
|
217
|
-
node.left = _newNodes.left;
|
|
218
|
-
node.right = _newNodes.right;
|
|
219
|
-
return reduce(node, precision);
|
|
220
|
-
} // (expr1 / something) + (expr2 / something) => (expr1 + expr2) / something
|
|
221
|
-
// (expr1 * something) + (expr2 * something) => (expr1 + expr2) * something
|
|
222
|
-
// (expr1 / something) - (expr2 / something) => (expr1 - expr2) / something
|
|
223
|
-
// (expr1 * something) - (expr2 * something) => (expr1 - expr2) * something
|
|
224
|
-
|
|
225
|
-
} else if ((node.left.operator === "/" || node.left.operator === "*") && node.left.operator === node.right.operator && isEqual(node.left.right, node.right.right)) {
|
|
226
|
-
return reduce({
|
|
227
|
-
type: "MathExpression",
|
|
228
|
-
operator: node.left.operator,
|
|
229
|
-
left: {
|
|
230
|
-
type: "MathExpression",
|
|
231
|
-
operator: node.operator,
|
|
232
|
-
left: node.left.left,
|
|
233
|
-
right: node.right.left
|
|
234
|
-
},
|
|
235
|
-
right: node.left.right
|
|
236
|
-
}, precision);
|
|
237
|
-
}
|
|
153
|
+
var root = withoutZeroItem[0].node;
|
|
154
|
+
|
|
155
|
+
for (var i = 1; i < withoutZeroItem.length; i++) {
|
|
156
|
+
root = {
|
|
157
|
+
type: 'MathExpression',
|
|
158
|
+
operator: withoutZeroItem[i].preOperator,
|
|
159
|
+
left: root,
|
|
160
|
+
right: withoutZeroItem[i].node
|
|
161
|
+
};
|
|
238
162
|
}
|
|
239
163
|
|
|
240
|
-
return
|
|
164
|
+
return root;
|
|
241
165
|
}
|
|
242
166
|
|
|
243
167
|
function reduceDivisionExpression(node) {
|
|
@@ -249,51 +173,93 @@ function reduceDivisionExpression(node) {
|
|
|
249
173
|
throw new Error(`Cannot divide by "${node.right.unit}", number expected`);
|
|
250
174
|
}
|
|
251
175
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
} // something / value
|
|
176
|
+
return applyNumberDivision(node.left, node.right.value);
|
|
177
|
+
} // apply (expr) / number
|
|
255
178
|
|
|
256
179
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
180
|
+
function applyNumberDivision(node, divisor) {
|
|
181
|
+
if (divisor === 0) {
|
|
182
|
+
throw new Error('Cannot divide by zero');
|
|
260
183
|
}
|
|
261
184
|
|
|
262
|
-
|
|
185
|
+
if (isValueType(node.type)) {
|
|
186
|
+
node.value /= divisor;
|
|
187
|
+
return node;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (node.type === "MathExpression" && isAddSubOperator(node.operator)) {
|
|
191
|
+
// turn (a + b) / num into a/num + b/num
|
|
192
|
+
// is good for further reduction
|
|
193
|
+
// checkout the test case
|
|
194
|
+
// "should reduce division before reducing additions"
|
|
195
|
+
return {
|
|
196
|
+
type: "MathExpression",
|
|
197
|
+
operator: node.operator,
|
|
198
|
+
left: applyNumberDivision(node.left, divisor),
|
|
199
|
+
right: applyNumberDivision(node.right, divisor)
|
|
200
|
+
};
|
|
201
|
+
} // it is impossible to reduce it into a single value
|
|
202
|
+
// .e.g the node contains css variable
|
|
203
|
+
// so we just preserve the division and let browser do it
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
type: "MathExpression",
|
|
208
|
+
operator: '/',
|
|
209
|
+
left: node,
|
|
210
|
+
right: {
|
|
211
|
+
type: "Number",
|
|
212
|
+
value: divisor
|
|
213
|
+
}
|
|
214
|
+
};
|
|
263
215
|
}
|
|
264
216
|
|
|
265
217
|
function reduceMultiplicationExpression(node) {
|
|
266
218
|
// (expr) * number
|
|
267
|
-
if (node.
|
|
268
|
-
|
|
269
|
-
node.left.left.value *= node.right.value;
|
|
270
|
-
node.left.right.value *= node.right.value;
|
|
271
|
-
return node.left;
|
|
272
|
-
}
|
|
273
|
-
} // something * number
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
if (isValueType(node.left.type) && node.right.type === 'Number') {
|
|
277
|
-
node.left.value *= node.right.value;
|
|
278
|
-
return node.left;
|
|
219
|
+
if (node.right.type === 'Number') {
|
|
220
|
+
return applyNumberMultiplication(node.left, node.right.value);
|
|
279
221
|
} // number * (expr)
|
|
280
222
|
|
|
281
223
|
|
|
282
|
-
if (node.left.type === 'Number'
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
} // number * something
|
|
224
|
+
if (node.left.type === 'Number') {
|
|
225
|
+
return applyNumberMultiplication(node.right, node.left.value);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return node;
|
|
229
|
+
} // apply (expr) / number
|
|
289
230
|
|
|
290
231
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
232
|
+
function applyNumberMultiplication(node, multiplier) {
|
|
233
|
+
if (isValueType(node.type)) {
|
|
234
|
+
node.value *= multiplier;
|
|
235
|
+
return node;
|
|
294
236
|
}
|
|
295
237
|
|
|
296
|
-
|
|
238
|
+
if (node.type === "MathExpression" && isAddSubOperator(node.operator)) {
|
|
239
|
+
// turn (a + b) * num into a*num + b*num
|
|
240
|
+
// is good for further reduction
|
|
241
|
+
// checkout the test case
|
|
242
|
+
// "should reduce multiplication before reducing additions"
|
|
243
|
+
return {
|
|
244
|
+
type: "MathExpression",
|
|
245
|
+
operator: node.operator,
|
|
246
|
+
left: applyNumberMultiplication(node.left, multiplier),
|
|
247
|
+
right: applyNumberMultiplication(node.right, multiplier)
|
|
248
|
+
};
|
|
249
|
+
} // it is impossible to reduce it into a single value
|
|
250
|
+
// .e.g the node contains css variable
|
|
251
|
+
// so we just preserve the division and let browser do it
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
type: "MathExpression",
|
|
256
|
+
operator: '*',
|
|
257
|
+
left: node,
|
|
258
|
+
right: {
|
|
259
|
+
type: "Number",
|
|
260
|
+
value: multiplier
|
|
261
|
+
}
|
|
262
|
+
};
|
|
297
263
|
}
|
|
298
264
|
|
|
299
265
|
function covertNodesUnits(left, right, precision) {
|
|
@@ -327,14 +293,15 @@ function covertNodesUnits(left, right, precision) {
|
|
|
327
293
|
|
|
328
294
|
function reduce(node, precision) {
|
|
329
295
|
if (node.type === "MathExpression") {
|
|
296
|
+
if (isAddSubOperator(node.operator)) {
|
|
297
|
+
// reduceAddSubExpression will call reduce recursively
|
|
298
|
+
return reduceAddSubExpression(node, precision);
|
|
299
|
+
}
|
|
300
|
+
|
|
330
301
|
node.left = reduce(node.left, precision);
|
|
331
302
|
node.right = reduce(node.right, precision);
|
|
332
303
|
|
|
333
304
|
switch (node.operator) {
|
|
334
|
-
case "+":
|
|
335
|
-
case "-":
|
|
336
|
-
return reduceAddSubExpression(node, precision);
|
|
337
|
-
|
|
338
305
|
case "/":
|
|
339
306
|
return reduceDivisionExpression(node, precision);
|
|
340
307
|
|
|
@@ -350,17 +317,4 @@ function reduce(node, precision) {
|
|
|
350
317
|
|
|
351
318
|
var _default = reduce;
|
|
352
319
|
exports.default = _default;
|
|
353
|
-
|
|
354
|
-
function isCSSFunction(node) {
|
|
355
|
-
if (node.type === "Function") {
|
|
356
|
-
return true;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
if (node.type === "MathExpression") {
|
|
360
|
-
return isCSSFunction(node.left) || isCSSFunction(node.right);
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
return false;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
320
|
module.exports = exports.default;
|