postcss-calc 11.1.1 → 11.1.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "postcss-calc",
3
- "version": "11.1.1",
3
+ "version": "11.1.2",
4
4
  "type": "module",
5
5
  "description": "PostCSS plugin to reduce calc()",
6
6
  "keywords": [
@@ -38,16 +38,16 @@
38
38
  "devEngines": {
39
39
  "packageManager": {
40
40
  "name": "pnpm",
41
- "version": "11.25.0"
41
+ "version": "12.3.4"
42
42
  }
43
43
  },
44
44
  "devDependencies": {
45
45
  "@csstools/css-calc": "^3.3.0",
46
46
  "@rmenke/css-tokenizer-tests": "^1.2.0",
47
- "@types/node": "^26.4.1",
47
+ "@types/node": "^26.5.0",
48
48
  "fast-check": "^4.9.0",
49
- "oxfmt": "^0.66.0",
50
- "oxlint": "^1.81.0",
49
+ "oxfmt": "^0.67.0",
50
+ "oxlint": "^1.82.0",
51
51
  "postcss": "^8.5.28",
52
52
  "typescript": "~7.0.2"
53
53
  },
@@ -61,6 +61,7 @@
61
61
  "lint": "oxlint . && tsc && oxfmt --check",
62
62
  "fmt": "oxfmt",
63
63
  "benchmark:arithmetic-chains": "node scripts/benchmark-arithmetic-chains.mjs",
64
+ "benchmark:nested-fallbacks": "node scripts/benchmark-nested-fallbacks.mjs",
64
65
  "test": "node --test --test-reporter=dot 'test/**/*.test.mjs' test/index.cjs test/convertUnit.cjs",
65
66
  "test:mutation:corpus": "node test/mutation/corpus-selection.mjs",
66
67
  "test:corpus:full": "POSTCSS_CALC_FULL_CORPUS=1 node --test test/conformance/corpus.test.mjs"
@@ -139,4 +139,18 @@ function convert(value, from, to) {
139
139
  return (value * f) / t;
140
140
  }
141
141
 
142
- export { baseOf, convert };
142
+ /**
143
+ * Return a base type only for units present in the static conversion table.
144
+ * Units with context-dependent values (em, rem, vw, etc.) return null.
145
+ * @param {string} unit
146
+ * @return {BaseType | null}
147
+ */
148
+ function staticBaseOf(unit) {
149
+ const key = unit.toLowerCase();
150
+ if (TO_CANONICAL[key] === undefined) {
151
+ return null;
152
+ }
153
+ return UNIT_TO_BASE[key] ?? null;
154
+ }
155
+
156
+ export { baseOf, staticBaseOf, convert };
package/src/lib/node.js CHANGED
@@ -16,9 +16,9 @@
16
16
 
17
17
  /**
18
18
  * @typedef {{type: 'Num', value: number}} Num
19
- * @typedef {{type: 'Dim', value: number, unit: string}} Dim
20
- * @typedef {{type: 'Ident', name: string}} Ident
21
- * @typedef {{type: 'Call', name: string, args: Node[]}} Call
19
+ * @typedef {{type: 'Dim', value: number, unit: string, rawUnit?: string}} Dim
20
+ * @typedef {{type: 'Ident', name: string, rawName?: string}} Ident
21
+ * @typedef {{type: 'Call', name: string, args: Node[], rawName?: string}} Call
22
22
  * @typedef {{sign: 1 | -1, node: Node}} SumTerm Sign is always +1 when node is Num or Dim.
23
23
  * @typedef {{type: 'Sum', terms: SumTerm[], grouped?: boolean}} Sum
24
24
  * @typedef {{exponent: 1 | -1, node: Node}} ProductFactor exponent +1 = numerator, -1 = denominator.
@@ -37,27 +37,36 @@ function num(value) {
37
37
  /**
38
38
  * @param {number} value
39
39
  * @param {string} unit
40
+ * @param {string} [rawUnit]
40
41
  * @return {Dim}
41
42
  */
42
- function dim(value, unit) {
43
- return { type: 'Dim', value, unit };
43
+ function dim(value, unit, rawUnit) {
44
+ return rawUnit === undefined
45
+ ? { type: 'Dim', value, unit }
46
+ : { type: 'Dim', value, unit, rawUnit };
44
47
  }
45
48
 
46
49
  /**
47
50
  * @param {string} name
51
+ * @param {string} [rawName]
48
52
  * @return {Ident}
49
53
  */
50
- function ident(name) {
51
- return { type: 'Ident', name };
54
+ function ident(name, rawName) {
55
+ return rawName === undefined
56
+ ? { type: 'Ident', name }
57
+ : { type: 'Ident', name, rawName };
52
58
  }
53
59
 
54
60
  /**
55
61
  * @param {string} name
56
62
  * @param {Node[]} args
63
+ * @param {string} [rawName]
57
64
  * @return {Call}
58
65
  */
59
- function call(name, args) {
60
- return { type: 'Call', name, args };
66
+ function call(name, args, rawName) {
67
+ return rawName === undefined
68
+ ? { type: 'Call', name, args }
69
+ : { type: 'Call', name, args, rawName };
61
70
  }
62
71
 
63
72
  /**
@@ -99,14 +108,9 @@ function pushSumTerm(out, term) {
99
108
 
100
109
  // sign=-1 around a Num/Dim leaf collapses into the value's sign — the
101
110
  // canonical-form rule downstream code relies on.
102
- if (sign === -1) {
103
- if (node.type === 'Num') {
104
- node = num(-node.value);
105
- sign = 1;
106
- } else if (node.type === 'Dim') {
107
- node = dim(-node.value, node.unit);
108
- sign = 1;
109
- }
111
+ if (sign === -1 && (node.type === 'Num' || node.type === 'Dim')) {
112
+ node = negate(node);
113
+ sign = 1;
110
114
  }
111
115
 
112
116
  // Drop zero-valued Nums. Dims with value 0 stay — the unit carries type.
@@ -169,7 +173,7 @@ function negate(node) {
169
173
  return num(-node.value);
170
174
  }
171
175
  if (node.type === 'Dim') {
172
- return dim(-node.value, node.unit);
176
+ return dim(-node.value, node.unit, node.rawUnit);
173
177
  }
174
178
  if (node.type === 'Sum') {
175
179
  const result = mkSum(
@@ -0,0 +1,40 @@
1
+ // Private metadata for opaque function contents (including var() fallbacks).
2
+ // Keeping it in a WeakMap means the public calculation AST remains unchanged.
3
+ /** @typedef {import('./node.js').Node} Node */
4
+ /** @typedef {string | Node | Component[]} Component */
5
+ /** @type {WeakMap<Extract<Node, {type: 'Call'}>, Component[]>} */
6
+ const components = new WeakMap();
7
+ /** @param {Extract<Node, {type: 'Call'}>} node @param {Component[]} tree */
8
+ function setComponents(node, tree) {
9
+ components.set(node, tree);
10
+ return node;
11
+ }
12
+ /** @param {Extract<Node, {type: 'Call'}>} node */
13
+ function getComponents(node) {
14
+ return components.get(node);
15
+ }
16
+ /** @param {Component[]} tree @param {(node: Node) => Node} simplify @return {Component[]} */
17
+ function simplifyComponents(tree, simplify) {
18
+ return tree.map((part) => {
19
+ if (typeof part === 'string') return part;
20
+ if (Array.isArray(part)) return simplifyComponents(part, simplify);
21
+ return simplify(part);
22
+ });
23
+ }
24
+ /** @param {Component[]} tree @param {(node: Node) => string} serialize @return {string} */
25
+ function serializeComponents(tree, serialize) {
26
+ let result = '';
27
+ for (const part of tree) {
28
+ if (typeof part === 'string') result += part;
29
+ else if (Array.isArray(part))
30
+ result += serializeComponents(part, serialize);
31
+ else result += serialize(part);
32
+ }
33
+ return result;
34
+ }
35
+ export {
36
+ getComponents,
37
+ setComponents,
38
+ simplifyComponents,
39
+ serializeComponents,
40
+ };