postcss-calc 11.0.0-rc.0 → 11.0.0-rc.1
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.0.0-rc.
|
|
3
|
+
"version": "11.0.0-rc.1",
|
|
4
4
|
"description": "PostCSS plugin to reduce calc()",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"css",
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"@eslint/js": "^10.0.1",
|
|
32
32
|
"@rmenke/css-tokenizer-tests": "^1.2.0",
|
|
33
33
|
"@stryker-mutator/core": "^9.6.1",
|
|
34
|
+
"@stryker-mutator/tap-runner": "^9.6.1",
|
|
34
35
|
"@stryker-mutator/typescript-checker": "^9.6.1",
|
|
35
36
|
"@types/node": "^26.1.1",
|
|
36
37
|
"eslint": "^10.7.0",
|
package/src/lib/serialize.js
CHANGED
|
@@ -15,7 +15,15 @@
|
|
|
15
15
|
* @property {string} [calcName] Wrapper name to use when `calc()` is needed. Default `'calc'`.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
// Below this is float noise, not a value: `0.1 + 0.2 - 0.3` is 5.5e-17.
|
|
19
|
+
const NOISE_FLOOR = 1e-12;
|
|
20
|
+
|
|
18
21
|
/**
|
|
22
|
+
* Rounding to `prec` decimal places turns `calc(1/1000000)` into `0`, and a
|
|
23
|
+
* `0` in CSS is often a switch, not a small number (`flex-grow: 0` never
|
|
24
|
+
* grows). So when a value is too small for `prec`, keep its significant digits
|
|
25
|
+
* instead: `1/1000000` -> `0.000001`, `1/3000000` -> `3.3333e-7`.
|
|
26
|
+
*
|
|
19
27
|
* @param {number} v
|
|
20
28
|
* @param {number | false} prec
|
|
21
29
|
* @return {number}
|
|
@@ -25,7 +33,12 @@ function round(v, prec) {
|
|
|
25
33
|
return v;
|
|
26
34
|
}
|
|
27
35
|
const m = Math.pow(10, prec);
|
|
28
|
-
|
|
36
|
+
const rounded = Math.round(v * m) / m;
|
|
37
|
+
if (rounded === 0 && Math.abs(v) > NOISE_FLOOR) {
|
|
38
|
+
// toPrecision needs at least one significant digit; `prec` may be 0.
|
|
39
|
+
return Number(v.toPrecision(Math.max(prec, 1)));
|
|
40
|
+
}
|
|
41
|
+
return rounded;
|
|
29
42
|
}
|
|
30
43
|
|
|
31
44
|
// §10.13 / §10.7.2: Infinity/NaN serialize as canonical keywords.
|
|
@@ -11,6 +11,7 @@ const { convert } = require('../convertUnits.js');
|
|
|
11
11
|
* @typedef {object} UnitBucket
|
|
12
12
|
* @property {string} unit
|
|
13
13
|
* @property {number} total
|
|
14
|
+
* @property {number} scale largest |term| accumulated into `total`, for noise detection
|
|
14
15
|
* @property {import('../convertUnits.js').BaseType | null} base
|
|
15
16
|
* @property {number} order
|
|
16
17
|
*/
|
package/src/lib/simplify/sum.js
CHANGED
|
@@ -12,6 +12,19 @@ const { mergeConvertibleBuckets } = require('./bucket.js');
|
|
|
12
12
|
* @typedef {import('./bucket.js').UnitBucket} UnitBucket
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
+
// Subtracting near-equal terms leaves float dust: `0.07 * 1e7 - 700000` is
|
|
16
|
+
// 1.16e-10, not 0. Snap a total that's tiny next to its terms back to 0.
|
|
17
|
+
const NOISE_REL = Number.EPSILON * 8;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {number} total
|
|
21
|
+
* @param {number} scale largest |term| accumulated into `total`
|
|
22
|
+
* @return {number}
|
|
23
|
+
*/
|
|
24
|
+
function denoise(total, scale) {
|
|
25
|
+
return Math.abs(total) < scale * NOISE_REL ? 0 : total;
|
|
26
|
+
}
|
|
27
|
+
|
|
15
28
|
/**
|
|
16
29
|
* @param {Sum} sum
|
|
17
30
|
* @param {SimplifyFn} simplify
|
|
@@ -23,6 +36,7 @@ function simplifySum(sum, simplify) {
|
|
|
23
36
|
// encountered unit. `100vh - 5rem - 10rem - 100px` → `-15rem` in phase 1,
|
|
24
37
|
// then vh/rem/px stay separate in phase 2 (none convert to each other).
|
|
25
38
|
let numTotal = 0;
|
|
39
|
+
let numScale = 0;
|
|
26
40
|
/** @type {Map<string, UnitBucket>} */
|
|
27
41
|
const byUnit = new Map();
|
|
28
42
|
/** @type {SumTerm[]} */
|
|
@@ -43,6 +57,7 @@ function simplifySum(sum, simplify) {
|
|
|
43
57
|
}
|
|
44
58
|
if (n.type === 'Num') {
|
|
45
59
|
numTotal += sign * n.value;
|
|
60
|
+
numScale = Math.max(numScale, Math.abs(n.value));
|
|
46
61
|
return;
|
|
47
62
|
}
|
|
48
63
|
if (n.type === 'Dim') {
|
|
@@ -50,10 +65,12 @@ function simplifySum(sum, simplify) {
|
|
|
50
65
|
const existing = byUnit.get(key);
|
|
51
66
|
if (existing) {
|
|
52
67
|
existing.total += sign * n.value;
|
|
68
|
+
existing.scale = Math.max(existing.scale, Math.abs(n.value));
|
|
53
69
|
} else {
|
|
54
70
|
byUnit.set(key, {
|
|
55
71
|
unit: n.unit,
|
|
56
72
|
total: sign * n.value,
|
|
73
|
+
scale: Math.abs(n.value),
|
|
57
74
|
base: baseOf(n.unit),
|
|
58
75
|
order: bucketOrder++,
|
|
59
76
|
});
|
|
@@ -71,9 +88,9 @@ function simplifySum(sum, simplify) {
|
|
|
71
88
|
// unconditionally is harmless. Zero-valued unit buckets are kept for
|
|
72
89
|
// type info (WPT calc-serialization-002).
|
|
73
90
|
/** @type {SumTerm[]} */
|
|
74
|
-
const terms = [{ sign: 1, node: num(numTotal) }];
|
|
91
|
+
const terms = [{ sign: 1, node: num(denoise(numTotal, numScale)) }];
|
|
75
92
|
for (const bucket of mergeConvertibleBuckets([...byUnit.values()])) {
|
|
76
|
-
terms.push({ sign: 1, node: dim(bucket.total, bucket.unit) });
|
|
93
|
+
terms.push({ sign: 1, node: dim(denoise(bucket.total, bucket.scale), bucket.unit) });
|
|
77
94
|
}
|
|
78
95
|
terms.push(...opaque);
|
|
79
96
|
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export type UnitBucket = {
|
|
2
2
|
unit: string;
|
|
3
3
|
total: number;
|
|
4
|
+
/**
|
|
5
|
+
* largest |term| accumulated into `total`, for noise detection
|
|
6
|
+
*/
|
|
7
|
+
scale: number;
|
|
4
8
|
base: import("../convertUnits.js").BaseType | null;
|
|
5
9
|
order: number;
|
|
6
10
|
};
|
|
@@ -8,6 +12,7 @@ export type UnitBucket = {
|
|
|
8
12
|
* @typedef {object} UnitBucket
|
|
9
13
|
* @property {string} unit
|
|
10
14
|
* @property {number} total
|
|
15
|
+
* @property {number} scale largest |term| accumulated into `total`, for noise detection
|
|
11
16
|
* @property {import('../convertUnits.js').BaseType | null} base
|
|
12
17
|
* @property {number} order
|
|
13
18
|
*/
|
|
@@ -3,13 +3,6 @@ export type Sum = import("../node.js").Sum;
|
|
|
3
3
|
export type SumTerm = import("../node.js").SumTerm;
|
|
4
4
|
export type SimplifyFn = import("../simplify.js").SimplifyFn;
|
|
5
5
|
export type UnitBucket = import("./bucket.js").UnitBucket;
|
|
6
|
-
/**
|
|
7
|
-
* @typedef {import('../node.js').Node} Node
|
|
8
|
-
* @typedef {import('../node.js').Sum} Sum
|
|
9
|
-
* @typedef {import('../node.js').SumTerm} SumTerm
|
|
10
|
-
* @typedef {import('../simplify.js').SimplifyFn} SimplifyFn
|
|
11
|
-
* @typedef {import('./bucket.js').UnitBucket} UnitBucket
|
|
12
|
-
*/
|
|
13
6
|
/**
|
|
14
7
|
* @param {Sum} sum
|
|
15
8
|
* @param {SimplifyFn} simplify
|