postcss-calc 8.2.3 → 8.2.4

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/src/index.js ADDED
@@ -0,0 +1,51 @@
1
+ 'use strict';
2
+ const transform = require('./lib/transform.js');
3
+
4
+ /**
5
+ * @typedef {{precision?: number | false,
6
+ * preserve?: boolean,
7
+ * warnWhenCannotResolve?: boolean,
8
+ * mediaQueries?: boolean,
9
+ * selectors?: boolean}} PostCssCalcOptions
10
+ */
11
+ /**
12
+ * @type {import('postcss').PluginCreator<PostCssCalcOptions>}
13
+ * @param {PostCssCalcOptions} opts
14
+ * @return {import('postcss').Plugin}
15
+ */
16
+ function pluginCreator(opts) {
17
+ const options = Object.assign(
18
+ {
19
+ precision: 5,
20
+ preserve: false,
21
+ warnWhenCannotResolve: false,
22
+ mediaQueries: false,
23
+ selectors: false,
24
+ },
25
+ opts
26
+ );
27
+
28
+ return {
29
+ postcssPlugin: 'postcss-calc',
30
+ OnceExit(css, { result }) {
31
+ css.walk((node) => {
32
+ const { type } = node;
33
+ if (type === 'decl') {
34
+ transform(node, 'value', options, result);
35
+ }
36
+
37
+ if (type === 'atrule' && options.mediaQueries) {
38
+ transform(node, 'params', options, result);
39
+ }
40
+
41
+ if (type === 'rule' && options.selectors) {
42
+ transform(node, 'selector', options, result);
43
+ }
44
+ });
45
+ },
46
+ };
47
+ }
48
+
49
+ pluginCreator.postcss = true;
50
+
51
+ module.exports = pluginCreator;
@@ -0,0 +1,160 @@
1
+ 'use strict';
2
+ /**
3
+ * @type {{[key:string]: {[key:string]: number}}}
4
+ */
5
+ const conversions = {
6
+ // Absolute length units
7
+ px: {
8
+ px: 1,
9
+ cm: 96 / 2.54,
10
+ mm: 96 / 25.4,
11
+ q: 96 / 101.6,
12
+ in: 96,
13
+ pt: 96 / 72,
14
+ pc: 16,
15
+ },
16
+ cm: {
17
+ px: 2.54 / 96,
18
+ cm: 1,
19
+ mm: 0.1,
20
+ q: 0.025,
21
+ in: 2.54,
22
+ pt: 2.54 / 72,
23
+ pc: 2.54 / 6,
24
+ },
25
+ mm: {
26
+ px: 25.4 / 96,
27
+ cm: 10,
28
+ mm: 1,
29
+ q: 0.25,
30
+ in: 25.4,
31
+ pt: 25.4 / 72,
32
+ pc: 25.4 / 6,
33
+ },
34
+ q: {
35
+ px: 101.6 / 96,
36
+ cm: 40,
37
+ mm: 4,
38
+ q: 1,
39
+ in: 101.6,
40
+ pt: 101.6 / 72,
41
+ pc: 101.6 / 6,
42
+ },
43
+ in: {
44
+ px: 1 / 96,
45
+ cm: 1 / 2.54,
46
+ mm: 1 / 25.4,
47
+ q: 1 / 101.6,
48
+ in: 1,
49
+ pt: 1 / 72,
50
+ pc: 1 / 6,
51
+ },
52
+ pt: {
53
+ px: 0.75,
54
+ cm: 72 / 2.54,
55
+ mm: 72 / 25.4,
56
+ q: 72 / 101.6,
57
+ in: 72,
58
+ pt: 1,
59
+ pc: 12,
60
+ },
61
+ pc: {
62
+ px: 0.0625,
63
+ cm: 6 / 2.54,
64
+ mm: 6 / 25.4,
65
+ q: 6 / 101.6,
66
+ in: 6,
67
+ pt: 6 / 72,
68
+ pc: 1,
69
+ },
70
+ // Angle units
71
+ deg: {
72
+ deg: 1,
73
+ grad: 0.9,
74
+ rad: 180 / Math.PI,
75
+ turn: 360,
76
+ },
77
+ grad: {
78
+ deg: 400 / 360,
79
+ grad: 1,
80
+ rad: 200 / Math.PI,
81
+ turn: 400,
82
+ },
83
+ rad: {
84
+ deg: Math.PI / 180,
85
+ grad: Math.PI / 200,
86
+ rad: 1,
87
+ turn: Math.PI * 2,
88
+ },
89
+ turn: {
90
+ deg: 1 / 360,
91
+ grad: 0.0025,
92
+ rad: 0.5 / Math.PI,
93
+ turn: 1,
94
+ },
95
+ // Duration units
96
+ s: {
97
+ s: 1,
98
+ ms: 0.001,
99
+ },
100
+ ms: {
101
+ s: 1000,
102
+ ms: 1,
103
+ },
104
+ // Frequency units
105
+ hz: {
106
+ hz: 1,
107
+ khz: 1000,
108
+ },
109
+ khz: {
110
+ hz: 0.001,
111
+ khz: 1,
112
+ },
113
+ // Resolution units
114
+ dpi: {
115
+ dpi: 1,
116
+ dpcm: 1 / 2.54,
117
+ dppx: 1 / 96,
118
+ },
119
+ dpcm: {
120
+ dpi: 2.54,
121
+ dpcm: 1,
122
+ dppx: 2.54 / 96,
123
+ },
124
+ dppx: {
125
+ dpi: 96,
126
+ dpcm: 96 / 2.54,
127
+ dppx: 1,
128
+ },
129
+ };
130
+ /**
131
+ * @param {number} value
132
+ * @param {string} sourceUnit
133
+ * @param {string} targetUnit
134
+ * @param {number|false} precision
135
+ */
136
+ function convertUnit(value, sourceUnit, targetUnit, precision) {
137
+ const sourceUnitNormalized = sourceUnit.toLowerCase();
138
+ const targetUnitNormalized = targetUnit.toLowerCase();
139
+
140
+ if (!conversions[targetUnitNormalized]) {
141
+ throw new Error('Cannot convert to ' + targetUnit);
142
+ }
143
+
144
+ if (!conversions[targetUnitNormalized][sourceUnitNormalized]) {
145
+ throw new Error('Cannot convert from ' + sourceUnit + ' to ' + targetUnit);
146
+ }
147
+
148
+ const converted =
149
+ conversions[targetUnitNormalized][sourceUnitNormalized] * value;
150
+
151
+ if (precision !== false) {
152
+ precision = Math.pow(10, Math.ceil(precision) || 5);
153
+
154
+ return Math.round(converted * precision) / precision;
155
+ }
156
+
157
+ return converted;
158
+ }
159
+
160
+ module.exports = convertUnit;
@@ -1,13 +1,5 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
-
8
- var _convertUnit = _interopRequireDefault(require("./convertUnit"));
9
-
10
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
1
+ 'use strict';
2
+ const convertUnit = require('./convertUnit.js');
11
3
 
