postcss-calc 11.0.1 → 11.0.2
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/README.md +2 -0
- package/package.json +5 -4
- package/src/lib/parser.js +63 -64
- package/types/lib/parser.d.ts +0 -4
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "postcss-calc",
|
|
3
|
-
"version": "11.0.
|
|
3
|
+
"version": "11.0.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "PostCSS plugin to reduce calc()",
|
|
6
6
|
"keywords": [
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"homepage": "https://github.com/postcss/postcss-calc",
|
|
14
14
|
"repository": {
|
|
15
15
|
"type": "git",
|
|
16
|
-
"url": "https://github.com/postcss/postcss-calc.git"
|
|
16
|
+
"url": "git+https://github.com/postcss/postcss-calc.git"
|
|
17
17
|
},
|
|
18
18
|
"exports": {
|
|
19
19
|
".": {
|
|
@@ -34,13 +34,13 @@
|
|
|
34
34
|
"devEngines": {
|
|
35
35
|
"packageManager": {
|
|
36
36
|
"name": "pnpm",
|
|
37
|
-
"version": "11.
|
|
37
|
+
"version": "11.25.0"
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@csstools/css-calc": "^3.3.0",
|
|
42
42
|
"@rmenke/css-tokenizer-tests": "^1.2.0",
|
|
43
|
-
"@types/node": "^26.
|
|
43
|
+
"@types/node": "^26.4.0",
|
|
44
44
|
"fast-check": "^4.9.0",
|
|
45
45
|
"oxfmt": "^0.65.0",
|
|
46
46
|
"oxlint": "^1.80.0",
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
"scripts": {
|
|
58
58
|
"lint": "oxlint . && tsc && oxfmt --check",
|
|
59
59
|
"fmt": "oxfmt",
|
|
60
|
+
"benchmark:arithmetic-chains": "node scripts/benchmark-arithmetic-chains.mjs",
|
|
60
61
|
"test": "node --test --test-reporter=dot 'test/**/*.test.mjs' test/index.cjs test/convertUnit.cjs",
|
|
61
62
|
"test:mutation:corpus": "node test/mutation/corpus-selection.mjs",
|
|
62
63
|
"test:corpus:full": "POSTCSS_CALC_FULL_CORPUS=1 node --test test/conformance/corpus.test.mjs"
|
package/src/lib/parser.js
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
// Pratt parser. +/- emit Sum nodes; */÷ emit Product nodes. node.js
|
|
2
2
|
// constructors flatten and normalize on construction, while parenthesized
|
|
3
3
|
// sums retain a grouping marker for the opaque-subtraction invariant.
|
|
4
|
-
import { mkSum, mkProduct, negate, ident, call } from './node.js';
|
|
4
|
+
import { mkSum, mkProduct, negate, num, dim, ident, call } from './node.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @typedef {import('./tokenizer.js').Token} Token
|
|
8
8
|
* @typedef {import('./tokenizer.js').TokenType} TokenType
|
|
9
9
|
* @typedef {import('./node.js').Node} Node
|
|
10
10
|
* @typedef {(p: Parser, token: Token) => Node} PrefixParselet
|
|
11
|
-
* @typedef {{lbp: number, parse: (p: Parser, left: Node, token: Token) => Node}} InfixParselet
|
|
12
11
|
*/
|
|
13
12
|
|
|
14
13
|
/**
|
|
@@ -30,17 +29,17 @@ function foldCalcKeyword(name) {
|
|
|
30
29
|
// form arrives as a single ident because CSS Syntax tokenizes leading
|
|
31
30
|
// `-` + ident-start as one ident-token.
|
|
32
31
|
if (name === 'NaN' || name === '-NaN') {
|
|
33
|
-
return
|
|
32
|
+
return num(Number.NaN);
|
|
34
33
|
}
|
|
35
34
|
switch (name.toLowerCase()) {
|
|
36
35
|
case 'pi':
|
|
37
|
-
return
|
|
36
|
+
return num(Math.PI);
|
|
38
37
|
case 'e':
|
|
39
|
-
return
|
|
38
|
+
return num(Math.E);
|
|
40
39
|
case 'infinity':
|
|
41
|
-
return
|
|
40
|
+
return num(Infinity);
|
|
42
41
|
case '-infinity':
|
|
43
|
-
return
|
|
42
|
+
return num(-Infinity);
|
|
44
43
|
}
|
|
45
44
|
return null;
|
|
46
45
|
}
|
|
@@ -102,40 +101,58 @@ class Parser {
|
|
|
102
101
|
if (!rule || rule.lbp < minBp) {
|
|
103
102
|
break;
|
|
104
103
|
}
|
|
105
|
-
|
|
106
|
-
|
|
104
|
+
if (infixKey === '+' || infixKey === '-') {
|
|
105
|
+
/** @type {import('./node.js').SumTerm[]} */
|
|
106
|
+
const terms = [{ sign: /** @type {1} */ (1), node: left }];
|
|
107
|
+
do {
|
|
108
|
+
const token = this.next();
|
|
109
|
+
requireSurroundingWs(this, token);
|
|
110
|
+
terms.push({
|
|
111
|
+
sign: /** @type {1 | -1} */ (token.value === '+' ? 1 : -1),
|
|
112
|
+
node: this.parseExpr(ADD_BP + 1),
|
|
113
|
+
});
|
|
114
|
+
const next = this.peek();
|
|
115
|
+
if (
|
|
116
|
+
next.type !== 'punct' ||
|
|
117
|
+
(next.value !== '+' && next.value !== '-')
|
|
118
|
+
) {
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
} while (ADD_BP >= minBp);
|
|
122
|
+
left = mkSum(terms);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (infixKey === '*' || infixKey === '/') {
|
|
127
|
+
/** @type {import('./node.js').ProductFactor[]} */
|
|
128
|
+
const factors = [{ exponent: /** @type {1} */ (1), node: left }];
|
|
129
|
+
do {
|
|
130
|
+
const token = this.next();
|
|
131
|
+
factors.push({
|
|
132
|
+
exponent: /** @type {1 | -1} */ (token.value === '*' ? 1 : -1),
|
|
133
|
+
node: this.parseExpr(MUL_BP + 1),
|
|
134
|
+
});
|
|
135
|
+
const next = this.peek();
|
|
136
|
+
if (
|
|
137
|
+
next.type !== 'punct' ||
|
|
138
|
+
(next.value !== '*' && next.value !== '/')
|
|
139
|
+
) {
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
} while (MUL_BP >= minBp);
|
|
143
|
+
left = mkProduct(factors);
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Every infix operator is handled above. Keep this defensive exit in
|
|
148
|
+
// case a future parselet is added without a chain implementation.
|
|
149
|
+
break;
|
|
107
150
|
}
|
|
108
151
|
|
|
109
152
|
return left;
|
|
110
153
|
}
|
|
111
154
|
}
|
|
112
155
|
|
|
113
|
-
/**
|
|
114
|
-
* @param {Node} left
|
|
115
|
-
* @param {Node} right
|
|
116
|
-
* @param {1 | -1} rightSign
|
|
117
|
-
* @return {Node}
|
|
118
|
-
*/
|
|
119
|
-
function addTerm(left, right, rightSign) {
|
|
120
|
-
return mkSum([
|
|
121
|
-
{ sign: 1, node: left },
|
|
122
|
-
{ sign: rightSign, node: right },
|
|
123
|
-
]);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* @param {Node} left
|
|
128
|
-
* @param {Node} right
|
|
129
|
-
* @param {1 | -1} rightExp
|
|
130
|
-
* @return {Node}
|
|
131
|
-
*/
|
|
132
|
-
function mulFactor(left, right, rightExp) {
|
|
133
|
-
return mkProduct([
|
|
134
|
-
{ exponent: 1, node: left },
|
|
135
|
-
{ exponent: rightExp, node: right },
|
|
136
|
-
]);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
156
|
const ADD_BP = 1;
|
|
140
157
|
const MUL_BP = 3;
|
|
141
158
|
const UNARY_BP = 7;
|
|
@@ -228,14 +245,14 @@ function requireSurroundingWs(p, token) {
|
|
|
228
245
|
|
|
229
246
|
/** @type {Record<string, PrefixParselet>} */
|
|
230
247
|
const PREFIX = {
|
|
231
|
-
number: (_p, t) => (
|
|
248
|
+
number: (_p, t) => num(Number.parseFloat(t.value)),
|
|
232
249
|
|
|
233
250
|
// Unit case normalization per §10.12: `1PX` serializes as `1px`.
|
|
234
|
-
dimension: (_p, t) =>
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
251
|
+
dimension: (_p, t) =>
|
|
252
|
+
dim(
|
|
253
|
+
Number.parseFloat(t.value),
|
|
254
|
+
t.unit === '%' ? '%' : /** @type {string} */ (t.unit).toLowerCase()
|
|
255
|
+
),
|
|
239
256
|
|
|
240
257
|
ident: (p, t) => {
|
|
241
258
|
const nxt = p.peek();
|
|
@@ -273,30 +290,12 @@ const PREFIX = {
|
|
|
273
290
|
'+': (p) => p.parseExpr(UNARY_BP),
|
|
274
291
|
};
|
|
275
292
|
|
|
276
|
-
/** @type {Record<string,
|
|
293
|
+
/** @type {Record<string, {lbp: number}>} */
|
|
277
294
|
const INFIX = {
|
|
278
|
-
'+': {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
return addTerm(left, p.parseExpr(ADD_BP + 1), 1);
|
|
283
|
-
},
|
|
284
|
-
},
|
|
285
|
-
'-': {
|
|
286
|
-
lbp: ADD_BP,
|
|
287
|
-
parse: (p, left, token) => {
|
|
288
|
-
requireSurroundingWs(p, token);
|
|
289
|
-
return addTerm(left, p.parseExpr(ADD_BP + 1), -1);
|
|
290
|
-
},
|
|
291
|
-
},
|
|
292
|
-
'*': {
|
|
293
|
-
lbp: MUL_BP,
|
|
294
|
-
parse: (p, left) => mulFactor(left, p.parseExpr(MUL_BP + 1), 1),
|
|
295
|
-
},
|
|
296
|
-
'/': {
|
|
297
|
-
lbp: MUL_BP,
|
|
298
|
-
parse: (p, left) => mulFactor(left, p.parseExpr(MUL_BP + 1), -1),
|
|
299
|
-
},
|
|
295
|
+
'+': { lbp: ADD_BP },
|
|
296
|
+
'-': { lbp: ADD_BP },
|
|
297
|
+
'*': { lbp: MUL_BP },
|
|
298
|
+
'/': { lbp: MUL_BP },
|
|
300
299
|
};
|
|
301
300
|
|
|
302
301
|
/**
|
package/types/lib/parser.d.ts
CHANGED
|
@@ -2,10 +2,6 @@ export type Token = import('./tokenizer.js').Token;
|
|
|
2
2
|
export type TokenType = import('./tokenizer.js').TokenType;
|
|
3
3
|
export type Node = import('./node.js').Node;
|
|
4
4
|
export type PrefixParselet = (p: Parser, token: Token) => Node;
|
|
5
|
-
export type InfixParselet = {
|
|
6
|
-
lbp: number;
|
|
7
|
-
parse: (p: Parser, left: Node, token: Token) => Node;
|
|
8
|
-
};
|
|
9
5
|
declare class Parser {
|
|
10
6
|
/** @private */
|
|
11
7
|
i;
|