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/package.json +19 -16
- package/src/__tests__/convertUnit.js +421 -0
- package/src/__tests__/index.js +903 -0
- package/src/index.js +51 -0
- package/src/lib/convertUnit.js +160 -0
- package/{dist → src}/lib/reducer.js +108 -142
- package/{dist → src}/lib/stringifier.js +36 -51
- package/src/lib/transform.js +109 -0
- package/src/parser.d.ts +51 -0
- package/src/parser.jison +111 -0
- package/{dist → src}/parser.js +0 -0
- package/types/index.d.ts +14 -13
- package/types/lib/convertUnit.d.ts +1 -1
- package/types/lib/reducer.d.ts +8 -5
- package/types/lib/stringifier.d.ts +2 -11
- package/types/lib/transform.d.ts +2 -2
- package/dist/index.js +0 -64
- package/dist/lib/convertUnit.js +0 -167
- package/dist/lib/transform.js +0 -119
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
|
-
|
|
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
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
-
}
|
|
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 ===
|
|
98
|
+
} else if (node.type === 'MathExpression') {
|
|
127
99
|
if (isAddSubOperator(node.operator)) {
|
|
128
100
|
collectAddSubItems(preOperator, node.left, collected, precision);
|
|
129
|
-
const collectRightOperator =
|
|
130
|
-
|
|
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);
|
|
134
|
-
|
|
135
|
-
if (
|
|
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
|
-
|
|
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
|
-
|
|
169
|
-
|
|
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
|
-
}
|
|
175
|
-
|
|
156
|
+
}
|
|
176
157
|
|
|
177
|
-
|
|
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:
|
|
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
|
-
}
|
|
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:
|
|
225
|
+
type: 'MathExpression',
|
|
248
226
|
operator: '/',
|
|
249
227
|
left: node,
|
|
250
228
|
right: {
|
|
251
|
-
type:
|
|
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
|
-
}
|
|
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:
|
|
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
|
-
}
|
|
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:
|
|
276
|
+
type: 'MathExpression',
|
|
306
277
|
operator: '*',
|
|
307
278
|
left: node,
|
|
308
279
|
right: {
|
|
309
|
-
type:
|
|
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 = (
|
|
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
|
|
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 ===
|
|
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
|
-
|
|
395
|
-
exports.default = _default;
|
|
396
|
-
module.exports = exports.default;
|
|
362
|
+
module.exports = reduce;
|