postcss-calc 7.0.4 → 8.2.0

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/dist/index.js CHANGED
@@ -5,38 +5,60 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.default = void 0;
7
7
 
8
- var _postcss = require("postcss");
9
-
10
8
  var _transform = _interopRequireDefault(require("./lib/transform"));
11
9
 
12
10
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
11
 
14
- var _default = (0, _postcss.plugin)('postcss-calc', function (opts) {
15
- var options = Object.assign({
12
+ /**
13
+ * @typedef {{precision?: number | false,
14
+ * preserve?: boolean,
15
+ * warnWhenCannotResolve?: boolean,
16
+ * mediaQueries?: boolean,
17
+ * selectors?: boolean}} PostCssCalcOptions
18
+ *
19
+ * @param {PostCssCalcOptions} opts
20
+ */
21
+ function pluginCreator(opts) {
22
+ const options = Object.assign({
16
23
  precision: 5,
17
24
  preserve: false,
18
25
  warnWhenCannotResolve: false,
19
26
  mediaQueries: false,
20
27
  selectors: false
21
28
  }, opts);
22
- return function (css, result) {
23
- css.walk(function (node) {
24
- var type = node.type;
25
-
26
- if (type === 'decl') {
27
- (0, _transform.default)(node, "value", options, result);
28
- }
29
-
30
- if (type === 'atrule' && options.mediaQueries) {
31
- (0, _transform.default)(node, "params", options, result);
32
- }
33
-
34
- if (type === 'rule' && options.selectors) {
35
- (0, _transform.default)(node, "selector", options, result);
36
- }
37
- });
29
+ return {
30
+ postcssPlugin: 'postcss-calc',
31
+
32
+ /**
33
+ * @param {import('postcss').Root} css
34
+ * @param {{result: import('postcss').Result}} helpers
35
+ */
36
+ OnceExit(css, {
37
+ result
38
+ }) {
39
+ css.walk(node => {
40
+ const {
41
+ type
42
+ } = node;
43
+
44
+ if (type === 'decl') {
45
+ (0, _transform.default)(node, "value", options, result);
46
+ }
47
+
48
+ if (type === 'atrule' && options.mediaQueries) {
49
+ (0, _transform.default)(node, "params", options, result);
50
+ }
51
+
52
+ if (type === 'rule' && options.selectors) {
53
+ (0, _transform.default)(node, "selector", options, result);
54
+ }
55
+ });
56
+ }
57
+
38
58
  };
39
- });
59
+ }
40
60
 
61
+ pluginCreator.postcss = true;
62
+ var _default = pluginCreator;
41
63
  exports.default = _default;
42
64
  module.exports = exports.default;
@@ -4,7 +4,11 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var conversions = {
7
+
8
+ /**
9
+ * @type {{[key:string]: {[key:string]: number}}}
10
+ */
11
+ const conversions = {
8
12
  // Absolute length units
9
13
  'px': {
10
14
  'px': 1,
@@ -129,10 +133,16 @@ var conversions = {
129
133
  'dppx': 1
130
134
  }
131
135
  };
136
+ /**
137
+ * @param {number} value
138
+ * @param {string} sourceUnit
139
+ * @param {string} targetUnit
140
+ * @param {number|false} precision
141
+ */
132
142
 
133
143
  function convertUnit(value, sourceUnit, targetUnit, precision) {
134
- var sourceUnitNormalized = sourceUnit.toLowerCase();
135
- var targetUnitNormalized = targetUnit.toLowerCase();
144
+ const sourceUnitNormalized = sourceUnit.toLowerCase();
145
+ const targetUnitNormalized = targetUnit.toLowerCase();
136
146
 
137
147
  if (!conversions[targetUnitNormalized]) {
138
148
  throw new Error("Cannot convert to " + targetUnit);
@@ -142,10 +152,10 @@ function convertUnit(value, sourceUnit, targetUnit, precision) {
142
152
  throw new Error("Cannot convert from " + sourceUnit + " to " + targetUnit);
143
153
  }
144
154
 
145
- var converted = conversions[targetUnitNormalized][sourceUnitNormalized] * value;
155
+ const converted = conversions[targetUnitNormalized][sourceUnitNormalized] * value;
146
156
 
147
157
  if (precision !== false) {
148
- precision = Math.pow(10, parseInt(precision) || 5);
158
+ precision = Math.pow(10, Math.ceil(precision) || 5);
149
159
  return Math.round(converted * precision) / precision;
150
160
  }
151
161
 
@@ -9,12 +9,12 @@ 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
- function isValueType(type) {
17
- switch (type) {
12
+ /**
13
+ * @param {import('../parser').CalcNode} node
14
+ * @return {node is import('../parser').ValueExpression}
15
+ */
16
+ function isValueType(node) {
17
+ switch (node.type) {
18
18
  case 'LengthValue':
19
19
  case 'AngleValue':
20
20
  case 'TimeValue':
@@ -35,213 +35,168 @@ function isValueType(type) {
35
35
 
36
36
  return false;
37
37
  }
38
+ /** @param {'-'|'+'} operator */
39
+
38
40
 
39
41
  function flip(operator) {
40
42
  return operator === '+' ? '-' : '+';
41
43
  }
44
+ /**
45
+ * @param {string} operator
46
+ * @returns {operator is '+'|'-'}
47
+ */
42
48
 
43
- function flipValue(node) {
44
- if (isValueType(node.type)) {
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
49
 
55
- return node;
50
+ function isAddSubOperator(operator) {
51
+ return operator === '+' || operator === '-';
56
52
  }
53
+ /**
54
+ * @typedef {{preOperator: '+'|'-', node: import('../parser').CalcNode}} Collectible
55
+ */
57
56
 
58
- function reduceAddSubExpression(node, precision) {
59
- // something + 0 => something
60
- // something - 0 => something
61
- if (isValueType(node.right.type) && node.right.value === 0) {
62
- return node.left;
63
- } // 0 + something => something
64
-
57
+ /**
58
+ * @param {'+'|'-'} preOperator
59
+ * @param {import('../parser').CalcNode} node
60
+ * @param {Collectible[]} collected
61
+ * @param {number} precision
62
+ */
65
63
 
66
- if (isValueType(node.left.type) && node.left.value === 0 && node.operator === "+") {
67
- return node.right;
68
- } // 0 - something => -something
69
64
 
65
+ function collectAddSubItems(preOperator, node, collected, precision) {
66
+ if (!isAddSubOperator(preOperator)) {
67
+ throw new Error(`invalid operator ${preOperator}`);
68
+ }
70
69
 
71
- if (isValueType(node.left.type) && node.left.value === 0 && node.operator === "-" && !isCSSFunction(node.right)) {
72
- return flipValue(node.right);
73
- } // value + value
74
- // value - value
70
+ if (isValueType(node)) {
71
+ const itemIndex = collected.findIndex(x => x.node.type === node.type);
75
72
 
73
+ if (itemIndex >= 0) {
74
+ if (node.value === 0) {
75
+ return;
76
+ } // can cast because of the criterion used to find itemIndex
76
77
 
77
- if (isValueType(node.left.type) && node.left.type === node.right.type) {
78
- var operator = node.operator;
79
78
 
80
- var _covertNodesUnits = covertNodesUnits(node.left, node.right, precision),
81
- left = _covertNodesUnits.left,
82
- right = _covertNodesUnits.right;
79
+ const otherValueNode =
80
+ /** @type import('../parser').ValueExpression*/
81
+ collected[itemIndex].node;
82
+ const {
83
+ left: reducedNode,
84
+ right: current
85
+ } = convertNodesUnits(otherValueNode, node, precision);
83
86
 
84
- if (operator === "+") {
85
- left.value += right.value;
86
- } else {
87
- left.value -= right.value;
88
- }
89
-
90
- return left;
91
- } // value <op> (expr)
87
+ if (collected[itemIndex].preOperator === '-') {
88
+ collected[itemIndex].preOperator = '+';
89
+ reducedNode.value *= -1;
90
+ }
92
91
 
92
+ if (preOperator === "+") {
93
+ reducedNode.value += current.value;
94
+ } else {
95
+ reducedNode.value -= current.value;
96
+ } // make sure reducedNode.value >= 0
93
97
 
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
98
 
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
99
+ if (reducedNode.value >= 0) {
100
+ collected[itemIndex] = {
101
+ node: reducedNode,
102
+ preOperator: '+'
103
+ };
104
+ } else {
105
+ reducedNode.value *= -1;
106
+ collected[itemIndex] = {
107
+ node: reducedNode,
108
+ preOperator: '-'
109
+ };
110
+ }
111
+ } else {
112
+ // make sure node.value >= 0
113
+ if (node.value >= 0) {
114
+ collected.push({
115
+ node,
116
+ preOperator
115
117
  });
116
- node.operator = _right.operator;
117
- node.right = _right.right;
118
- return reduce(node, precision);
119
- } // something + (something + value) => dimension + something
120
- // something + (something - value) => dimension + something
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
118
+ } else {
119
+ node.value *= -1;
120
+ collected.push({
121
+ node,
122
+ preOperator: flip(preOperator)
133
123
  });
134
- node.right = _right2.left;
135
- return reduce(node, precision);
136
124
  }
137
125
  }
138
- } // (expr) <op> value
139
-
140
-
141
- if (node.left.type === 'MathExpression' && (node.left.operator === '+' || node.left.operator === '-') && isValueType(node.right.type)) {
142
- // (value + something) + value => value + something
143
- // (value - something) + value => value - something
144
- // (value + something) - value => value + something
145
- // (value - something) - value => value - something
146
- if (node.right.type === node.left.left.type) {
147
- var _left3 = node.left,
148
- _operator2 = node.operator,
149
- _right3 = node.right;
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);
126
+ } else if (node.type === "MathExpression") {
127
+ if (isAddSubOperator(node.operator)) {
128
+ collectAddSubItems(preOperator, node.left, collected, precision);
129
+ const collectRightOperator = preOperator === '-' ? flip(node.operator) : node.operator;
130
+ collectAddSubItems(collectRightOperator, node.right, collected, precision);
131
+ } else {
132
+ // * or /
133
+ const reducedNode = reduce(node, precision); // prevent infinite recursive call
134
+
135
+ if (reducedNode.type !== "MathExpression" || isAddSubOperator(reducedNode.operator)) {
136
+ collectAddSubItems(preOperator, reducedNode, collected, precision);
176
137
  } else {
177
- _left4.right = reduce({
178
- type: 'MathExpression',
179
- operator: _operator3,
180
- left: _left4.right,
181
- right: _right4
182
- }, precision);
138
+ collected.push({
139
+ node: reducedNode,
140
+ preOperator
141
+ });
183
142
  }
143
+ }
144
+ } else {
145
+ collected.push({
146
+ node,
147
+ preOperator
148
+ });
149
+ }
150
+ }
151
+ /**
152
+ * @param {import('../parser').CalcNode} node
153
+ * @param {number} precision
154
+ */
184
155
 
185
- if (_left4.right.value < 0) {
186
- _left4.right.value *= -1;
187
- _left4.operator = _left4.operator === '-' ? '+' : '-';
188
- }
189
156
 
190
- _left4.parenthesized = node.parenthesized;
191
- return reduce(_left4, precision);
192
- }
193
- } // (expr) + (expr) => number
194
- // (expr) - (expr) => number
195
-
196
-
197
- if (node.right.type === 'MathExpression' && node.left.type === 'MathExpression') {
198
- if (node.left.operator === "-" && node.right.operator === "+" || node.right.operator === "-" && node.left.operator === "+") {
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);
157
+ function reduceAddSubExpression(node, precision) {
158
+ /** @type Collectible[] */
159
+ const collected = [];
160
+ collectAddSubItems('+', node, collected, precision);
161
+ const withoutZeroItem = collected.filter(item => !(isValueType(item.node) && item.node.value === 0));
162
+ const firstNonZeroItem = withoutZeroItem[0]; // could be undefined
163
+ // prevent producing "calc(-var(--a))" or "calc()"
164
+ // which is invalid css
165
+
166
+ if (!firstNonZeroItem || firstNonZeroItem.preOperator === '-' && !isValueType(firstNonZeroItem.node)) {
167
+ const firstZeroItem = collected.find(item => isValueType(item.node) && item.node.value === 0);
168
+
169
+ if (firstZeroItem) {
170
+ withoutZeroItem.unshift(firstZeroItem);
237
171
  }
172
+ } // make sure the preOperator of the first item is +
173
+
174
+
175
+ if (withoutZeroItem[0].preOperator === '-' && isValueType(withoutZeroItem[0].node)) {
176
+ withoutZeroItem[0].node.value *= -1;
177
+ withoutZeroItem[0].preOperator = '+';
238
178
  }
239
179
 
240
- return node;
180
+ let root = withoutZeroItem[0].node;
181
+
182
+ for (let i = 1; i < withoutZeroItem.length; i++) {
183
+ root = {
184
+ type: 'MathExpression',
185
+ operator: withoutZeroItem[i].preOperator,
186
+ left: root,
187
+ right: withoutZeroItem[i].node
188
+ };
189
+ }
190
+
191
+ return root;
241
192
  }
193
+ /**
194
+ * @param {import('../parser').MathExpression} node
195
+ */
196
+
242
197
 
243
198
  function reduceDivisionExpression(node) {
244
- if (!isValueType(node.right.type)) {
199
+ if (!isValueType(node.right)) {
245
200
  return node;
246
201
  }
247
202
 
@@ -249,54 +204,119 @@ function reduceDivisionExpression(node) {
249
204
  throw new Error(`Cannot divide by "${node.right.unit}", number expected`);
250
205
  }
251
206
 
252
- if (node.right.value === 0) {
253
- throw new Error('Cannot divide by zero');
254
- } // something / value
207
+ return applyNumberDivision(node.left, node.right.value);
208
+ }
209
+ /**
210
+ * apply (expr) / number
211
+ *
212
+ * @param {import('../parser').CalcNode} node
213
+ * @param {number} divisor
214
+ * @return {import('../parser').CalcNode}
215
+ */
255
216
 
256
217
 
257
- if (isValueType(node.left.type)) {
258
- node.left.value /= node.right.value;
259
- return node.left;
218
+ function applyNumberDivision(node, divisor) {
219
+ if (divisor === 0) {
220
+ throw new Error('Cannot divide by zero');
260
221
  }
261
222
 
262
- return node;
263
- }
223
+ if (isValueType(node)) {
224
+ node.value /= divisor;
225
+ return node;
226
+ }
264
227
 
265
- function reduceMultiplicationExpression(node) {
266
- // (expr) * number
267
- if (node.left.type === 'MathExpression' && node.right.type === 'Number') {
268
- if (isValueType(node.left.left.type) && isValueType(node.left.right.type)) {
269
- node.left.left.value *= node.right.value;
270
- node.left.right.value *= node.right.value;
271
- return node.left;
228
+ if (node.type === "MathExpression" && isAddSubOperator(node.operator)) {
229
+ // turn (a + b) / num into a/num + b/num
230
+ // is good for further reduction
231
+ // checkout the test case
232
+ // "should reduce division before reducing additions"
233
+ return {
234
+ type: "MathExpression",
235
+ operator: node.operator,
236
+ left: applyNumberDivision(node.left, divisor),
237
+ right: applyNumberDivision(node.right, divisor)
238
+ };
239
+ } // it is impossible to reduce it into a single value
240
+ // .e.g the node contains css variable
241
+ // so we just preserve the division and let browser do it
242
+
243
+
244
+ return {
245
+ type: "MathExpression",
246
+ operator: '/',
247
+ left: node,
248
+ right: {
249
+ type: "Number",
250
+ value: divisor
272
251
  }
273
- } // something * number
252
+ };
253
+ }
254
+ /**
255
+ * @param {import('../parser').MathExpression} node
256
+ */
274
257
 
275
258
 
276
- if (isValueType(node.left.type) && node.right.type === 'Number') {
277
- node.left.value *= node.right.value;
278
- return node.left;
259
+ function reduceMultiplicationExpression(node) {
260
+ // (expr) * number
261
+ if (node.right.type === 'Number') {
262
+ return applyNumberMultiplication(node.left, node.right.value);
279
263
  } // number * (expr)
280
264
 
281
265
 
282
- if (node.left.type === 'Number' && node.right.type === 'MathExpression') {
283
- if (isValueType(node.right.left.type) && isValueType(node.right.right.type)) {
284
- node.right.left.value *= node.left.value;
285
- node.right.right.value *= node.left.value;
286
- return node.right;
287
- }
288
- } // number * something
266
+ if (node.left.type === 'Number') {
267
+ return applyNumberMultiplication(node.right, node.left.value);
268
+ }
269
+
270
+ return node;
271
+ }
272
+ /**
273
+ * apply (expr) * number
274
+ * @param {number} multiplier
275
+ * @param {import('../parser').CalcNode} node
276
+ * @return {import('../parser').CalcNode}
277
+ */
289
278
 
290
279
 
291
- if (node.left.type === 'Number' && isValueType(node.right.type)) {
292
- node.right.value *= node.left.value;
293
- return node.right;
280
+ function applyNumberMultiplication(node, multiplier) {
281
+ if (isValueType(node)) {
282
+ node.value *= multiplier;
283
+ return node;
294
284
  }
295
285
 
296
- return node;
286
+ if (node.type === "MathExpression" && isAddSubOperator(node.operator)) {
287
+ // turn (a + b) * num into a*num + b*num
288
+ // is good for further reduction
289
+ // checkout the test case
290
+ // "should reduce multiplication before reducing additions"
291
+ return {
292
+ type: "MathExpression",
293
+ operator: node.operator,
294
+ left: applyNumberMultiplication(node.left, multiplier),
295
+ right: applyNumberMultiplication(node.right, multiplier)
296
+ };
297
+ } // it is impossible to reduce it into a single value
298
+ // .e.g the node contains css variable
299
+ // so we just preserve the division and let browser do it
300
+
301
+
302
+ return {
303
+ type: "MathExpression",
304
+ operator: '*',
305
+ left: node,
306
+ right: {
307
+ type: "Number",
308
+ value: multiplier
309
+ }
310
+ };
297
311
  }
312
+ /**
313
+ * @param {import('../parser').ValueExpression} left
314
+ * @param {import('../parser').ValueExpression} right
315
+ * @param {number} precision
316
+ */
317
+
298
318
 
299
- function covertNodesUnits(left, right, precision) {
319
+ function convertNodesUnits(left, right, precision) {
300
320
  switch (left.type) {
301
321
  case 'LengthValue':
302
322
  case 'AngleValue':
@@ -304,7 +324,7 @@ function covertNodesUnits(left, right, precision) {
304
324
  case 'FrequencyValue':
305
325
  case 'ResolutionValue':
306
326
  if (right.type === left.type && right.unit && left.unit) {
307
- var converted = (0, _convertUnit.default)(right.value, right.unit, left.unit, precision);
327
+ const converted = (0, _convertUnit.default)(right.value, right.unit, left.unit, precision);
308
328
  right = {
309
329
  type: left.type,
310
330
  value: converted,
@@ -324,22 +344,28 @@ function covertNodesUnits(left, right, precision) {
324
344
  };
325
345
  }
326
346
  }
347
+ /**
348
+ * @param {import('../parser').CalcNode} node
349
+ * @param {number} precision
350
+ */
351
+
327
352
 
328
353
  function reduce(node, precision) {
329
354
  if (node.type === "MathExpression") {
355
+ if (isAddSubOperator(node.operator)) {
356
+ // reduceAddSubExpression will call reduce recursively
357
+ return reduceAddSubExpression(node, precision);
358
+ }
359
+
330
360
  node.left = reduce(node.left, precision);
331
361
  node.right = reduce(node.right, precision);
332
362
 
333
363
  switch (node.operator) {
334
- case "+":
335
- case "-":
336
- return reduceAddSubExpression(node, precision);
337
-
338
364
  case "/":
339
- return reduceDivisionExpression(node, precision);
365
+ return reduceDivisionExpression(node);
340
366
 
341
367
  case "*":
342
- return reduceMultiplicationExpression(node, precision);
368
+ return reduceMultiplicationExpression(node);
343
369
  }
344
370
 
345
371
  return node;
@@ -350,17 +376,4 @@ function reduce(node, precision) {
350
376
 
351
377
  var _default = reduce;
352
378
  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
379
  module.exports = exports.default;
@@ -4,30 +4,41 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = _default;
7
- var order = {
7
+ const order = {
8
8
  "*": 0,
9
9
  "/": 0,
10
10
  "+": 1,
11
11
  "-": 1
12
12
  };
13
+ /**
14
+ * @param {number} value
15
+ * @param {number | false} prec
16
+ */
13
17
 
14
18
  function round(value, prec) {
15
19
  if (prec !== false) {
16
- var precision = Math.pow(10, prec);
20
+ const precision = Math.pow(10, prec);
17
21
  return Math.round(value * precision) / precision;
18
22
  }
19
23
 
20
24
  return value;
21
25
  }
26
+ /**
27
+ * @param {number | false} prec
28
+ * @param {import('../parser').CalcNode} node
29
+ */
30
+
22
31
 
23
32
  function stringify(node, prec) {
24
33
  switch (node.type) {
25
34
  case "MathExpression":
26
35
  {
27
- var left = node.left,
28
- right = node.right,
29
- op = node.operator;
30
- var str = "";
36
+ const {
37
+ left,
38
+ right,
39
+ operator: op
40
+ } = node;
41
+ let str = "";
31
42
 
32
43
  if (left.type === 'MathExpression' && order[op] < order[left.operator]) {
33
44
  str += `(${stringify(left, prec)})`;
@@ -47,19 +58,30 @@ function stringify(node, prec) {
47
58
  }
48
59
 
49
60
  case 'Number':
50
- return round(node.value, prec);
61
+ return round(node.value, prec).toString();
51
62
 
52
63
  case 'Function':
53
- return node.value;
64
+ return node.value.toString();
54
65
 
55
66
  default:
56
67
  return round(node.value, prec) + node.unit;
57
68
  }
58
69
  }
70
+ /**
71
+ * @param {string} calc
72
+ * @param {import('../parser').CalcNode} node
73
+ * @param {string} originalValue
74
+ * @param {{precision: number | false, warnWhenCannotResolve: boolean}} options
75
+ * @param {import("postcss").Result} result
76
+ * @param {import("postcss").ChildNode} item
77
+ *
78
+ * @returns {string}
79
+ */
80
+
59
81
 
60
82
  function _default(calc, node, originalValue, options, result, item) {
61
- var str = stringify(node, options.precision);
62
- var shouldPrintCalc = node.type === "MathExpression" || node.type === "Function";
83
+ let str = stringify(node, options.precision);
84
+ const shouldPrintCalc = node.type === "MathExpression" || node.type === "Function";
63
85
 
64
86
  if (shouldPrintCalc) {
65
87
  // if calc expression couldn't be resolved to a single value, re-wrap it as
@@ -18,42 +18,56 @@ var _stringifier = _interopRequireDefault(require("./stringifier"));
18
18
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
19
19
 
20
20
  // eslint-disable-next-line import/no-unresolved
21
- var MATCH_CALC = /((?:-(moz|webkit)-)?calc)/i;
21
+ const MATCH_CALC = /((?:-(moz|webkit)-)?calc)/i;
22
+ /**
23
+ * @param {string} value
24
+ * @param {{precision: number, warnWhenCannotResolve: boolean}} options
25
+ * @param {import("postcss").Result} result
26
+ * @param {import("postcss").ChildNode} item
27
+ */
22
28
 
23
29
  function transformValue(value, options, result, item) {
24
- return (0, _postcssValueParser.default)(value).walk(function (node) {
30
+ return (0, _postcssValueParser.default)(value).walk(node => {
25
31
  // skip anything which isn't a calc() function
26
- if (node.type !== 'function' || !MATCH_CALC.test(node.value)) {
27
- return node;
32
+ if (node.type !== "function" || !MATCH_CALC.test(node.value)) {
33
+ return;
28
34
  } // stringify calc expression and produce an AST
29
35
 
30
36
 
31
- var contents = _postcssValueParser.default.stringify(node.nodes);
37
+ const contents = _postcssValueParser.default.stringify(node.nodes);
32
38
 
33
- var ast = _parser.parser.parse(contents); // reduce AST to its simplest form, that is, either to a single value
39
+ const ast = _parser.parser.parse(contents); // reduce AST to its simplest form, that is, either to a single value
34
40
  // or a simplified calc expression
35
41
 
36
42
 
37
- var reducedAst = (0, _reducer.default)(ast, options.precision); // stringify AST and write it back
43
+ const reducedAst = (0, _reducer.default)(ast, options.precision); // stringify AST and write it back
38
44
 
39
- node.type = 'word';
45
+ /** @type {valueParser.Node} */
46
+ node.type = "word";
40
47
  node.value = (0, _stringifier.default)(node.value, reducedAst, value, options, result, item);
41
48
  return false;
42
49
  }).toString();
43
50
  }
51
+ /**
52
+ * @param {import("postcss-selector-parser").Selectors} value
53
+ * @param {{precision: number, warnWhenCannotResolve: boolean}} options
54
+ * @param {import("postcss").Result} result
55
+ * @param {import("postcss").ChildNode} item
56
+ */
57
+
44
58
 
45
59
  function transformSelector(value, options, result, item) {
46
- return (0, _postcssSelectorParser.default)(function (selectors) {
47
- selectors.walk(function (node) {
60
+ return (0, _postcssSelectorParser.default)(selectors => {
61
+ selectors.walk(node => {
48
62
  // attribute value
49
63
  // e.g. the "calc(3*3)" part of "div[data-size="calc(3*3)"]"
50
- if (node.type === 'attribute' && node.value) {
64
+ if (node.type === "attribute" && node.value) {
51
65
  node.setValue(transformValue(node.value, options, result, item));
52
66
  } // tag value
53
67
  // e.g. the "calc(3*3)" part of "div:nth-child(2n + calc(3*3))"
54
68
 
55
69
 
56
- if (node.type === 'tag') {
70
+ if (node.type === "tag") {
57
71
  node.value = transformValue(node.value, options, result, item);
58
72
  }
59
73
 
@@ -61,15 +75,39 @@ function transformSelector(value, options, result, item) {
61
75
  });
62
76
  }).processSync(value);
63
77
  }
64
-
65
- var _default = function _default(node, property, options, result) {
66
- var value = property === "selector" ? transformSelector(node[property], options, result, node) : transformValue(node[property], options, result, node); // if the preserve option is enabled and the value has changed, write the
78
+ /**
79
+ * @param {any} node
80
+ * @param {{precision: number, preserve: boolean, warnWhenCannotResolve: boolean}} options
81
+ * @param {'value'|'params'|'selector'} property
82
+ * @param {import("postcss").Result} result
83
+ */
84
+
85
+
86
+ var _default = (node, property, options, result) => {
87
+ let value = node[property];
88
+
89
+ try {
90
+ value = property === "selector" ? transformSelector(node[property], options, result, node) : transformValue(node[property], options, result, node);
91
+ } catch (error) {
92
+ if (error instanceof Error) {
93
+ result.warn(error.message, {
94
+ node
95
+ });
96
+ } else {
97
+ result.warn('Error', {
98
+ node
99
+ });
100
+ }
101
+
102
+ return;
103
+ } // if the preserve option is enabled and the value has changed, write the
67
104
  // transformed value into a cloned node which is inserted before the current
68
105
  // node, preserving the original value. Otherwise, overwrite the original
69
106
  // value.
70
107
 
108
+
71
109
  if (options.preserve && node[property] !== value) {
72
- var clone = node.clone();
110
+ const clone = node.clone();
73
111
  clone[property] = value;
74
112
  node.parent.insertBefore(node, clone);
75
113
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "postcss-calc",
3
- "version": "7.0.4",
3
+ "version": "8.2.0",
4
4
  "description": "PostCSS plugin to reduce calc()",
5
5
  "keywords": [
6
6
  "css",
@@ -10,52 +10,50 @@
10
10
  "calc"
11
11
  ],
12
12
  "main": "dist/index.js",
13
+ "types": "types/index.d.ts",
13
14
  "files": [
14
15
  "dist",
16
+ "types",
15
17
  "LICENSE"
16
18
  ],
17
- "scripts": {
18
- "prepublish": "npm run build",
19
- "build": "del-cli dist && cross-env BABEL_ENV=publish babel src --out-dir dist --ignore src/__tests__/**/*.js && jison src/parser.jison -o dist/parser.js",
20
- "pretest": "npm run build && eslint src",
21
- "test": "ava"
22
- },
23
19
  "author": "Andy Jansson",
24
20
  "license": "MIT",
25
21
  "repository": "https://github.com/postcss/postcss-calc.git",
26
22
  "eslintConfig": {
27
- "parser": "babel-eslint",
28
- "extends": "eslint-config-i-am-meticulous",
23
+ "extends": [
24
+ "eslint:recommended",
25
+ "plugin:import/recommended"
26
+ ],
29
27
  "rules": {
30
28
  "curly": "error"
31
29
  }
32
30
  },
33
31
  "devDependencies": {
34
- "@babel/cli": "^7.1.2",
35
- "@babel/core": "^7.1.2",
36
- "@babel/polyfill": "^7.0.0",
37
- "@babel/preset-env": "^7.1.0",
38
- "@babel/register": "^7.0.0",
39
- "ava": "^1.4.1",
40
- "babel-eslint": "^10.0.1",
32
+ "@babel/cli": "^7.16.0",
33
+ "@babel/core": "^7.16.5",
34
+ "@babel/plugin-transform-modules-commonjs": "^7.16.5",
35
+ "@babel/register": "^7.16.7",
41
36
  "babel-plugin-add-module-exports": "^1.0.0",
42
- "cross-env": "^5.2.0",
43
- "del-cli": "^1.1.0",
44
- "eslint": "^5.7.0",
45
- "eslint-config-i-am-meticulous": "^11.0.0",
46
- "eslint-plugin-babel": "^5.2.1",
47
- "eslint-plugin-import": "^2.14.0",
48
- "jison-gho": "^0.6.1-215"
37
+ "eslint": "^8.5.0",
38
+ "eslint-plugin-import": "^2.25.3",
39
+ "jison-gho": "^0.6.1-216",
40
+ "postcss": "^8.2.2",
41
+ "rimraf": "^3.0.2",
42
+ "typescript": "^4.5.4",
43
+ "uvu": "^0.5.2"
49
44
  },
50
45
  "dependencies": {
51
- "postcss": "^7.0.27",
52
46
  "postcss-selector-parser": "^6.0.2",
53
47
  "postcss-value-parser": "^4.0.2"
54
48
  },
55
- "ava": {
56
- "require": [
57
- "@babel/register",
58
- "@babel/polyfill"
59
- ]
60
- }
61
- }
49
+ "peerDependencies": {
50
+ "postcss": "^8.2.2"
51
+ },
52
+ "scripts": {
53
+ "build": "rimraf dist && babel src --out-dir dist --ignore src/__tests__/**/*.js && jison src/parser.jison -o dist/parser.js",
54
+ "lint": "eslint src && tsc",
55
+ "pretest": "pnpm run build",
56
+ "test": "uvu -r @babel/register src/__tests__"
57
+ },
58
+ "readme": "# PostCSS Calc [<img src=\"https://postcss.github.io/postcss/logo.svg\" alt=\"PostCSS\" width=\"90\" height=\"90\" align=\"right\">][PostCSS]\n\n[![NPM Version][npm-img]][npm-url]\n[![Build Status][cli-img]][cli-url]\n[![Support Chat][git-img]][git-url]\n\n[PostCSS Calc] lets you reduce `calc()` references whenever it's possible. This\ncan be particularly useful with the [PostCSS Custom Properties] plugin.\n\nWhen multiple units are mixed together in the same expression, the `calc()`\nstatement is left as is, to fallback to the [W3C calc() implementation].\n\n## Installation\n\n```bash\nnpm install postcss-calc\n```\n\n## Usage\n\n```js\n// dependencies\nvar fs = require(\"fs\")\nvar postcss = require(\"postcss\")\nvar calc = require(\"postcss-calc\")\n\n// css to be processed\nvar css = fs.readFileSync(\"input.css\", \"utf8\")\n\n// process css\nvar output = postcss()\n .use(calc())\n .process(css)\n .css\n```\n\n**Example** (with [PostCSS Custom Properties] enabled as well):\n\n```js\n// dependencies\nvar fs = require(\"fs\")\nvar postcss = require(\"postcss\")\nvar customProperties = require(\"postcss-custom-properties\")\nvar calc = require(\"postcss-calc\")\n\n// css to be processed\nvar css = fs.readFileSync(\"input.css\", \"utf8\")\n\n// process css\nvar output = postcss()\n .use(customProperties())\n .use(calc())\n .process(css)\n .css\n```\n\nUsing this `input.css`:\n\n```css\n:root {\n --main-font-size: 16px;\n}\n\nbody {\n font-size: var(--main-font-size);\n}\n\nh1 {\n font-size: calc(var(--main-font-size) * 2);\n height: calc(100px - 2em);\n margin-bottom: calc(\n var(--main-font-size)\n * 1.5\n )\n}\n```\n\nyou will get:\n\n```css\nbody {\n font-size: 16px\n}\n\nh1 {\n font-size: 32px;\n height: calc(100px - 2em);\n margin-bottom: 24px\n}\n```\n\nCheckout [tests] for more examples.\n\n### Options\n\n#### `precision` (default: `5`)\n\nAllow you to define the precision for decimal numbers.\n\n```js\nvar out = postcss()\n .use(calc({precision: 10}))\n .process(css)\n .css\n```\n\n#### `preserve` (default: `false`)\n\nAllow you to preserve calc() usage in output so browsers will handle decimal\nprecision themselves.\n\n```js\nvar out = postcss()\n .use(calc({preserve: true}))\n .process(css)\n .css\n```\n\n#### `warnWhenCannotResolve` (default: `false`)\n\nAdds warnings when calc() are not reduced to a single value.\n\n```js\nvar out = postcss()\n .use(calc({warnWhenCannotResolve: true}))\n .process(css)\n .css\n```\n\n#### `mediaQueries` (default: `false`)\n\nAllows calc() usage as part of media query declarations.\n\n```js\nvar out = postcss()\n .use(calc({mediaQueries: true}))\n .process(css)\n .css\n```\n\n#### `selectors` (default: `false`)\n\nAllows calc() usage as part of selectors.\n\n```js\nvar out = postcss()\n .use(calc({selectors: true}))\n .process(css)\n .css\n```\n\nExample:\n\n```css\ndiv[data-size=\"calc(3*3)\"] {\n width: 100px;\n}\n```\n\n---\n\n## Contributing\n\nWork on a branch, install dev-dependencies, respect coding style & run tests\nbefore submitting a bug fix or a feature.\n\n```bash\ngit clone git@github.com:postcss/postcss-calc.git\ngit checkout -b patch-1\nnpm install\nnpm test\n```\n\n## [Changelog](CHANGELOG.md)\n\n## [License](LICENSE)\n\n[cli-img]: https://img.shields.io/travis/postcss/postcss-calc/master.svg\n[cli-url]: https://travis-ci.org/postcss/postcss-calc\n[git-img]: https://img.shields.io/badge/support-chat-blue.svg\n[git-url]: https://gitter.im/postcss/postcss\n[npm-img]: https://img.shields.io/npm/v/postcss-calc.svg\n[npm-url]: https://www.npmjs.com/package/postcss-calc\n\n[PostCSS]: https://github.com/postcss\n[PostCSS Calc]: https://github.com/postcss/postcss-calc\n[PostCSS Custom Properties]: https://github.com/postcss/postcss-custom-properties\n[tests]: src/__tests__/index.js\n[W3C calc() implementation]: https://www.w3.org/TR/css3-values/#calc-notation\n"
59
+ }
@@ -0,0 +1,30 @@
1
+ export default pluginCreator;
2
+ export type PostCssCalcOptions = {
3
+ precision?: number | false;
4
+ preserve?: boolean;
5
+ warnWhenCannotResolve?: boolean;
6
+ mediaQueries?: boolean;
7
+ selectors?: boolean;
8
+ };
9
+ /**
10
+ * @typedef {{precision?: number | false,
11
+ * preserve?: boolean,
12
+ * warnWhenCannotResolve?: boolean,
13
+ * mediaQueries?: boolean,
14
+ * selectors?: boolean}} PostCssCalcOptions
15
+ *
16
+ * @param {PostCssCalcOptions} opts
17
+ */
18
+ declare function pluginCreator(opts: PostCssCalcOptions): {
19
+ postcssPlugin: string;
20
+ /**
21
+ * @param {import('postcss').Root} css
22
+ * @param {{result: import('postcss').Result}} helpers
23
+ */
24
+ OnceExit(css: import('postcss').Root, { result }: {
25
+ result: import('postcss').Result;
26
+ }): void;
27
+ };
28
+ declare namespace pluginCreator {
29
+ const postcss: boolean;
30
+ }
@@ -0,0 +1,8 @@
1
+ export default convertUnit;
2
+ /**
3
+ * @param {number} value
4
+ * @param {string} sourceUnit
5
+ * @param {string} targetUnit
6
+ * @param {number|false} precision
7
+ */
8
+ declare function convertUnit(value: number, sourceUnit: string, targetUnit: string, precision: number | false): number;
@@ -0,0 +1,10 @@
1
+ export default reduce;
2
+ export type Collectible = {
3
+ preOperator: '+' | '-';
4
+ node: import('../parser').CalcNode;
5
+ };
6
+ /**
7
+ * @param {import('../parser').CalcNode} node
8
+ * @param {number} precision
9
+ */
10
+ declare function reduce(node: import('../parser').CalcNode, precision: number): import("../parser").MathExpression | import("../parser").DimensionExpression | import("../parser").NumberExpression | import("../parser").FunctionExpression;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @param {string} calc
3
+ * @param {import('../parser').CalcNode} node
4
+ * @param {string} originalValue
5
+ * @param {{precision: number | false, warnWhenCannotResolve: boolean}} options
6
+ * @param {import("postcss").Result} result
7
+ * @param {import("postcss").ChildNode} item
8
+ *
9
+ * @returns {string}
10
+ */
11
+ export default function _default(calc: string, node: import('../parser').CalcNode, originalValue: string, options: {
12
+ precision: number | false;
13
+ warnWhenCannotResolve: boolean;
14
+ }, result: import("postcss").Result, item: import("postcss").ChildNode): string;
@@ -0,0 +1,6 @@
1
+ declare function _default(node: any, property: 'value' | 'params' | 'selector', options: {
2
+ precision: number;
3
+ preserve: boolean;
4
+ warnWhenCannotResolve: boolean;
5
+ }, result: import("postcss").Result): void;
6
+ export default _default;
package/CHANGELOG.md DELETED
@@ -1,118 +0,0 @@
1
- # 7.0.4
2
-
3
- - Fixed: strips away important factors from multiplications in calc() ([#107](https://github.com/postcss/postcss-calc/issues/107))
4
-
5
- # 7.0.3
6
-
7
- - Fixed: substracted css-variable from zero ([#111](https://github.com/postcss/postcss-calc/issues/111))
8
-
9
- # 7.0.2
10
-
11
- - Fixed: incorrect reduction of subtraction from zero ([#88](https://github.com/postcss/postcss-calc/issues/88))
12
- - Fixed: doesn't remove calc for single function
13
- - Fixed: relax parser on unknown units ([#76](https://github.com/postcss/postcss-calc/issues/76))
14
- - Fixed: handle numbers with exponen composed ([#83](https://github.com/postcss/postcss-calc/pull/83))
15
- - Fixed: handle plus sign before value ([#79](https://github.com/postcss/postcss-calc/pull/79))
16
- - Fixed: better handle precision for nested calc ([#75](https://github.com/postcss/postcss-calc/pull/75))
17
- - Fixed: properly handle nested add and sub expression inside sub expression ([#64](https://github.com/postcss/postcss-calc/issues/64))
18
- - Fixed: handle uppercase units and functions ([#71](https://github.com/postcss/postcss-calc/pull/71))
19
- - Fixed: do not break `calc` with single var ([cssnano/cssnano#725](https://github.com/cssnano/cssnano/issues/725))
20
- - Updated: `postcss` to 7.0.27 (patch)
21
- - Updated: `postcss-selector-parser` to 6.0.2
22
- - Updated: `postcss-value-parser` to 4.0.2
23
-
24
- # 7.0.1
25
-
26
- - Updated: `postcss` to 7.0.2 (patch)
27
- - Updated: `postcss-selector-parser` to 5.0.0-rc.4 (patch)
28
- - Updated: `postcss-value-parser` to 3.3.1 (patch)
29
-
30
- # 7.0.0
31
-
32
- - Changed: Updated postcss-selector-parser to version 5.0.0-rc.3
33
- - Changed: Dropped reduce-css-calc as a dependency
34
- - Fixed: Support constant() and env() ([#42](https://github.com/postcss/postcss-calc/issues/42), [#48](https://github.com/postcss/postcss-calc/issues/48))
35
- - Fixed: Support custom properties with "calc" in its name ([#50](https://github.com/postcss/postcss-calc/issues/50))
36
- - Fixed: Remove unnecessary whitespace around `*` and `/` ([cssnano#625](https://github.com/cssnano/cssnano/issues/625))
37
- - Fixed: Arithmetic bugs around subtraction ([#49](https://github.com/postcss/postcss-calc/issues/49))
38
- - Fixed: Handling of nested calc statements ([reduce-css-calc#49](https://github.com/MoOx/reduce-css-calc/issues/49))
39
- - Fixed: Bugs regarding complex calculations ([reduce-cs-calc#45](https://github.com/MoOx/reduce-css-calc/issues/45))
40
- - Fixed: `100%` incorrectly being transformed to `1` ([reduce-css-calc#44](https://github.com/MoOx/reduce-css-calc/issues/44))
41
- - Added: support for case-insensitive calc statements
42
-
43
- # 6.0.2 - 2018-09-25
44
-
45
- - Fixed: use PostCSS 7 (thanks to @douglasduteil)
46
-
47
- # 6.0.1 - 2017-10-10
48
-
49
- - Fixed: throwing error for attribute selectors without a value
50
-
51
- # 6.0.0 - 2017-05-08
52
-
53
- - Breaking: Updated PostCSS from v5.x to v6.x, and reduce-css-calc from v1.x
54
- to v2.x (thanks to @andyjansson).
55
-
56
- # 5.3.1 - 2016-08-22
57
-
58
- - Fixed: avoid security issue related to ``reduce-css-calc@< 1.2.4``.
59
-
60
- # 5.3.0 - 2016-07-11
61
-
62
- - Added: support for selector transformation via `selectors` option.
63
- ([#29](https://github.com/postcss/postcss-calc/pull/29) - @uniquegestaltung)
64
-
65
- # 5.2.1 - 2016-04-10
66
-
67
- - Fixed: support for multiline value
68
- ([#27](https://github.com/postcss/postcss-calc/pull/27))
69
-
70
- # 5.2.0 - 2016-01-08
71
-
72
- - Added: "mediaQueries" option for `@media` support
73
- ([#22](https://github.com/postcss/postcss-calc/pull/22))
74
-
75
- # 5.1.0 - 2016-01-07
76
-
77
- - Added: "warnWhenCannotResolve" option to warn when calc() are not reduced to a single value
78
- ([#20](https://github.com/postcss/postcss-calc/pull/20))
79
-
80
- # 5.0.0 - 2015-08-25
81
-
82
- - Removed: compatibility with postcss v4.x
83
- - Added: compatibility with postcss v5.x
84
-
85
- # 4.1.0 - 2015-04-09
86
-
87
- - Added: compatibility with postcss v4.1.x ([#12](https://github.com/postcss/postcss-calc/pull/12))
88
-
89
- # 4.0.1 - 2015-04-09
90
-
91
- - Fixed: `preserve` option does not create duplicated values ([#7](https://github.com/postcss/postcss-calc/issues/7))
92
-
93
- # 4.0.0 - 2015-01-26
94
-
95
- - Added: compatibility with postcss v4.x
96
- - Changed: partial compatiblity with postcss v3.x (stack traces have lost filename)
97
-
98
- # 3.0.0 - 2014-11-24
99
-
100
- - Added: GNU like exceptions ([#4](https://github.com/postcss/postcss-calc/issues/4))
101
- - Added: `precision` option ([#5](https://github.com/postcss/postcss-calc/issues/5))
102
- - Added: `preserve` option ([#6](https://github.com/postcss/postcss-calc/issues/6))
103
-
104
- # 2.1.0 - 2014-10-15
105
-
106
- - Added: source of the error (gnu like message) (fix [#3](https://github.com/postcss/postcss-calc/issues/3))
107
-
108
- # 2.0.1 - 2014-08-10
109
-
110
- - Fixed: correctly ignore unrecognized values (fix [#2](https://github.com/postcss/postcss-calc/issues/2))
111
-
112
- # 2.0.0 - 2014-08-06
113
-
114
- - Changed: Plugin now return a function to have a consistent api. ([ref 1](https://github.com/ianstormtaylor/rework-color-function/issues/6), [ref 2](https://twitter.com/jongleberry/status/496552790416576513))
115
-
116
- # 1.0.0 - 2014-08-04
117
-
118
- ✨ First release based on [rework-calc](https://github.com/reworkcss/rework-calc) v1.1.0 (code mainly exported to [`reduce-css-calc`](https://github.com/MoOx/reduce-css-calc))