12
4
  /**
13
5
  * @param {import('../parser').CalcNode} node
@@ -32,161 +24,153 @@ function isValueType(node) {
32
24
  case 'Number':
33
25
  return true;
34
26
  }
35
-
36
27
  return false;
37
28
  }
38
- /** @param {'-'|'+'} operator */
39
-
40
29
 
30
+ /** @param {'-'|'+'} operator */
41
31
  function flip(operator) {
42
32
  return operator === '+' ? '-' : '+';
43
33
  }
34
+
44
35
  /**
45
36
  * @param {string} operator
46
37
  * @returns {operator is '+'|'-'}
47
38
  */
48
-
49
-
50
39
  function isAddSubOperator(operator) {
51
40
  return operator === '+' || operator === '-';
52
41
  }
42
+
53
43
  /**
54
44
  * @typedef {{preOperator: '+'|'-', node: import('../parser').CalcNode}} Collectible
55
- */
45
+ */
56
46
 
57
47
  /**
58
48
  * @param {'+'|'-'} preOperator
59
49
  * @param {import('../parser').CalcNode} node
60
- * @param {Collectible[]} collected
50
+ * @param {Collectible[]} collected
61
51
  * @param {number} precision
62
52
  */
63
-
64
-
65
53
  function collectAddSubItems(preOperator, node, collected, precision) {
66
54
  if (!isAddSubOperator(preOperator)) {
67
55
  throw new Error(`invalid operator ${preOperator}`);
68
56
  }
69
-
70
57
  if (isValueType(node)) {
71
- const itemIndex = collected.findIndex(x => x.node.type === node.type);
72
-
58
+ const itemIndex = collected.findIndex((x) => x.node.type === node.type);
73
59
  if (itemIndex >= 0) {
74
60
  if (node.value === 0) {
75
61
  return;
76
- } // can cast because of the criterion used to find itemIndex
77
-
78
-
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);
62
+ }
63
+ // can cast because of the criterion used to find itemIndex
64
+ const otherValueNode = /** @type import('../parser').ValueExpression*/ (
65
+ collected[itemIndex].node
66
+ );
67
+ const { left: reducedNode, right: current } = convertNodesUnits(
68
+ otherValueNode,
69
+ node,
70
+ precision
71
+ );
86
72
 
87
73
  if (collected[itemIndex].preOperator === '-') {
88
74
  collected[itemIndex].preOperator = '+';
89
75
  reducedNode.value *= -1;
90
76
  }
91
-
92
- if (preOperator === "+") {
77
+ if (preOperator === '+') {
93
78
  reducedNode.value += current.value;
94
79
  } else {
95
80
  reducedNode.value -= current.value;
96
- } // make sure reducedNode.value >= 0
97
-
98
-
81
+ }
82
+ // make sure reducedNode.value >= 0
99
83
  if (reducedNode.value >= 0) {
100
- collected[itemIndex] = {
101
- node: reducedNode,
102
- preOperator: '+'
103
- };
84
+ collected[itemIndex] = { node: reducedNode, preOperator: '+' };
104
85
  } else {
105
86
  reducedNode.value *= -1;
106
- collected[itemIndex] = {
107
- node: reducedNode,
108
- preOperator: '-'
109
- };
87
+ collected[itemIndex] = { node: reducedNode, preOperator: '-' };
110
88
  }
111
89
  } else {
112
90
  // make sure node.value >= 0
113
91
  if (node.value >= 0) {
114
- collected.push({
115
- node,
116
- preOperator
117
- });
92
+ collected.push({ node, preOperator });
118
93
  } else {
119
94
  node.value *= -1;
120
- collected.push({
121
- node,
122
- preOperator: flip(preOperator)
123
- });
95
+ collected.push({ node, preOperator: flip(preOperator) });
124
96
  }
125
97
  }
