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 +6 -5
- package/src/lib/convertUnits.js +15 -1
- package/src/lib/node.js +22 -18
- package/src/lib/opaque.js +40 -0
- package/src/lib/parser.js +381 -200
- package/src/lib/serialize.js +14 -6
- package/src/lib/simplify/abs.js +1 -1
- package/src/lib/simplify/bucket.js +18 -23
- package/src/lib/simplify/call.js +8 -1
- package/src/lib/simplify/product.js +7 -4
- package/src/lib/simplify/sum.js +8 -5
- package/src/lib/tokenizer.js +6 -135
- package/src/reduce.js +1 -4
- package/types/lib/convertUnits.d.ts +8 -1
- package/types/lib/node.d.ts +12 -6
- package/types/lib/opaque.d.ts +15 -0
- package/types/lib/parser.d.ts +40 -36
- package/types/lib/simplify/bucket.d.ts +2 -2
- package/types/lib/tokenizer.d.ts +3 -32
package/src/lib/serialize.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// operator, or when a finite scalar is negative.
|
|
4
4
|
|
|
5
5
|
import { num, dim } from './node.js';
|
|
6
|
+
import { getComponents, serializeComponents } from './opaque.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* @typedef {import('./node.js').Node} Node
|
|
@@ -90,7 +91,7 @@ function serializeNumber(v) {
|
|
|
90
91
|
*/
|
|
91
92
|
function serializeScalar(node, prec) {
|
|
92
93
|
const value = round(node.value, prec);
|
|
93
|
-
const text = `${serializeNumber(value)}${node.type === 'Dim' ? node.unit : ''}`;
|
|
94
|
+
const text = `${serializeNumber(value)}${node.type === 'Dim' ? (node.rawUnit ?? node.unit) : ''}`;
|
|
94
95
|
return { value, text };
|
|
95
96
|
}
|
|
96
97
|
|
|
@@ -109,7 +110,7 @@ function serialize(node, opts = {}) {
|
|
|
109
110
|
return `${calcName}(${degenerateKeyword(node.value)})`;
|
|
110
111
|
}
|
|
111
112
|
if (node.type === 'Dim' && isDegenerate(node.value)) {
|
|
112
|
-
return `${calcName}(${degenerateKeyword(node.value)} * 1${node.unit})`;
|
|
113
|
+
return `${calcName}(${degenerateKeyword(node.value)} * 1${node.rawUnit ?? node.unit})`;
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
if (node.type === 'Num' || node.type === 'Dim') {
|
|
@@ -176,14 +177,21 @@ function serializeExpr(node, prec) {
|
|
|
176
177
|
// Nested degenerate Dim wraps in calc() so the `<kw> * 1<unit>` form
|
|
177
178
|
// parses back as one Dim factor. The bare form round-trips wrong
|
|
178
179
|
// inside a Product — `0 * Dim(Infinity, px)` would re-fold as NaN.
|
|
179
|
-
return `calc(${degenerateKeyword(node.value)} * 1${node.unit})`;
|
|
180
|
+
return `calc(${degenerateKeyword(node.value)} * 1${node.rawUnit ?? node.unit})`;
|
|
180
181
|
}
|
|
181
182
|
return serializeScalar(node, prec).text;
|
|
182
183
|
case 'Ident':
|
|
183
|
-
return node.name;
|
|
184
|
+
return node.rawName ?? node.name;
|
|
184
185
|
case 'Call': {
|
|
186
|
+
const components = getComponents(node);
|
|
187
|
+
if (components) {
|
|
188
|
+
const args = node.args
|
|
189
|
+
.map((arg) => serializeExpr(arg, prec))
|
|
190
|
+
.join(', ');
|
|
191
|
+
return `${node.rawName ?? node.name}(${args}${serializeComponents(components, (child) => serialize(child, { precision: prec }))})`;
|
|
192
|
+
}
|
|
185
193
|
const args = node.args.map((a) => serializeExpr(a, prec)).join(', ');
|
|
186
|
-
return `${node.name}(${args})`;
|
|
194
|
+
return `${node.rawName ?? node.name}(${args})`;
|
|
187
195
|
}
|
|
188
196
|
case 'Sum':
|
|
189
197
|
return serializeSum(node, prec);
|
|
@@ -212,7 +220,7 @@ function displaySign(term) {
|
|
|
212
220
|
if (node.type === 'Dim' && Number.isFinite(node.value) && node.value < 0) {
|
|
213
221
|
return {
|
|
214
222
|
sign: /** @type {1 | -1} */ (-sign),
|
|
215
|
-
magnitude: dim(-node.value, node.unit),
|
|
223
|
+
magnitude: dim(-node.value, node.unit, node.rawUnit),
|
|
216
224
|
};
|
|
217
225
|
}
|
|
218
226
|
return { sign, magnitude: node };
|
package/src/lib/simplify/abs.js
CHANGED
|
@@ -9,10 +9,10 @@ import { convert } from '../convertUnits.js';
|
|
|
9
9
|
/**
|
|
10
10
|
* @typedef {object} UnitBucket
|
|
11
11
|
* @property {string} unit
|
|
12
|
+
* @property {string} [rawUnit]
|
|
12
13
|
* @property {number} total
|
|
13
14
|
* @property {number} scale largest |term| accumulated into `total`, for noise detection
|
|
14
15
|
* @property {import('../convertUnits.js').BaseType | null} base
|
|
15
|
-
* @property {number} order
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
/** Mutates `buckets` in place — totals of survivor buckets accumulate the
|
|
@@ -21,32 +21,27 @@ import { convert } from '../convertUnits.js';
|
|
|
21
21
|
* @return {UnitBucket[]}
|
|
22
22
|
*/
|
|
23
23
|
function mergeConvertibleBuckets(buckets) {
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
/** @type {Map<import('../convertUnits.js').BaseType, UnitBucket>} */ const representative =
|
|
25
|
+
new Map();
|
|
26
26
|
/** @type {UnitBucket[]} */ const out = [];
|
|
27
|
-
for (const b of
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
for (const b of buckets) {
|
|
28
|
+
if (b.base === null) {
|
|
29
|
+
out.push(b);
|
|
30
30
|
continue;
|
|
31
31
|
}
|
|
32
|
-
|
|
33
|
-
if (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const converted = convert(other.total, other.unit, b.unit);
|
|
43
|
-
if (converted !== null) {
|
|
44
|
-
b.total += converted;
|
|
45
|
-
merged.add(keyO);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
32
|
+
const first = representative.get(b.base);
|
|
33
|
+
if (!first) {
|
|
34
|
+
representative.set(b.base, b);
|
|
35
|
+
out.push(b);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const converted = convert(b.total, b.unit, first.unit);
|
|
39
|
+
if (converted === null) {
|
|
40
|
+
out.push(b);
|
|
41
|
+
continue;
|
|
48
42
|
}
|
|
49
|
-
|
|
43
|
+
first.total += converted;
|
|
44
|
+
first.scale = Math.max(first.scale, Math.abs(converted));
|
|
50
45
|
}
|
|
51
46
|
return out;
|
|
52
47
|
}
|
package/src/lib/simplify/call.js
CHANGED
|
@@ -17,6 +17,7 @@ import { simplifyLog } from './log.js';
|
|
|
17
17
|
import { simplifyHypot } from './hypot.js';
|
|
18
18
|
|
|
19
19
|
import { call } from '../node.js';
|
|
20
|
+
import { getComponents, setComponents, simplifyComponents } from '../opaque.js';
|
|
20
21
|
|
|
21
22
|
/** @typedef {import('../node.js').Node} Node */
|
|
22
23
|
/** @typedef {import('../simplify.js').SimplifyFn} SimplifyFn */
|
|
@@ -101,6 +102,12 @@ function simplifyCall(node, simplify) {
|
|
|
101
102
|
|
|
102
103
|
const args = node.args.map((a) => simplify(a));
|
|
103
104
|
|
|
105
|
+
const components = getComponents(node);
|
|
106
|
+
if (components) {
|
|
107
|
+
const result = call(node.name, args, node.rawName);
|
|
108
|
+
return setComponents(result, simplifyComponents(components, simplify));
|
|
109
|
+
}
|
|
110
|
+
|
|
104
111
|
const simplifier = MATH_SIMPLIFIERS.get(name);
|
|
105
112
|
if (simplifier) {
|
|
106
113
|
// min/max preserve the call's original casing in their opaque-args
|
|
@@ -111,7 +118,7 @@ function simplifyCall(node, simplify) {
|
|
|
111
118
|
);
|
|
112
119
|
}
|
|
113
120
|
|
|
114
|
-
return call(node.name, args);
|
|
121
|
+
return call(node.name, args, node.rawName);
|
|
115
122
|
}
|
|
116
123
|
|
|
117
124
|
export {
|
|
@@ -15,7 +15,7 @@ import { tryCancelPair } from './cancel.js';
|
|
|
15
15
|
*/
|
|
16
16
|
function simplifyProduct(product, simplify) {
|
|
17
17
|
let coeff = 1;
|
|
18
|
-
/** @type {{exponent: 1 | -1, value: number, unit: string}[]} */
|
|
18
|
+
/** @type {{exponent: 1 | -1, value: number, unit: string, rawUnit?: string}[]} */
|
|
19
19
|
const dims = [];
|
|
20
20
|
/** @type {ProductFactor[]} */
|
|
21
21
|
const opaque = [];
|
|
@@ -54,7 +54,7 @@ function simplifyProduct(product, simplify) {
|
|
|
54
54
|
return;
|
|
55
55
|
}
|
|
56
56
|
if (n.type === 'Dim') {
|
|
57
|
-
dims.push({ exponent, value: n.value, unit: n.unit });
|
|
57
|
+
dims.push({ exponent, value: n.value, unit: n.unit, rawUnit: n.rawUnit });
|
|
58
58
|
scalarChain.push({ exponent, value: n.value });
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
@@ -112,7 +112,7 @@ function simplifyProduct(product, simplify) {
|
|
|
112
112
|
value = value / f.value;
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
|
-
return dim(value, d.unit);
|
|
115
|
+
return dim(value, d.unit, d.rawUnit);
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
if (remainingDims.length === 0 && opaque.length === 0) {
|
|
@@ -125,7 +125,10 @@ function simplifyProduct(product, simplify) {
|
|
|
125
125
|
factors.push({ exponent: 1, node: num(coeff) });
|
|
126
126
|
}
|
|
127
127
|
for (const d of remainingDims) {
|
|
128
|
-
factors.push({
|
|
128
|
+
factors.push({
|
|
129
|
+
exponent: d.exponent,
|
|
130
|
+
node: dim(d.value, d.unit, d.rawUnit),
|
|
131
|
+
});
|
|
129
132
|
}
|
|
130
133
|
factors.push(...opaque);
|
|
131
134
|
|
package/src/lib/simplify/sum.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { mkSum, num, dim } from '../node.js';
|
|
2
|
-
import {
|
|
2
|
+
import { staticBaseOf } from '../convertUnits.js';
|
|
3
3
|
import { mergeConvertibleBuckets } from './bucket.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -39,7 +39,6 @@ function simplifySum(sum, simplify) {
|
|
|
39
39
|
const byUnit = new Map();
|
|
40
40
|
/** @type {SumTerm[]} */
|
|
41
41
|
const opaque = [];
|
|
42
|
-
let bucketOrder = 0;
|
|
43
42
|
|
|
44
43
|
/**
|
|
45
44
|
* @param {1 | -1} sign
|
|
@@ -78,10 +77,10 @@ function simplifySum(sum, simplify) {
|
|
|
78
77
|
} else {
|
|
79
78
|
byUnit.set(key, {
|
|
80
79
|
unit: n.unit,
|
|
80
|
+
rawUnit: n.rawUnit,
|
|
81
81
|
total: sign * n.value,
|
|
82
82
|
scale: Math.abs(n.value),
|
|
83
|
-
base:
|
|
84
|
-
order: bucketOrder++,
|
|
83
|
+
base: staticBaseOf(n.unit),
|
|
85
84
|
});
|
|
86
85
|
}
|
|
87
86
|
return;
|
|
@@ -101,7 +100,11 @@ function simplifySum(sum, simplify) {
|
|
|
101
100
|
for (const bucket of mergeConvertibleBuckets([...byUnit.values()])) {
|
|
102
101
|
terms.push({
|
|
103
102
|
sign: 1,
|
|
104
|
-
node: dim(
|
|
103
|
+
node: dim(
|
|
104
|
+
denoise(bucket.total, bucket.scale),
|
|
105
|
+
bucket.unit,
|
|
106
|
+
bucket.rawUnit
|
|
107
|
+
),
|
|
105
108
|
});
|
|
106
109
|
}
|
|
107
110
|
terms.push(...opaque);
|
package/src/lib/tokenizer.js
CHANGED
|
@@ -1,139 +1,10 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Thin project-local entry point for the CSS Syntax tokenizer. The parser
|
|
2
|
+
// consumes native tokens directly so decoded values and source spelling remain available.
|
|
3
|
+
import { tokenize as tokenizeCss } from '@csstools/css-tokenizer';
|
|
2
4
|
|
|
3
|
-
import
|
|
4
|
-
tokenize as tokenizeCss,
|
|
5
|
-
TokenType as CssType,
|
|
6
|
-
} from '@csstools/css-tokenizer';
|
|
7
|
-
/**
|
|
8
|
-
* @typedef {'number' | 'dimension' | 'ident' | 'punct' | 'eof'} TokenType
|
|
9
|
-
* @typedef {object} Token
|
|
10
|
-
* @property {TokenType} type
|
|
11
|
-
* @property {string} value
|
|
12
|
-
* @property {string} [unit] Present on `dimension` tokens; `%` for percentages.
|
|
13
|
-
* @property {number} pos
|
|
14
|
-
* @property {boolean} ws Whitespace immediately before — drives the §10.1 `+`/`-` rule.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
const PUNCT_DELIMS = new Set(['+', '-', '*', '/']);
|
|
18
|
-
|
|
19
|
-
const NUMERIC_RAW = /^[+-]?(?:\d+(?:\.\d+)?|\.\d+)(?:[eE][+-]?\d+)?/;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* @param {string} input
|
|
23
|
-
* @return {Token[]}
|
|
24
|
-
*/
|
|
5
|
+
/** @param {string} input @return {import('@csstools/css-tokenizer').CSSToken[]} */
|
|
25
6
|
function tokenize(input) {
|
|
26
|
-
return
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* CSS absorbs leading signs (`-5px` is one token); the parser expects
|
|
31
|
-
* punct sign + unsigned numeric, so split them back out.
|
|
32
|
-
* @param {Token[]} tokens
|
|
33
|
-
* @param {string} raw
|
|
34
|
-
* @param {string | undefined} unit
|
|
35
|
-
* @param {number} pos
|
|
36
|
-
* @param {boolean} ws
|
|
37
|
-
* @return {void}
|
|
38
|
-
*/
|
|
39
|
-
function pushNumeric(tokens, raw, unit, pos, ws) {
|
|
40
|
-
let value = /** @type {RegExpExecArray} */ (NUMERIC_RAW.exec(raw))[0];
|
|
41
|
-
const sign = value[0];
|
|
42
|
-
if (sign === '+' || sign === '-') {
|
|
43
|
-
tokens.push({ type: 'punct', value: sign, pos, ws });
|
|
44
|
-
value = value.slice(1);
|
|
45
|
-
pos += 1;
|
|
46
|
-
ws = false;
|
|
47
|
-
}
|
|
48
|
-
if (unit === undefined) {
|
|
49
|
-
tokens.push({ type: 'number', value, pos, ws });
|
|
50
|
-
} else {
|
|
51
|
-
tokens.push({ type: 'dimension', value, unit, pos, ws });
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Convert a slice of an existing CSS token stream into the token subset used
|
|
57
|
-
* by the calculation parser. Token positions remain relative to the original
|
|
58
|
-
* source text, which keeps parse errors useful to adapter callers.
|
|
59
|
-
*
|
|
60
|
-
* @param {import('@csstools/css-tokenizer').CSSToken[]} cssTokens
|
|
61
|
-
* @param {number} eofPosition
|
|
62
|
-
* @param {number} [start]
|
|
63
|
-
* @param {number} [end]
|
|
64
|
-
* @return {Token[]}
|
|
65
|
-
*/
|
|
66
|
-
function tokenizeTokens(
|
|
67
|
-
cssTokens,
|
|
68
|
-
eofPosition,
|
|
69
|
-
start = 0,
|
|
70
|
-
end = cssTokens.length
|
|
71
|
-
) {
|
|
72
|
-
/** @type {Token[]} */
|
|
73
|
-
const tokens = [];
|
|
74
|
-
let ws = true;
|
|
75
|
-
|
|
76
|
-
for (let i = start; i < end; i++) {
|
|
77
|
-
const t = cssTokens[i];
|
|
78
|
-
switch (t[0]) {
|
|
79
|
-
case CssType.Whitespace:
|
|
80
|
-
case CssType.Comment:
|
|
81
|
-
ws = true;
|
|
82
|
-
continue;
|
|
83
|
-
case CssType.Number:
|
|
84
|
-
pushNumeric(tokens, t[1], undefined, t[2], ws);
|
|
85
|
-
ws = false;
|
|
86
|
-
continue;
|
|
87
|
-
case CssType.Dimension:
|
|
88
|
-
pushNumeric(tokens, t[1], t[4].unit, t[2], ws);
|
|
89
|
-
ws = false;
|
|
90
|
-
continue;
|
|
91
|
-
case CssType.Percentage:
|
|
92
|
-
pushNumeric(tokens, t[1], '%', t[2], ws);
|
|
93
|
-
ws = false;
|
|
94
|
-
continue;
|
|
95
|
-
case CssType.Ident:
|
|
96
|
-
tokens.push({ type: 'ident', value: t[4].value, pos: t[2], ws });
|
|
97
|
-
break;
|
|
98
|
-
case CssType.Function:
|
|
99
|
-
tokens.push({ type: 'ident', value: t[4].value, pos: t[2], ws });
|
|
100
|
-
tokens.push({
|
|
101
|
-
type: 'punct',
|
|
102
|
-
value: '(',
|
|
103
|
-
pos: t[2] + t[1].length - 1,
|
|
104
|
-
ws: false,
|
|
105
|
-
});
|
|
106
|
-
break;
|
|
107
|
-
case CssType.OpenParen:
|
|
108
|
-
tokens.push({ type: 'punct', value: '(', pos: t[2], ws });
|
|
109
|
-
break;
|
|
110
|
-
case CssType.CloseParen:
|
|
111
|
-
tokens.push({ type: 'punct', value: ')', pos: t[2], ws });
|
|
112
|
-
break;
|
|
113
|
-
case CssType.Comma:
|
|
114
|
-
tokens.push({ type: 'punct', value: ',', pos: t[2], ws });
|
|
115
|
-
break;
|
|
116
|
-
case CssType.Delim:
|
|
117
|
-
if (!PUNCT_DELIMS.has(t[4].value)) {
|
|
118
|
-
throw new Error(
|
|
119
|
-
`Unexpected character "${t[4].value}" at position ${t[2]}`
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
tokens.push({ type: 'punct', value: t[4].value, pos: t[2], ws });
|
|
123
|
-
break;
|
|
124
|
-
case CssType.EOF:
|
|
125
|
-
continue;
|
|
126
|
-
default:
|
|
127
|
-
throw new Error(
|
|
128
|
-
`Unexpected character "${t[1][0] ?? ''}" at position ${t[2]}`
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
ws = false;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
tokens.push({ type: 'eof', value: '', pos: eofPosition, ws });
|
|
135
|
-
|
|
136
|
-
return tokens;
|
|
7
|
+
return tokenizeCss({ css: input });
|
|
137
8
|
}
|
|
138
9
|
|
|
139
|
-
export { tokenize
|
|
10
|
+
export { tokenize };
|
package/src/reduce.js
CHANGED
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
tokenize as cssTokenize,
|
|
6
6
|
TokenType as CssType,
|
|
7
7
|
} from '@csstools/css-tokenizer';
|
|
8
|
-
import { tokenizeTokens } from './lib/tokenizer.js';
|
|
9
8
|
import { parse } from './lib/parser.js';
|
|
10
9
|
import { simplify } from './lib/simplify.js';
|
|
11
10
|
import {
|
|
@@ -95,9 +94,7 @@ function walkTokens(start, expectedClose, ctx, transform) {
|
|
|
95
94
|
const inputEnd = closed && isCalc ? ctx.tokens[close][2] : end;
|
|
96
95
|
const contents = ctx.value.slice(inputStart, inputEnd);
|
|
97
96
|
try {
|
|
98
|
-
const node = simplify(
|
|
99
|
-
parse(tokenizeTokens(ctx.tokens, end, sliceStart, sliceEnd))
|
|
100
|
-
);
|
|
97
|
+
const node = simplify(parse(ctx.tokens, sliceStart, sliceEnd));
|
|
101
98
|
ctx.replacements.push({
|
|
102
99
|
start: token[2],
|
|
103
100
|
end,
|
|
@@ -14,4 +14,11 @@ declare function baseOf(unit: string): BaseType | null;
|
|
|
14
14
|
* @return {number | null}
|
|
15
15
|
*/
|
|
16
16
|
declare function convert(value: number, from: string, to: string): number | null;
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* Return a base type only for units present in the static conversion table.
|
|
19
|
+
* Units with context-dependent values (em, rem, vw, etc.) return null.
|
|
20
|
+
* @param {string} unit
|
|
21
|
+
* @return {BaseType | null}
|
|
22
|
+
*/
|
|
23
|
+
declare function staticBaseOf(unit: string): BaseType | null;
|
|
24
|
+
export { baseOf, staticBaseOf, convert };
|
package/types/lib/node.d.ts
CHANGED
|
@@ -6,15 +6,18 @@ export type Dim = {
|
|
|
6
6
|
type: 'Dim';
|
|
7
7
|
value: number;
|
|
8
8
|
unit: string;
|
|
9
|
+
rawUnit?: string;
|
|
9
10
|
};
|
|
10
11
|
export type Ident = {
|
|
11
12
|
type: 'Ident';
|
|
12
13
|
name: string;
|
|
14
|
+
rawName?: string;
|
|
13
15
|
};
|
|
14
16
|
export type Call = {
|
|
15
17
|
type: 'Call';
|
|
16
18
|
name: string;
|
|
17
19
|
args: Node[];
|
|
20
|
+
rawName?: string;
|
|
18
21
|
};
|
|
19
22
|
export type SumTerm = {
|
|
20
23
|
sign: 1 | -1;
|
|
@@ -36,9 +39,9 @@ export type Product = {
|
|
|
36
39
|
export type Node = Num | Dim | Ident | Call | Sum | Product;
|
|
37
40
|
/**
|
|
38
41
|
* @typedef {{type: 'Num', value: number}} Num
|
|
39
|
-
* @typedef {{type: 'Dim', value: number, unit: string}} Dim
|
|
40
|
-
* @typedef {{type: 'Ident', name: string}} Ident
|
|
41
|
-
* @typedef {{type: 'Call', name: string, args: Node[]}} Call
|
|
42
|
+
* @typedef {{type: 'Dim', value: number, unit: string, rawUnit?: string}} Dim
|
|
43
|
+
* @typedef {{type: 'Ident', name: string, rawName?: string}} Ident
|
|
44
|
+
* @typedef {{type: 'Call', name: string, args: Node[], rawName?: string}} Call
|
|
42
45
|
* @typedef {{sign: 1 | -1, node: Node}} SumTerm Sign is always +1 when node is Num or Dim.
|
|
43
46
|
* @typedef {{type: 'Sum', terms: SumTerm[], grouped?: boolean}} Sum
|
|
44
47
|
* @typedef {{exponent: 1 | -1, node: Node}} ProductFactor exponent +1 = numerator, -1 = denominator.
|
|
@@ -53,20 +56,23 @@ declare function num(value: number): Num;
|
|
|
53
56
|
/**
|
|
54
57
|
* @param {number} value
|
|
55
58
|
* @param {string} unit
|
|
59
|
+
* @param {string} [rawUnit]
|
|
56
60
|
* @return {Dim}
|
|
57
61
|
*/
|
|
58
|
-
declare function dim(value: number, unit: string): Dim;
|
|
62
|
+
declare function dim(value: number, unit: string, rawUnit?: string): Dim;
|
|
59
63
|
/**
|
|
60
64
|
* @param {string} name
|
|
65
|
+
* @param {string} [rawName]
|
|
61
66
|
* @return {Ident}
|
|
62
67
|
*/
|
|
63
|
-
declare function ident(name: string): Ident;
|
|
68
|
+
declare function ident(name: string, rawName?: string): Ident;
|
|
64
69
|
/**
|
|
65
70
|
* @param {string} name
|
|
66
71
|
* @param {Node[]} args
|
|
72
|
+
* @param {string} [rawName]
|
|
67
73
|
* @return {Call}
|
|
68
74
|
*/
|
|
69
|
-
declare function call(name: string, args: Node[]): Call;
|
|
75
|
+
declare function call(name: string, args: Node[], rawName?: string): Call;
|
|
70
76
|
/**
|
|
71
77
|
* @param {SumTerm[]} rawTerms
|
|
72
78
|
* @return {Node}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type Node = import('./node.js').Node;
|
|
2
|
+
export type Component = string | Node | Component[];
|
|
3
|
+
/** @param {Extract<Node, {type: 'Call'}>} node @param {Component[]} tree */
|
|
4
|
+
declare function setComponents(node: Extract<Node, {
|
|
5
|
+
type: 'Call';
|
|
6
|
+
}>, tree: Component[]): import("./node.js").Call;
|
|
7
|
+
/** @param {Extract<Node, {type: 'Call'}>} node */
|
|
8
|
+
declare function getComponents(node: Extract<Node, {
|
|
9
|
+
type: 'Call';
|
|
10
|
+
}>): Component[] | undefined;
|
|
11
|
+
/** @param {Component[]} tree @param {(node: Node) => Node} simplify @return {Component[]} */
|
|
12
|
+
declare function simplifyComponents(tree: Component[], simplify: (node: Node) => Node): Component[];
|
|
13
|
+
/** @param {Component[]} tree @param {(node: Node) => string} serialize @return {string} */
|
|
14
|
+
declare function serializeComponents(tree: Component[], serialize: (node: Node) => string): string;
|
|
15
|
+
export { getComponents, setComponents, simplifyComponents, serializeComponents, };
|
package/types/lib/parser.d.ts
CHANGED
|
@@ -1,51 +1,55 @@
|
|
|
1
|
-
export type
|
|
2
|
-
export type TokenType = import('./tokenizer.js').TokenType;
|
|
1
|
+
export type CSSToken = import('@csstools/css-tokenizer').CSSToken;
|
|
3
2
|
export type Node = import('./node.js').Node;
|
|
3
|
+
export type Component = string | Node | Component[];
|
|
4
|
+
export type Token = {
|
|
5
|
+
type: 'number' | 'dimension' | 'ident' | 'function' | 'punct' | 'eof';
|
|
6
|
+
value: string | number;
|
|
7
|
+
raw: string;
|
|
8
|
+
unit?: string;
|
|
9
|
+
rawUnit?: string;
|
|
10
|
+
signCharacter?: '+' | '-';
|
|
11
|
+
pos: number;
|
|
12
|
+
ws: boolean;
|
|
13
|
+
};
|
|
4
14
|
export type PrefixParselet = (p: Parser, token: Token) => Node;
|
|
15
|
+
/** Bounded cursor that skips trivia but records whether it preceded a token. */
|
|
5
16
|
declare class Parser {
|
|
6
|
-
|
|
7
|
-
i;
|
|
8
|
-
/** @private @readonly */
|
|
9
|
-
tokens;
|
|
17
|
+
#private;
|
|
10
18
|
/**
|
|
11
|
-
* @param {
|
|
19
|
+
* @param {CSSToken[]} tokens
|
|
20
|
+
* @param {number} start
|
|
21
|
+
* @param {number} end
|
|
22
|
+
* @param {Map<number, number>} [ends]
|
|
12
23
|
*/
|
|
13
|
-
constructor(tokens:
|
|
24
|
+
constructor(tokens: CSSToken[], start: number, end: number, ends?: Map<number, number>);
|
|
25
|
+
/** @return {Map<number, number>} */
|
|
26
|
+
get ends(): Map<number, number>;
|
|
27
|
+
/** @return {number} */
|
|
28
|
+
eofPosition(): number;
|
|
29
|
+
/** @return {Token} */
|
|
30
|
+
read(): Token;
|
|
14
31
|
/** @return {Token} */
|
|
15
32
|
peek(): Token;
|
|
16
33
|
/** @return {Token} */
|
|
17
34
|
next(): Token;
|
|
18
|
-
/**
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
*/
|
|
35
|
+
/** @return {{start: number, close: number, tokens: CSSToken[], ends: Map<number, number>}} */
|
|
36
|
+
functionRange(): {
|
|
37
|
+
start: number;
|
|
38
|
+
close: number;
|
|
39
|
+
tokens: CSSToken[];
|
|
40
|
+
ends: Map<number, number>;
|
|
41
|
+
};
|
|
42
|
+
/** @param {number} index */
|
|
43
|
+
consumeThrough(index: number): void;
|
|
44
|
+
/** @param {string} value @param {string} [value2] @return {boolean} */
|
|
29
45
|
isPunct(value: string, value2?: string): boolean;
|
|
30
|
-
/**
|
|
31
|
-
* @param {string} value
|
|
32
|
-
* @return {boolean}
|
|
33
|
-
*/
|
|
46
|
+
/** @param {string} value @return {boolean} */
|
|
34
47
|
matchPunct(value: string): boolean;
|
|
35
|
-
/**
|
|
36
|
-
* @param {string} value
|
|
37
|
-
* @return {Token}
|
|
38
|
-
*/
|
|
48
|
+
/** @param {string} value @return {Token} */
|
|
39
49
|
expectPunct(value: string): Token;
|
|
40
|
-
/**
|
|
41
|
-
* @param {number} [minBp]
|
|
42
|
-
* @return {Node}
|
|
43
|
-
*/
|
|
50
|
+
/** @param {number} [minBp] @return {Node} */
|
|
44
51
|
parseExpr(minBp?: number): Node;
|
|
45
52
|
}
|
|
46
|
-
/**
|
|
47
|
-
|
|
48
|
-
* @return {Node}
|
|
49
|
-
*/
|
|
50
|
-
declare function parse(tokens: Token[]): Node;
|
|
53
|
+
/** @param {CSSToken[]} tokens @param {number} [start] @param {number} [end] @return {Node} */
|
|
54
|
+
declare function parse(tokens: CSSToken[], start?: number, end?: number): Node;
|
|
51
55
|
export { parse };
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
export type UnitBucket = {
|
|
2
2
|
unit: string;
|
|
3
|
+
rawUnit?: string;
|
|
3
4
|
total: number;
|
|
4
5
|
/**
|
|
5
6
|
* largest |term| accumulated into `total`, for noise detection
|
|
6
7
|
*/
|
|
7
8
|
scale: number;
|
|
8
9
|
base: import('../convertUnits.js').BaseType | null;
|
|
9
|
-
order: number;
|
|
10
10
|
};
|
|
11
11
|
/**
|
|
12
12
|
* @typedef {object} UnitBucket
|
|
13
13
|
* @property {string} unit
|
|
14
|
+
* @property {string} [rawUnit]
|
|
14
15
|
* @property {number} total
|
|
15
16
|
* @property {number} scale largest |term| accumulated into `total`, for noise detection
|
|
16
17
|
* @property {import('../convertUnits.js').BaseType | null} base
|
|
17
|
-
* @property {number} order
|
|
18
18
|
*/
|
|
19
19
|
/** Mutates `buckets` in place — totals of survivor buckets accumulate the
|
|
20
20
|
* converted values of merged neighbors. Caller must not reuse the input.
|
package/types/lib/tokenizer.d.ts
CHANGED
|
@@ -1,32 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
value: string;
|
|
5
|
-
/**
|
|
6
|
-
* Present on `dimension` tokens; `%` for percentages.
|
|
7
|
-
*/
|
|
8
|
-
unit?: string;
|
|
9
|
-
pos: number;
|
|
10
|
-
/**
|
|
11
|
-
* Whitespace immediately before — drives the §10.1 `+`/`-` rule.
|
|
12
|
-
*/
|
|
13
|
-
ws: boolean;
|
|
14
|
-
};
|
|
15
|
-
/**
|
|
16
|
-
* @param {string} input
|
|
17
|
-
* @return {Token[]}
|
|
18
|
-
*/
|
|
19
|
-
declare function tokenize(input: string): Token[];
|
|
20
|
-
/**
|
|
21
|
-
* Convert a slice of an existing CSS token stream into the token subset used
|
|
22
|
-
* by the calculation parser. Token positions remain relative to the original
|
|
23
|
-
* source text, which keeps parse errors useful to adapter callers.
|
|
24
|
-
*
|
|
25
|
-
* @param {import('@csstools/css-tokenizer').CSSToken[]} cssTokens
|
|
26
|
-
* @param {number} eofPosition
|
|
27
|
-
* @param {number} [start]
|
|
28
|
-
* @param {number} [end]
|
|
29
|
-
* @return {Token[]}
|
|
30
|
-
*/
|
|
31
|
-
declare function tokenizeTokens(cssTokens: import('@csstools/css-tokenizer').CSSToken[], eofPosition: number, start?: number, end?: number): Token[];
|
|
32
|
-
export { tokenize, tokenizeTokens };
|
|
1
|
+
/** @param {string} input @return {import('@csstools/css-tokenizer').CSSToken[]} */
|
|
2
|
+
declare function tokenize(input: string): import('@csstools/css-tokenizer').CSSToken[];
|
|
3
|
+
export { tokenize };
|