126
- } else if (node.type === "MathExpression") {
98
+ } else if (node.type === 'MathExpression') {
127
99
  if (isAddSubOperator(node.operator)) {
128
100
  collectAddSubItems(preOperator, node.left, collected, precision);
129
- const collectRightOperator = preOperator === '-' ? flip(node.operator) : node.operator;
130
- collectAddSubItems(collectRightOperator, node.right, collected, precision);
101
+ const collectRightOperator =
102
+ preOperator === '-' ? flip(node.operator) : node.operator;
103
+ collectAddSubItems(
104
+ collectRightOperator,
105
+ node.right,
106
+ collected,
107
+ precision
108
+ );
131
109
  } else {
132
110
  // * or /
133
- const reducedNode = reduce(node, precision); // prevent infinite recursive call
134
-
135
- if (reducedNode.type !== "MathExpression" || isAddSubOperator(reducedNode.operator)) {
111
+ const reducedNode = reduce(node, precision);
112
+ // prevent infinite recursive call
113
+ if (
114
+ reducedNode.type !== 'MathExpression' ||
115
+ isAddSubOperator(reducedNode.operator)
116
+ ) {
136
117
  collectAddSubItems(preOperator, reducedNode, collected, precision);
137
118
  } else {
138
- collected.push({
139
- node: reducedNode,
140
- preOperator
141
- });
119
+ collected.push({ node: reducedNode, preOperator });
142
120
  }
143
121
  }
144
122
  } else if (node.type === 'ParenthesizedExpression') {
145
123
  collectAddSubItems(preOperator, node.content, collected, precision);
146
124
  } else {
147
- collected.push({
148
- node,
149
- preOperator
150
- });
125
+ collected.push({ node, preOperator });
151
126
  }
152
127
  }
128
+
153
129
  /**
154
130
  * @param {import('../parser').CalcNode} node
155
131
  * @param {number} precision
156
132
  */
157
-
158
-
159
133
  function reduceAddSubExpression(node, precision) {
160
134
  /** @type Collectible[] */
161
135
  const collected = [];
162
136
  collectAddSubItems('+', node, collected, precision);
163
- const withoutZeroItem = collected.filter(item => !(isValueType(item.node) && item.node.value === 0));
137
+
138
+ const withoutZeroItem = collected.filter(
139
+ (item) => !(isValueType(item.node) && item.node.value === 0)
140
+ );
164
141
  const firstNonZeroItem = withoutZeroItem[0]; // could be undefined
142
+
165
143
  // prevent producing "calc(-var(--a))" or "calc()"
166
144
  // which is invalid css
167
-
168
- if (!firstNonZeroItem || firstNonZeroItem.preOperator === '-' && !isValueType(firstNonZeroItem.node)) {
169
- const firstZeroItem = collected.find(item => isValueType(item.node) && item.node.value === 0);
170
-
145
+ if (
146
+ !firstNonZeroItem ||
147
+ (firstNonZeroItem.preOperator === '-' &&
148
+ !isValueType(firstNonZeroItem.node))
149
+ ) {
150
+ const firstZeroItem = collected.find(
151
+ (item) => isValueType(item.node) && item.node.value === 0
152
+ );
171
153
  if (firstZeroItem) {
172
154
  withoutZeroItem.unshift(firstZeroItem);
173
155
  }
174
- } // make sure the preOperator of the first item is +
175
-
156
+ }
176
157
 
177
- if (withoutZeroItem[0].preOperator === '-' && isValueType(withoutZeroItem[0].node)) {
158
+ // make sure the preOperator of the first item is +
159
+ if (
160
+ withoutZeroItem[0].preOperator === '-' &&
161
+ isValueType(withoutZeroItem[0].node)
162
+ ) {
178
163
  withoutZeroItem[0].node.value *= -1;
179
164
  withoutZeroItem[0].preOperator = '+';
180
165
  }
181
166
 
182
167
  let root = withoutZeroItem[0].node;
183
-
184
168
  for (let i = 1; i < withoutZeroItem.length; i++) {
185
169
  root = {
186
170
  type: 'MathExpression',
187
171
  operator: withoutZeroItem[i].preOperator,
188
172
  left: root,
189
- right: withoutZeroItem[i].node
173
+ right: withoutZeroItem[i].node,
190
174
  };
191
175
  }
192
176
 
@@ -195,8 +179,6 @@ function reduceAddSubExpression(node, precision) {
195
179
  /**
196
180
  * @param {import('../parser').MathExpression} node
197
181
  */
198
-
199
-
200
182
  function reduceDivisionExpression(node) {
201
183
  if (!isValueType(node.right)) {
202
184
  return node;
@@ -208,116 +190,104 @@ function reduceDivisionExpression(node) {
208
190
 
209
191
  return applyNumberDivision(node.left, node.right.value);
210
192
  }
193
+
211
194
  /**
212
195
  * apply (expr) / number
213
196
  *
214
197
  * @param {import('../parser').CalcNode} node
215
198
  * @param {number} divisor
216
199
  * @return {import('../parser').CalcNode}
217
- */
218
-
219
-
200
+ */
220
201
  function applyNumberDivision(node, divisor) {
221
202
  if (divisor === 0) {
222
203
  throw new Error('Cannot divide by zero');
223
204
  }
224
-
225
205
  if (isValueType(node)) {
226
206
  node.value /= divisor;
227
207
  return node;
228
208
  }
229
-
230
- if (node.type === "MathExpression" && isAddSubOperator(node.operator)) {
209
+ if (node.type === 'MathExpression' && isAddSubOperator(node.operator)) {
231
210
  // turn (a + b) / num into a/num + b/num
232
211
  // is good for further reduction
233
212
  // checkout the test case
234
213
  // "should reduce division before reducing additions"
235
214
  return {
236
- type: "MathExpression",
215
+ type: 'MathExpression',
237
216
  operator: node.operator,
238
217
  left: applyNumberDivision(node.left, divisor),
239
- right: applyNumberDivision(node.right, divisor)
218
+ right: applyNumberDivision(node.right, divisor),
240
219
  };
241
- } // it is impossible to reduce it into a single value
220
+ }
221
+ // it is impossible to reduce it into a single value
242
222
  // .e.g the node contains css variable
243
223
  // so we just preserve the division and let browser do it
244
-
245
-
246
224
  return {
247
- type: "MathExpression",
225
+ type: 'MathExpression',
248
226
  operator: '/',
249
227
  left: node,
250
228
  right: {
251
- type: "Number",
252
- value: divisor
253
- }
229
+ type: 'Number',
230
+ value: divisor,
231
+ },
254
232
  };
255
233
  }
256
234
  /**
257
235
  * @param {import('../parser').MathExpression} node
258
236
  */
259
-
260
-
261
237
  function reduceMultiplicationExpression(node) {
262
238
  // (expr) * number
263
239
  if (node.right.type === 'Number') {
264
240
  return applyNumberMultiplication(node.left, node.right.value);
265
- } // number * (expr)
266
-
267
-
241
+ }
242
+ // number * (expr)
268
243
  if (node.left.type === 'Number') {
269
244
  return applyNumberMultiplication(node.right, node.left.value);
270
245
  }
271
-
272
246
  return node;
273
247
  }
248
+
274
249
  /**
275
250
  * apply (expr) * number
276
251
  * @param {number} multiplier
277
252
  * @param {import('../parser').CalcNode} node
278
253
  * @return {import('../parser').CalcNode}
279
254
  */
280
-
281
-
282
255
  function applyNumberMultiplication(node, multiplier) {
283
256
  if (isValueType(node)) {
284
257
  node.value *= multiplier;
285
258
  return node;
286
259
  }
287
-
288
- if (node.type === "MathExpression" && isAddSubOperator(node.operator)) {
260
+ if (node.type === 'MathExpression' && isAddSubOperator(node.operator)) {
289
261
  // turn (a + b) * num into a*num + b*num
290
262
  // is good for further reduction
291
263
  // checkout the test case
292
264
  // "should reduce multiplication before reducing additions"
293
265
  return {
294
- type: "MathExpression",
266
+ type: 'MathExpression',
295
267
  operator: node.operator,
296
268
  left: applyNumberMultiplication(node.left, multiplier),
297
- right: applyNumberMultiplication(node.right, multiplier)
269
+ right: applyNumberMultiplication(node.right, multiplier),
298
270
  };
299
- } // it is impossible to reduce it into a single value
271
+ }
272
+ // it is impossible to reduce it into a single value
300
273
  // .e.g the node contains css variable
301
274
  // so we just preserve the division and let browser do it
302
-
303
-
304
275
  return {
305
- type: "MathExpression",
276
+ type: 'MathExpression',
306
277
  operator: '*',
307
278
  left: node,
308
279
  right: {
309
- type: "Number",
310
- value: multiplier
311
- }
280
+ type: 'Number',
281
+ value: multiplier,
282
+ },
312
283
  };
313
284
  }
285
+
314
286
  /**
315
287
  * @param {import('../parser').ValueExpression} left
316
288
  * @param {import('../parser').ValueExpression} right
317
289
  * @param {number} precision
318
290
  */
319
-
320
-
321
291
  function convertNodesUnits(left, right, precision) {
322
292
  switch (left.type) {
323
293
  case 'LengthValue':
@@ -326,56 +296,54 @@ function convertNodesUnits(left, right, precision) {
326
296
  case 'FrequencyValue':
327
297
  case 'ResolutionValue':
328
298
  if (right.type === left.type && right.unit && left.unit) {
329
- const converted = (0, _convertUnit.default)(right.value, right.unit, left.unit, precision);
299
+ const converted = convertUnit(
300
+ right.value,
301
+ right.unit,
302
+ left.unit,
303
+ precision
304
+ );
305
+
330
306
  right = {
331
307
  type: left.type,
332
308
  value: converted,
333
- unit: left.unit
309
+ unit: left.unit,
334
310
  };
335
311
  }
336
312
 
337
- return {
338
- left,
339
- right
340
- };
341
-
313
+ return { left, right };
342
314
  default:
343
- return {
344
- left,
345
- right
346
- };
315
+ return { left, right };
347
316
  }
348
317
  }
318
+
349
319
  /**
350
320
  * @param {import('../parser').ParenthesizedExpression} node
351
321
  */
352
-
353
-
354
322
  function includesNoCssProperties(node) {
355
- return node.content.type !== 'Function' && (node.content.type !== 'MathExpression' || node.content.right.type !== 'Function' && node.content.left.type !== 'Function');
323
+ return (
324
+ node.content.type !== 'Function' &&
325
+ (node.content.type !== 'MathExpression' ||
326
+ (node.content.right.type !== 'Function' &&
327
+ node.content.left.type !== 'Function'))
328
+ );
356
329
  }
357
330
  /**
358
331
  * @param {import('../parser').CalcNode} node
359
332
  * @param {number} precision
360
333
  * @return {import('../parser').CalcNode}
361
334
  */
362
-
363
-
364
335
  function reduce(node, precision) {
365
- if (node.type === "MathExpression") {
336
+ if (node.type === 'MathExpression') {
366
337
  if (isAddSubOperator(node.operator)) {
367
338
  // reduceAddSubExpression will call reduce recursively
368
339
  return reduceAddSubExpression(node, precision);
369
340
  }
370
-
371
341
  node.left = reduce(node.left, precision);
372
342
  node.right = reduce(node.right, precision);
373
-
374
343
  switch (node.operator) {
375
- case "/":
344
+ case '/':
376
345
  return reduceDivisionExpression(node);
377
-
378
- case "*":
346
+ case '*':
379
347
  return reduceMultiplicationExpression(node);
380
348
  }
381
349
 
@@ -391,6 +359,4 @@ function reduce(node, precision) {
391
359
  return node;
392
360
  }
393
361
 
394
- var _default = reduce;
395
- exports.default = _default;
396
- module.exports = exports.default;
362
+ module.exports = reduce;