webpack 5.108.1 → 5.108.3
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/lib/CleanPlugin.js +8 -25
- package/lib/Compilation.js +0 -1
- package/lib/DefinePlugin.js +8 -19
- package/lib/ExternalModule.js +64 -19
- package/lib/ExternalModuleFactoryPlugin.js +37 -1
- package/lib/LazyBarrel.js +4 -3
- package/lib/NormalModule.js +49 -59
- package/lib/bun/BunTargetPlugin.js +1 -7
- package/lib/container/ModuleFederationPlugin.js +9 -25
- package/lib/css/CssInjectStyleRuntimeModule.js +9 -24
- package/lib/css/CssLoadingRuntimeModule.js +12 -27
- package/lib/css/CssModulesPlugin.js +15 -31
- package/lib/css/CssParser.js +421 -381
- package/lib/css/syntax.js +768 -305
- package/lib/deno/DenoTargetPlugin.js +1 -7
- package/lib/dependencies/HarmonyAcceptDependency.js +8 -16
- package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +22 -0
- package/lib/dependencies/HarmonyImportDependency.js +2 -0
- package/lib/dependencies/ImportMetaPlugin.js +9 -25
- package/lib/esm/ModuleChunkLoadingRuntimeModule.js +10 -26
- package/lib/javascript/JavascriptModulesPlugin.js +38 -54
- package/lib/node/NodeTargetPlugin.js +1 -62
- package/lib/node/nodeBuiltins.js +80 -0
- package/lib/optimize/ConcatenatedModule.js +17 -27
- package/lib/optimize/RealContentHashPlugin.js +8 -24
- package/lib/runtime/LoadScriptRuntimeModule.js +9 -24
- package/lib/util/createHooksRegistry.js +35 -0
- package/lib/wasm-async/AsyncWebAssemblyModulesPlugin.js +12 -29
- package/lib/web/JsonpChunkLoadingRuntimeModule.js +10 -25
- package/package.json +1 -1
- package/types.d.ts +84 -71
package/lib/css/syntax.js
CHANGED
|
@@ -209,7 +209,6 @@ const CC_EXCLAMATION = "!".charCodeAt(0);
|
|
|
209
209
|
const CC_UPPER_A = "A".charCodeAt(0);
|
|
210
210
|
const CC_UPPER_F = "F".charCodeAt(0);
|
|
211
211
|
const CC_UPPER_E = "E".charCodeAt(0);
|
|
212
|
-
const CC_UPPER_U = "U".charCodeAt(0);
|
|
213
212
|
const CC_UPPER_Z = "Z".charCodeAt(0);
|
|
214
213
|
const CC_0 = "0".charCodeAt(0);
|
|
215
214
|
const CC_9 = "9".charCodeAt(0);
|
|
@@ -298,18 +297,6 @@ const _isSpace = (cc) => cc === CC_SPACE || cc === CC_TAB;
|
|
|
298
297
|
// rarer tab / newline tests.
|
|
299
298
|
const _isWhiteSpace = (cc) => _isSpace(cc) || _isNewline(cc);
|
|
300
299
|
|
|
301
|
-
/**
|
|
302
|
-
* ident-start code point per the spec: a letter, a non-ASCII code point,
|
|
303
|
-
* or U+005F LOW LINE (`_`).
|
|
304
|
-
* @param {number} cc char code
|
|
305
|
-
* @returns {boolean} true, if cc is an ident-start code point
|
|
306
|
-
*/
|
|
307
|
-
const isIdentStartCodePoint = (cc) =>
|
|
308
|
-
(cc >= CC_LOWER_A && cc <= CC_LOWER_Z) ||
|
|
309
|
-
(cc >= CC_UPPER_A && cc <= CC_UPPER_Z) ||
|
|
310
|
-
cc === CC_LOW_LINE ||
|
|
311
|
-
cc >= 0x80;
|
|
312
|
-
|
|
313
300
|
/**
|
|
314
301
|
* @param {number} cc char code
|
|
315
302
|
* @returns {boolean} true, if cc is a digit
|
|
@@ -482,11 +469,17 @@ const _ifThreeCodePointsWouldStartANumber = (input, pos, f, s, t) => {
|
|
|
482
469
|
* @returns {number} position just past the last ident-sequence code point
|
|
483
470
|
*/
|
|
484
471
|
const _consumeAnIdentSequence = (input, pos) => {
|
|
472
|
+
// Hot loop (every ident, at-keyword, hash, function name, unit). Both checks
|
|
473
|
+
// are inlined from `_isIdentCodePoint` / `_ifTwoCodePointsAreValidEscape`: the
|
|
474
|
+
// ASCII ident test is a single table load, and the escape test reads the
|
|
475
|
+
// following code point only when `cc` is a `\` (rare) instead of eagerly.
|
|
485
476
|
for (;;) {
|
|
486
477
|
const cc = input.charCodeAt(pos);
|
|
487
478
|
pos++;
|
|
488
|
-
if (
|
|
489
|
-
|
|
479
|
+
if (cc < 128 ? _identCharTable[cc] === 1 : _isIdentStartCodePointCC(cc)) {
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
if (cc === CC_REVERSE_SOLIDUS && !_isNewline(input.charCodeAt(pos))) {
|
|
490
483
|
pos = _consumeAnEscapedCodePoint(input, pos);
|
|
491
484
|
continue;
|
|
492
485
|
}
|
|
@@ -950,6 +943,96 @@ function consumeReverseSolidus(input, pos, out) {
|
|
|
950
943
|
return fill(out, TT_DELIM, pos - 1, pos);
|
|
951
944
|
}
|
|
952
945
|
|
|
946
|
+
// `consumeAToken` dispatch: the §4 token rules keyed by the lead code point are
|
|
947
|
+
// === Tokenizer lead-character dispatch (CSS Syntax Level 3 §4 "consume a token") ===
|
|
948
|
+
//
|
|
949
|
+
// `consumeAToken` selects a sub-routine from the first ("lead") code point of each
|
|
950
|
+
// token. The §4 rules are keyed on specific code points (`"` `#` `(` digit
|
|
951
|
+
// ident-start …) that sit SPARSELY across the ASCII range, so a plain `switch (cc)`
|
|
952
|
+
// compiles to a jump table spanning U+0009..U+007D in which the most common lead —
|
|
953
|
+
// an ident-start letter — is not a case and reaches its handler only after the
|
|
954
|
+
// digit/whitespace tests miss. `_charClass` precomputes, for every ASCII code
|
|
955
|
+
// point, a dense handler id (`HC_*`, 0..12) so `consumeAToken` is one array load +
|
|
956
|
+
// a compact 13-entry jump table and idents dispatch directly. Non-ASCII
|
|
957
|
+
// (cc >= 128) is always ident-start per §4, so it skips the table.
|
|
958
|
+
//
|
|
959
|
+
// Extending for a spec change: repoint the code point in the build loop below; if
|
|
960
|
+
// it needs a new sub-routine, add an `HC_*` id, a `case` in `consumeAToken`, and a
|
|
961
|
+
// row here. This list is the authoritative "which lead code point dispatches
|
|
962
|
+
// where" map (§4 "consume a token", step by lead code point):
|
|
963
|
+
//
|
|
964
|
+
// HC_WHITESPACE whitespace U+0009 TAB U+000A LF U+000C FF U+000D CR U+0020 SPACE
|
|
965
|
+
// HC_STRING string start U+0022 " U+0027 '
|
|
966
|
+
// HC_SINGLE one-char token ( ) , : ; [ ] { } (its token type comes from `_singleTT`)
|
|
967
|
+
// HC_NUMBER_SIGN hash / delim U+0023 #
|
|
968
|
+
// HC_PLUS_SIGN number / delim U+002B +
|
|
969
|
+
// HC_HYPHEN_MINUS number / CDC / ident / delim U+002D -
|
|
970
|
+
// HC_FULL_STOP number / delim U+002E .
|
|
971
|
+
// HC_LESS_THAN CDO / delim U+003C <
|
|
972
|
+
// HC_AT_SIGN at-keyword / delim U+0040 @
|
|
973
|
+
// HC_REVERSE_SOLIDUS escape / delim U+005C \
|
|
974
|
+
// HC_DIGIT number U+0030..U+0039 0-9
|
|
975
|
+
// HC_IDENT ident-like U+0041..U+005A A-Z U+0061..U+007A a-z U+005F _ (plus cc >= 128)
|
|
976
|
+
// HC_DELIM anything else -> a single <delim-token>
|
|
977
|
+
//
|
|
978
|
+
// `_singleTT[cc]` is the token type for the HC_SINGLE code points (a second table
|
|
979
|
+
// so they share one handler instead of one `case` each). The default class 0 is
|
|
980
|
+
// the delim handler (anything not matched below), so it needs no named constant.
|
|
981
|
+
const HC_WHITESPACE = 1;
|
|
982
|
+
const HC_STRING = 2;
|
|
983
|
+
const HC_SINGLE = 3;
|
|
984
|
+
const HC_NUMBER_SIGN = 4;
|
|
985
|
+
const HC_PLUS_SIGN = 5;
|
|
986
|
+
const HC_HYPHEN_MINUS = 6;
|
|
987
|
+
const HC_FULL_STOP = 7;
|
|
988
|
+
const HC_LESS_THAN = 8;
|
|
989
|
+
const HC_AT_SIGN = 9;
|
|
990
|
+
const HC_REVERSE_SOLIDUS = 10;
|
|
991
|
+
const HC_DIGIT = 11;
|
|
992
|
+
const HC_IDENT = 12;
|
|
993
|
+
const _charClass = new Uint8Array(128);
|
|
994
|
+
const _singleTT = new Uint8Array(128);
|
|
995
|
+
_singleTT[CC_LEFT_PARENTHESIS] = TT_LEFT_PARENTHESIS;
|
|
996
|
+
_singleTT[CC_RIGHT_PARENTHESIS] = TT_RIGHT_PARENTHESIS;
|
|
997
|
+
_singleTT[CC_COMMA] = TT_COMMA;
|
|
998
|
+
_singleTT[CC_COLON] = TT_COLON;
|
|
999
|
+
_singleTT[CC_SEMICOLON] = TT_SEMICOLON;
|
|
1000
|
+
_singleTT[CC_LEFT_SQUARE] = TT_LEFT_SQUARE_BRACKET;
|
|
1001
|
+
_singleTT[CC_RIGHT_SQUARE] = TT_RIGHT_SQUARE_BRACKET;
|
|
1002
|
+
_singleTT[CC_LEFT_CURLY] = TT_LEFT_CURLY_BRACKET;
|
|
1003
|
+
_singleTT[CC_RIGHT_CURLY] = TT_RIGHT_CURLY_BRACKET;
|
|
1004
|
+
// Each ASCII code point belongs to exactly one class; HC_SINGLE is seeded from
|
|
1005
|
+
// `_singleTT` above, the rest follow §4's lead-code-point rules, and everything
|
|
1006
|
+
// unmatched stays the delim class (0). Keep this in sync with the table above.
|
|
1007
|
+
for (let i = 0; i < 128; i++) {
|
|
1008
|
+
if (_singleTT[i] !== 0) {
|
|
1009
|
+
_charClass[i] = HC_SINGLE;
|
|
1010
|
+
} else if (_isWhiteSpace(i)) {
|
|
1011
|
+
_charClass[i] = HC_WHITESPACE;
|
|
1012
|
+
} else if (i === CC_QUOTATION_MARK || i === CC_APOSTROPHE) {
|
|
1013
|
+
_charClass[i] = HC_STRING;
|
|
1014
|
+
} else if (i === CC_NUMBER_SIGN) {
|
|
1015
|
+
_charClass[i] = HC_NUMBER_SIGN;
|
|
1016
|
+
} else if (i === CC_PLUS_SIGN) {
|
|
1017
|
+
_charClass[i] = HC_PLUS_SIGN;
|
|
1018
|
+
} else if (i === CC_HYPHEN_MINUS) {
|
|
1019
|
+
_charClass[i] = HC_HYPHEN_MINUS;
|
|
1020
|
+
} else if (i === CC_FULL_STOP) {
|
|
1021
|
+
_charClass[i] = HC_FULL_STOP;
|
|
1022
|
+
} else if (i === CC_LESS_THAN_SIGN) {
|
|
1023
|
+
_charClass[i] = HC_LESS_THAN;
|
|
1024
|
+
} else if (i === CC_AT_SIGN) {
|
|
1025
|
+
_charClass[i] = HC_AT_SIGN;
|
|
1026
|
+
} else if (i === CC_REVERSE_SOLIDUS) {
|
|
1027
|
+
_charClass[i] = HC_REVERSE_SOLIDUS;
|
|
1028
|
+
} else if (_isDigit(i)) {
|
|
1029
|
+
_charClass[i] = HC_DIGIT;
|
|
1030
|
+
} else if (_isIdentStartCodePointCC(i)) {
|
|
1031
|
+
_charClass[i] = HC_IDENT;
|
|
1032
|
+
}
|
|
1033
|
+
// else stays the delim class (0)
|
|
1034
|
+
}
|
|
1035
|
+
|
|
953
1036
|
/**
|
|
954
1037
|
* Per-character dispatcher. The outer loop has already advanced past
|
|
955
1038
|
* the lead code point (`pos - 1` is the lead).
|
|
@@ -960,65 +1043,50 @@ function consumeReverseSolidus(input, pos, out) {
|
|
|
960
1043
|
* @returns {MutableToken | undefined} the resulting token, or undefined at EOF
|
|
961
1044
|
*/
|
|
962
1045
|
function consumeAToken(input, pos, cc, out) {
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
case
|
|
968
|
-
case CC_SPACE:
|
|
1046
|
+
// `u` / `U` would start a unicode-range token in the spec; those are not
|
|
1047
|
+
// produced, so they map to HC_IDENT and fall through to ident-like.
|
|
1048
|
+
switch (cc < 128 ? _charClass[cc] : HC_IDENT) {
|
|
1049
|
+
// Run of whitespace → one <whitespace-token>.
|
|
1050
|
+
case HC_WHITESPACE:
|
|
969
1051
|
return consumeSpace(input, pos, out);
|
|
970
|
-
|
|
971
|
-
case
|
|
1052
|
+
// `"` / `'` → <string-token> (or <bad-string-token> on a raw newline).
|
|
1053
|
+
case HC_STRING:
|
|
972
1054
|
return consumeAStringToken(input, pos, out);
|
|
973
|
-
|
|
1055
|
+
// One-code-point token: its type is looked up in `_singleTT` (the `(` `)`
|
|
1056
|
+
// `,` `:` `;` `[` `]` `{` `}` set), so all of them share this arm.
|
|
1057
|
+
case HC_SINGLE:
|
|
1058
|
+
return fill(out, _singleTT[cc], pos - 1, pos);
|
|
1059
|
+
// `#` → <hash-token> if an ident/escape follows, else a <delim-token>.
|
|
1060
|
+
case HC_NUMBER_SIGN:
|
|
974
1061
|
return consumeNumberSign(input, pos, out);
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
case CC_RIGHT_PARENTHESIS:
|
|
978
|
-
return fill(out, TT_RIGHT_PARENTHESIS, pos - 1, pos);
|
|
979
|
-
case CC_PLUS_SIGN:
|
|
1062
|
+
// `+` → <number-token> if it starts a number, else a <delim-token>.
|
|
1063
|
+
case HC_PLUS_SIGN:
|
|
980
1064
|
return consumePlusSign(input, pos, out);
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
case CC_HYPHEN_MINUS:
|
|
1065
|
+
// `-` → number / <CDC-token> (`-->`) / ident / <delim-token>.
|
|
1066
|
+
case HC_HYPHEN_MINUS:
|
|
984
1067
|
return consumeHyphenMinus(input, pos, out);
|
|
985
|
-
|
|
1068
|
+
// `.` → <number-token> if a digit follows, else a <delim-token>.
|
|
1069
|
+
case HC_FULL_STOP:
|
|
986
1070
|
return consumeFullStop(input, pos, out);
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
case CC_SEMICOLON:
|
|
990
|
-
return fill(out, TT_SEMICOLON, pos - 1, pos);
|
|
991
|
-
case CC_LESS_THAN_SIGN:
|
|
1071
|
+
// `<` → <CDO-token> (`<!--`), else a <delim-token>.
|
|
1072
|
+
case HC_LESS_THAN:
|
|
992
1073
|
return consumeLessThan(input, pos, out);
|
|
993
|
-
|
|
1074
|
+
// `@` → <at-keyword-token> if an ident follows, else a <delim-token>.
|
|
1075
|
+
case HC_AT_SIGN:
|
|
994
1076
|
return consumeCommercialAt(input, pos, out);
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
case CC_REVERSE_SOLIDUS:
|
|
1077
|
+
// `\` → ident-like token if it's a valid escape, else a <delim-token>.
|
|
1078
|
+
case HC_REVERSE_SOLIDUS:
|
|
998
1079
|
return consumeReverseSolidus(input, pos, out);
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1080
|
+
// Digit → numeric token; `pos - 1` re-includes the digit the caller passed.
|
|
1081
|
+
case HC_DIGIT:
|
|
1082
|
+
return consumeANumericToken(input, pos - 1, out);
|
|
1083
|
+
// Ident-start (letter / `_` / non-ASCII, incl. `u`/`U`) → ident / function /
|
|
1084
|
+
// url token; `pos - 1` re-includes the lead code point.
|
|
1085
|
+
case HC_IDENT:
|
|
1086
|
+
return consumeAnIdentLikeToken(input, pos - 1, out);
|
|
1005
1087
|
default:
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
return consumeANumericToken(input, pos, out);
|
|
1009
|
-
}
|
|
1010
|
-
if (cc === CC_LOWER_U || cc === CC_UPPER_U) {
|
|
1011
|
-
// Unicode-range tokens are not produced — fall back to
|
|
1012
|
-
// ident-like to match the existing tokenizer's behaviour.
|
|
1013
|
-
pos--;
|
|
1014
|
-
return consumeAnIdentLikeToken(input, pos, out);
|
|
1015
|
-
}
|
|
1016
|
-
if (isIdentStartCodePoint(cc)) {
|
|
1017
|
-
pos--;
|
|
1018
|
-
return consumeAnIdentLikeToken(input, pos, out);
|
|
1019
|
-
}
|
|
1020
|
-
// EOF is impossible here (caller guarded with the outer
|
|
1021
|
-
// loop's `pos < input.length` check). Anything else: delim.
|
|
1088
|
+
// HC_DELIM. EOF is impossible here (caller guarded with the outer
|
|
1089
|
+
// loop's `pos < input.length` check). Anything else: a <delim-token>.
|
|
1022
1090
|
return fill(out, TT_DELIM, pos - 1, pos);
|
|
1023
1091
|
}
|
|
1024
1092
|
}
|
|
@@ -1043,18 +1111,16 @@ function readToken(input, pos, out) {
|
|
|
1043
1111
|
// Comment: `/*…*/` is yielded as a token (filtered by `next`).
|
|
1044
1112
|
if (cc === CC_SOLIDUS && input.charCodeAt(pos + 1) === CC_ASTERISK) {
|
|
1045
1113
|
const start = pos;
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
pos++;
|
|
1057
|
-
}
|
|
1114
|
+
// Jump to the closing `*/` in one native scan instead of a per-character
|
|
1115
|
+
// loop — comment bodies (license banners, source comments) can be long.
|
|
1116
|
+
// No close: unterminated comment runs to EOF so ranges cover all input.
|
|
1117
|
+
const close = input.indexOf("*/", pos + 2);
|
|
1118
|
+
return fill(
|
|
1119
|
+
out,
|
|
1120
|
+
TT_COMMENT,
|
|
1121
|
+
start,
|
|
1122
|
+
close === -1 ? input.length : close + 2
|
|
1123
|
+
);
|
|
1058
1124
|
}
|
|
1059
1125
|
// `consumeAToken` dispatches on the lead code point at `pos` (it expects the
|
|
1060
1126
|
// position just past the lead and the already-read lead code point).
|
|
@@ -1240,26 +1306,28 @@ class Token extends Node {
|
|
|
1240
1306
|
* @param {number} end byte offset just past the token's last code point
|
|
1241
1307
|
* @param {LocConverter} locConverter shared loc converter
|
|
1242
1308
|
*/
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
/** @type {string | undefined} */
|
|
1250
|
-
this._value = undefined;
|
|
1251
|
-
}
|
|
1309
|
+
// No own fields: a leaf token is exactly a `Node` plus the value getters
|
|
1310
|
+
// below. `value` is derived from the byte range on read instead of cached in
|
|
1311
|
+
// a `_value` slot — most tokens (whitespace, punctuation) never read it, and
|
|
1312
|
+
// dropping the slot is ~8 bytes saved on every token (the bulk of all nodes).
|
|
1313
|
+
// hash / at-keyword strip their `#` / `@` prefix; url uses its content range
|
|
1314
|
+
// (`contentStart` / `contentEnd`, the token's only own fields).
|
|
1252
1315
|
|
|
1253
1316
|
/**
|
|
1254
1317
|
* @returns {string} the token's value (raw source slice unless overridden)
|
|
1255
1318
|
*/
|
|
1256
1319
|
get value() {
|
|
1257
|
-
const
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
this.end
|
|
1262
|
-
|
|
1320
|
+
const input = this._locConverter._input;
|
|
1321
|
+
const type = this.type;
|
|
1322
|
+
// hash (`#name` → `name`) and at-keyword (`@name` → `name`) drop one char.
|
|
1323
|
+
if (type === T_HASH || type === T_AT_KEYWORD) {
|
|
1324
|
+
return input.slice(this.start + 1, this.end);
|
|
1325
|
+
}
|
|
1326
|
+
if (type === T_URL) {
|
|
1327
|
+
const u = /** @type {UrlToken} */ (/** @type {unknown} */ (this));
|
|
1328
|
+
return input.slice(u.contentStart, u.contentEnd);
|
|
1329
|
+
}
|
|
1330
|
+
return input.slice(this.start, this.end);
|
|
1263
1331
|
}
|
|
1264
1332
|
|
|
1265
1333
|
/**
|
|
@@ -1297,19 +1365,28 @@ class Token extends Node {
|
|
|
1297
1365
|
|
|
1298
1366
|
/**
|
|
1299
1367
|
* Spec type flag. For number / dimension tokens it's "integer" / "number"
|
|
1300
|
-
* (derived from `value`); for hash tokens it's "id" / "unrestricted" (
|
|
1301
|
-
*
|
|
1302
|
-
*
|
|
1368
|
+
* (derived from `value`); for hash tokens it's "id" / "unrestricted" (re-derived
|
|
1369
|
+
* from the source). The two senses share the name in the spec; both are computed
|
|
1370
|
+
* on read so every leaf token keeps the same object shape (no own `typeFlag`).
|
|
1303
1371
|
* @returns {"integer" | "number" | "id" | "unrestricted"} the spec type flag
|
|
1304
1372
|
*/
|
|
1305
1373
|
get typeFlag() {
|
|
1306
1374
|
if (this.type === T_HASH) {
|
|
1307
|
-
//
|
|
1308
|
-
//
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1375
|
+
// Re-derive id-ness from the source (whether the name after `#` starts an
|
|
1376
|
+
// ident sequence) rather than storing an `_isId` slot — keeps hash tokens
|
|
1377
|
+
// the same shape as every other leaf token. Matches the lexer's
|
|
1378
|
+
// `consumeNumberSign`, which sets `isId` from the same check.
|
|
1379
|
+
const input = this._locConverter._input;
|
|
1380
|
+
const p = this.start + 1;
|
|
1381
|
+
return _ifThreeCodePointsWouldStartAnIdentSequence(
|
|
1382
|
+
input,
|
|
1383
|
+
p,
|
|
1384
|
+
input.charCodeAt(p),
|
|
1385
|
+
input.charCodeAt(p + 1),
|
|
1386
|
+
input.charCodeAt(p + 2)
|
|
1387
|
+
)
|
|
1388
|
+
? "id"
|
|
1389
|
+
: "unrestricted";
|
|
1313
1390
|
}
|
|
1314
1391
|
const v = this.value;
|
|
1315
1392
|
return _typeFlagOf(
|
|
@@ -1333,6 +1410,54 @@ class Token extends Node {
|
|
|
1333
1410
|
}
|
|
1334
1411
|
}
|
|
1335
1412
|
|
|
1413
|
+
/**
|
|
1414
|
+
* The non-leaf `Node` subclass: functions, simple blocks, declarations, at-rules
|
|
1415
|
+
* and qualified rules. It declares the union of every container field up front so
|
|
1416
|
+
* all five share **one** hidden class — the consume algorithms only overwrite the
|
|
1417
|
+
* slots relevant to their type, never adding a property, so the shape never
|
|
1418
|
+
* transitions. This caps the shape count: the walker's hot `.type` / `.value` /
|
|
1419
|
+
* `.prelude` loads otherwise see eight distinct node maps (five container types
|
|
1420
|
+
* plus the token / hash / url token maps), tipping V8's inline cache into the
|
|
1421
|
+
* slow megamorphic path; folding the five containers into one leaves four maps
|
|
1422
|
+
* (token, hash, url, container) — within the polymorphic limit, so those loads
|
|
1423
|
+
* stay inline-cached. Unused-for-the-type slots keep their defaults (the field
|
|
1424
|
+
* typedefs below document which fields each type uses). The stylesheet node is
|
|
1425
|
+
* rare (one per parse) and stays a bare `Node`.
|
|
1426
|
+
*/
|
|
1427
|
+
class Container extends Node {
|
|
1428
|
+
/**
|
|
1429
|
+
* @param {number} type node type
|
|
1430
|
+
* @param {number} start byte offset of the node's first code point
|
|
1431
|
+
* @param {number} end byte offset just past the node's last code point
|
|
1432
|
+
* @param {LocConverter} locConverter shared loc converter
|
|
1433
|
+
*/
|
|
1434
|
+
constructor(type, start, end, locConverter) {
|
|
1435
|
+
super(type, start, end, locConverter);
|
|
1436
|
+
/** @type {string} name (function / at-rule / declaration) */
|
|
1437
|
+
this.name = "";
|
|
1438
|
+
/** @type {number} */
|
|
1439
|
+
this.nameStart = start;
|
|
1440
|
+
/** @type {number} */
|
|
1441
|
+
this.nameEnd = start;
|
|
1442
|
+
/** @type {ComponentValue[] | null} component values (function / block / declaration) */
|
|
1443
|
+
this.value = null;
|
|
1444
|
+
/** @type {ComponentValue[] | null} prelude (at-rule / qualified rule) */
|
|
1445
|
+
this.prelude = null;
|
|
1446
|
+
/** @type {Declaration[] | null} */
|
|
1447
|
+
this.declarations = null;
|
|
1448
|
+
/** @type {Rule[] | null} */
|
|
1449
|
+
this.childRules = null;
|
|
1450
|
+
/** @type {number} `{` start offset, or -1 (at-rule / qualified rule) */
|
|
1451
|
+
this.blockStart = -1;
|
|
1452
|
+
/** @type {number} `}` end offset, or -1 (at-rule / qualified rule) */
|
|
1453
|
+
this.blockEnd = -1;
|
|
1454
|
+
/** @type {boolean} stripped `!important` (declaration) */
|
|
1455
|
+
this.important = false;
|
|
1456
|
+
/** @type {SimpleBlockToken | undefined} opening char (simple block) */
|
|
1457
|
+
this.token = undefined;
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1336
1461
|
/**
|
|
1337
1462
|
* Number token (`123`, `-1.5`, `+2e3`). `value` is the raw source slice (the spec's "value"); `numericValue` / `typeFlag` / `sign` are lazy getters derived from it (see `Token`).
|
|
1338
1463
|
* @typedef {Token & { numericValue: number, typeFlag: "integer" | "number", sign: "+" | "-" | "" }} NumberToken
|
|
@@ -1430,82 +1555,320 @@ class Token extends Node {
|
|
|
1430
1555
|
* @typedef {Node & { rules: Rule[] }} Stylesheet
|
|
1431
1556
|
*/
|
|
1432
1557
|
|
|
1558
|
+
// Lexer-token-type → AST-node-type map. A single \`new Token\` construct site
|
|
1559
|
+
// (vs a ~20-case switch with a \`new Token\` in each arm) keeps V8 on the fast
|
|
1560
|
+
// monomorphic allocation path — the switch form showed up as generic construct
|
|
1561
|
+
// stubs in profiles. URL is the one type with extra own state, handled first.
|
|
1562
|
+
const _ttToNodeType = new Uint8Array(27);
|
|
1563
|
+
_ttToNodeType[TT_WHITESPACE] = T_WHITESPACE;
|
|
1564
|
+
_ttToNodeType[TT_IDENTIFIER] = T_IDENT;
|
|
1565
|
+
_ttToNodeType[TT_STRING] = T_STRING;
|
|
1566
|
+
_ttToNodeType[TT_DELIM] = T_DELIM;
|
|
1567
|
+
_ttToNodeType[TT_NUMBER] = T_NUMBER;
|
|
1568
|
+
_ttToNodeType[TT_PERCENTAGE] = T_PERCENTAGE;
|
|
1569
|
+
_ttToNodeType[TT_DIMENSION] = T_DIMENSION;
|
|
1570
|
+
_ttToNodeType[TT_HASH] = T_HASH;
|
|
1571
|
+
_ttToNodeType[TT_AT_KEYWORD] = T_AT_KEYWORD;
|
|
1572
|
+
_ttToNodeType[TT_BAD_STRING_TOKEN] = T_BAD_STRING;
|
|
1573
|
+
_ttToNodeType[TT_BAD_URL_TOKEN] = T_BAD_URL;
|
|
1574
|
+
_ttToNodeType[TT_COLON] = T_COLON;
|
|
1575
|
+
_ttToNodeType[TT_COMMA] = T_COMMA;
|
|
1576
|
+
_ttToNodeType[TT_SEMICOLON] = T_SEMICOLON;
|
|
1577
|
+
_ttToNodeType[TT_RIGHT_PARENTHESIS] = T_RIGHT_PARENTHESIS;
|
|
1578
|
+
_ttToNodeType[TT_RIGHT_SQUARE_BRACKET] = T_RIGHT_SQUARE_BRACKET;
|
|
1579
|
+
_ttToNodeType[TT_RIGHT_CURLY_BRACKET] = T_RIGHT_CURLY_BRACKET;
|
|
1580
|
+
_ttToNodeType[TT_CDO] = T_CDO;
|
|
1581
|
+
_ttToNodeType[TT_CDC] = T_CDC;
|
|
1582
|
+
|
|
1583
|
+
// === AST construction backend ===
|
|
1584
|
+
// The consume algorithms build nodes through these module-level primitives
|
|
1585
|
+
// rather than `new Token` / `new Container` directly, so the node
|
|
1586
|
+
// representation can be swapped under the parser. The object backend below
|
|
1587
|
+
// builds the retainable `Node` / `Token` / `Container` tree the `parseA*`
|
|
1588
|
+
// entry points return; the Struct-of-Arrays backend (added separately) writes
|
|
1589
|
+
// the same nodes into reused typed arrays for the streaming `grammar`, where
|
|
1590
|
+
// per-node allocation dominates cost. Child lists are plain arrays in both
|
|
1591
|
+
// backends (a node ref is an object or an integer index); only node creation /
|
|
1592
|
+
// field access differs, so only those ops are swapped.
|
|
1593
|
+
|
|
1594
|
+
// Current loc converter for the active parse (object backend reads it).
|
|
1595
|
+
let _lc = /** @type {LocConverter} */ (/** @type {unknown} */ (null));
|
|
1596
|
+
|
|
1597
|
+
/** @type {(type: number, start: number, end: number) => Node} */
|
|
1598
|
+
let _mkLeaf;
|
|
1599
|
+
/** @type {(start: number, end: number, contentStart: number, contentEnd: number) => Node} */
|
|
1600
|
+
let _mkUrl;
|
|
1601
|
+
/** @type {(type: number, start: number, end: number) => Node} */
|
|
1602
|
+
let _mkContainer;
|
|
1603
|
+
/** @type {(start: number) => Node} */
|
|
1604
|
+
let _mkStylesheet;
|
|
1605
|
+
/** @type {(r: Node, v: string, nameStart: number, nameEnd: number) => void} */
|
|
1606
|
+
let _setName;
|
|
1607
|
+
/** @type {(r: Node, v: number) => void} */
|
|
1608
|
+
let _setEnd;
|
|
1609
|
+
/** @type {(r: Node, blockStart: number, blockEnd: number) => void} */
|
|
1610
|
+
let _setBlock;
|
|
1611
|
+
/** @type {(r: Node) => void} */
|
|
1612
|
+
let _setImportant;
|
|
1613
|
+
/** @type {(r: Node, ch: SimpleBlockToken) => void} */
|
|
1614
|
+
let _setToken;
|
|
1615
|
+
/** @type {(r: Node, list: Node[]) => void} */
|
|
1616
|
+
let _setValue;
|
|
1617
|
+
/** @type {(r: Node, list: Node[]) => void} */
|
|
1618
|
+
let _setPrelude;
|
|
1619
|
+
/** @type {(r: Node, decls: Node[], childRules: Node[]) => void} */
|
|
1620
|
+
let _setBody;
|
|
1621
|
+
/** @type {(r: Node, list: Node[]) => void} */
|
|
1622
|
+
let _setRules;
|
|
1623
|
+
/** @type {(r: Node) => number} */
|
|
1624
|
+
let _nType;
|
|
1625
|
+
/** @type {(r: Node) => number} */
|
|
1626
|
+
let _nStart;
|
|
1627
|
+
/** @type {(r: Node) => string} */
|
|
1628
|
+
let _nValue;
|
|
1629
|
+
/** @type {(r: Node) => SimpleBlockToken} */
|
|
1630
|
+
let _nToken;
|
|
1631
|
+
|
|
1632
|
+
// Child lists are plain arrays in every backend; refs are pushed by value.
|
|
1633
|
+
const _list = () => /** @type {Node[]} */ ([]);
|
|
1634
|
+
|
|
1635
|
+
// -- object backend: builds the retainable class-instance tree --
|
|
1636
|
+
/** @type {typeof _mkLeaf} */
|
|
1637
|
+
const _objLeaf = (type, start, end) => new Token(type, start, end, _lc);
|
|
1638
|
+
/** @type {typeof _mkUrl} */
|
|
1639
|
+
const _objUrl = (start, end, cs, ce) => {
|
|
1640
|
+
const u = /** @type {UrlToken} */ (new Token(T_URL, start, end, _lc));
|
|
1641
|
+
u.contentStart = cs;
|
|
1642
|
+
u.contentEnd = ce;
|
|
1643
|
+
return u;
|
|
1644
|
+
};
|
|
1645
|
+
/** @type {typeof _mkContainer} */
|
|
1646
|
+
const _objContainer = (type, start, end) =>
|
|
1647
|
+
new Container(type, start, end, _lc);
|
|
1648
|
+
/** @type {typeof _mkStylesheet} */
|
|
1649
|
+
const _objStylesheet = (start) => {
|
|
1650
|
+
const s = /** @type {Stylesheet} */ (
|
|
1651
|
+
new Node(T_STYLESHEET, start, start, _lc)
|
|
1652
|
+
);
|
|
1653
|
+
s.rules = [];
|
|
1654
|
+
return s;
|
|
1655
|
+
};
|
|
1656
|
+
/** @param {LocConverter} lc loc converter for this parse */
|
|
1657
|
+
const useObjectBackend = (lc) => {
|
|
1658
|
+
_lc = lc;
|
|
1659
|
+
_mkLeaf = _objLeaf;
|
|
1660
|
+
_mkUrl = _objUrl;
|
|
1661
|
+
_mkContainer = _objContainer;
|
|
1662
|
+
_mkStylesheet = _objStylesheet;
|
|
1663
|
+
_setName = (r, v, ns, ne) => {
|
|
1664
|
+
const c = /** @type {Container} */ (r);
|
|
1665
|
+
c.name = v;
|
|
1666
|
+
c.nameStart = ns;
|
|
1667
|
+
c.nameEnd = ne;
|
|
1668
|
+
};
|
|
1669
|
+
_setEnd = (r, v) => {
|
|
1670
|
+
r.end = v;
|
|
1671
|
+
};
|
|
1672
|
+
_setBlock = (r, bs, be) => {
|
|
1673
|
+
const c = /** @type {Container} */ (r);
|
|
1674
|
+
c.blockStart = bs;
|
|
1675
|
+
c.blockEnd = be;
|
|
1676
|
+
};
|
|
1677
|
+
_setImportant = (r) => {
|
|
1678
|
+
/** @type {Container} */ (r).important = true;
|
|
1679
|
+
};
|
|
1680
|
+
_setToken = (r, ch) => {
|
|
1681
|
+
/** @type {Container} */ (r).token = ch;
|
|
1682
|
+
};
|
|
1683
|
+
_setValue = (r, list) => {
|
|
1684
|
+
/** @type {Container} */ (r).value = /** @type {ComponentValue[]} */ (list);
|
|
1685
|
+
};
|
|
1686
|
+
_setPrelude = (r, list) => {
|
|
1687
|
+
/** @type {Container} */ (r).prelude = /** @type {ComponentValue[]} */ (
|
|
1688
|
+
list
|
|
1689
|
+
);
|
|
1690
|
+
};
|
|
1691
|
+
_setBody = (r, decls, childRules) => {
|
|
1692
|
+
const c = /** @type {Container} */ (r);
|
|
1693
|
+
c.declarations = /** @type {Declaration[]} */ (decls);
|
|
1694
|
+
c.childRules = /** @type {Rule[]} */ (childRules);
|
|
1695
|
+
};
|
|
1696
|
+
_setRules = (r, list) => {
|
|
1697
|
+
/** @type {Stylesheet} */ (r).rules = /** @type {Rule[]} */ (list);
|
|
1698
|
+
};
|
|
1699
|
+
_nType = (r) => r.type;
|
|
1700
|
+
_nStart = (r) => r.start;
|
|
1701
|
+
_nValue = (r) => /** @type {Token} */ (r).value;
|
|
1702
|
+
_nToken = (r) =>
|
|
1703
|
+
/** @type {SimpleBlockToken} */ (/** @type {Container} */ (r).token);
|
|
1704
|
+
};
|
|
1705
|
+
|
|
1706
|
+
// -- struct-of-arrays backend: writes nodes into reused typed arrays --
|
|
1707
|
+
// A node ref is its integer id; fields live in parallel arrays indexed by id.
|
|
1708
|
+
// Three reused int slots (`_soaA0/1/2`) plus a flags byte carry the per-type
|
|
1709
|
+
// extras; child lists hang off three object arrays. Slot meaning by type:
|
|
1710
|
+
// url: a0 contentStart, a1 contentEnd
|
|
1711
|
+
// function: a0 nameEnd
|
|
1712
|
+
// declaration: a0 nameEnd, flags bit0 important
|
|
1713
|
+
// at-rule: a0 nameEnd, a1 blockStart, a2 blockEnd
|
|
1714
|
+
// qualified: a1 blockStart, a2 blockEnd
|
|
1715
|
+
// `name` / `nameStart` / a simple block's `token` are derived from the source
|
|
1716
|
+
// on read (see the SoA accessors), so they need no slot. Lists: l0 =
|
|
1717
|
+
// value | prelude | stylesheet rules, l1 = declarations, l2 = childRules.
|
|
1718
|
+
// `grammar` resets `_soaN` to 0 after each top-level rule's walk, so the
|
|
1719
|
+
// buffers are reused across rules and the parse allocates almost nothing.
|
|
1720
|
+
let _soaCap = 0;
|
|
1721
|
+
let _soaN = 0;
|
|
1722
|
+
let _soaTy = new Uint8Array(0);
|
|
1723
|
+
let _soaSt = new Int32Array(0);
|
|
1724
|
+
let _soaEn = new Int32Array(0);
|
|
1725
|
+
let _soaA0 = new Int32Array(0);
|
|
1726
|
+
let _soaA1 = new Int32Array(0);
|
|
1727
|
+
let _soaA2 = new Int32Array(0);
|
|
1728
|
+
let _soaFl = new Uint8Array(0);
|
|
1729
|
+
/** @type {(Node[] | null)[]} */
|
|
1730
|
+
const _soaL0 = [];
|
|
1731
|
+
/** @type {(Node[] | null)[]} */
|
|
1732
|
+
const _soaL1 = [];
|
|
1733
|
+
/** @type {(Node[] | null)[]} */
|
|
1734
|
+
const _soaL2 = [];
|
|
1735
|
+
let _soaInput = "";
|
|
1736
|
+
let _soaLC = /** @type {LocConverter} */ (/** @type {unknown} */ (null));
|
|
1737
|
+
|
|
1738
|
+
// Node refs are integers here but typed `Node` across the parser; these are
|
|
1739
|
+
// identity casts that just satisfy the type system at the boundary.
|
|
1740
|
+
/** @type {(n: Node) => number} */
|
|
1741
|
+
const _ix = (n) => /** @type {number} */ (/** @type {unknown} */ (n));
|
|
1742
|
+
/** @type {(i: number) => Node} */
|
|
1743
|
+
const _ref = (i) => /** @type {Node} */ (/** @type {unknown} */ (i));
|
|
1744
|
+
|
|
1745
|
+
/** @param {number} need minimum capacity */
|
|
1746
|
+
const _soaGrow = (need) => {
|
|
1747
|
+
let cap = _soaCap || 4096;
|
|
1748
|
+
while (cap < need) cap *= 2;
|
|
1749
|
+
const ty = new Uint8Array(cap);
|
|
1750
|
+
ty.set(_soaTy);
|
|
1751
|
+
_soaTy = ty;
|
|
1752
|
+
const st = new Int32Array(cap);
|
|
1753
|
+
st.set(_soaSt);
|
|
1754
|
+
_soaSt = st;
|
|
1755
|
+
const en = new Int32Array(cap);
|
|
1756
|
+
en.set(_soaEn);
|
|
1757
|
+
_soaEn = en;
|
|
1758
|
+
const a0 = new Int32Array(cap);
|
|
1759
|
+
a0.set(_soaA0);
|
|
1760
|
+
_soaA0 = a0;
|
|
1761
|
+
const a1 = new Int32Array(cap);
|
|
1762
|
+
a1.set(_soaA1);
|
|
1763
|
+
_soaA1 = a1;
|
|
1764
|
+
const a2 = new Int32Array(cap);
|
|
1765
|
+
a2.set(_soaA2);
|
|
1766
|
+
_soaA2 = a2;
|
|
1767
|
+
const fl = new Uint8Array(cap);
|
|
1768
|
+
fl.set(_soaFl);
|
|
1769
|
+
_soaFl = fl;
|
|
1770
|
+
_soaCap = cap;
|
|
1771
|
+
};
|
|
1772
|
+
/** @type {(type: number, start: number, end: number) => Node} */
|
|
1773
|
+
const _soaAlloc = (type, start, end) => {
|
|
1774
|
+
// Ids are 1-based: a node ref is used in truthiness checks (`if (!parent)`),
|
|
1775
|
+
// so 0 must stay reserved for "no node".
|
|
1776
|
+
const i = _soaN + 1;
|
|
1777
|
+
if (i >= _soaCap) _soaGrow(i + 1);
|
|
1778
|
+
_soaTy[i] = type;
|
|
1779
|
+
_soaSt[i] = start;
|
|
1780
|
+
_soaEn[i] = end;
|
|
1781
|
+
_soaFl[i] = 0;
|
|
1782
|
+
// Clear list slots so a reused id never exposes a previous node's children.
|
|
1783
|
+
_soaL0[i] = null;
|
|
1784
|
+
_soaL1[i] = null;
|
|
1785
|
+
_soaL2[i] = null;
|
|
1786
|
+
_soaN = i;
|
|
1787
|
+
return _ref(i);
|
|
1788
|
+
};
|
|
1789
|
+
// Raw token value (the lazy `Token.value` form): hash / at-keyword drop their
|
|
1790
|
+
// one-char prefix, url uses its content range. Shared by the parser's
|
|
1791
|
+
// mid-parse reads and the SoA accessor.
|
|
1792
|
+
/**
|
|
1793
|
+
* @param {number} i node id
|
|
1794
|
+
* @returns {string} raw token value
|
|
1795
|
+
*/
|
|
1796
|
+
const _soaValueOf = (i) => {
|
|
1797
|
+
const ty = _soaTy[i];
|
|
1798
|
+
if (ty === T_HASH || ty === T_AT_KEYWORD) {
|
|
1799
|
+
return _soaInput.slice(_soaSt[i] + 1, _soaEn[i]);
|
|
1800
|
+
}
|
|
1801
|
+
if (ty === T_URL) return _soaInput.slice(_soaA0[i], _soaA1[i]);
|
|
1802
|
+
return _soaInput.slice(_soaSt[i], _soaEn[i]);
|
|
1803
|
+
};
|
|
1804
|
+
/**
|
|
1805
|
+
* @param {string} input source
|
|
1806
|
+
* @param {LocConverter} lc loc converter
|
|
1807
|
+
*/
|
|
1808
|
+
const useSoaBackend = (input, lc) => {
|
|
1809
|
+
_soaInput = input;
|
|
1810
|
+
_soaLC = lc;
|
|
1811
|
+
_soaN = 0;
|
|
1812
|
+
_mkLeaf = (type, start, end) => _soaAlloc(type, start, end);
|
|
1813
|
+
_mkUrl = (start, end, cs, ce) => {
|
|
1814
|
+
const r = _soaAlloc(T_URL, start, end);
|
|
1815
|
+
_soaA0[_ix(r)] = cs;
|
|
1816
|
+
_soaA1[_ix(r)] = ce;
|
|
1817
|
+
return r;
|
|
1818
|
+
};
|
|
1819
|
+
_mkContainer = (type, start, end) => _soaAlloc(type, start, end);
|
|
1820
|
+
_mkStylesheet = (start) => _soaAlloc(T_STYLESHEET, start, start);
|
|
1821
|
+
// name / nameStart are derived from start + nameEnd; only nameEnd is stored.
|
|
1822
|
+
_setName = (r, v, ns, ne) => {
|
|
1823
|
+
_soaA0[_ix(r)] = ne;
|
|
1824
|
+
};
|
|
1825
|
+
_setEnd = (r, v) => {
|
|
1826
|
+
_soaEn[_ix(r)] = v;
|
|
1827
|
+
};
|
|
1828
|
+
_setBlock = (r, bs, be) => {
|
|
1829
|
+
const i = _ix(r);
|
|
1830
|
+
_soaA1[i] = bs;
|
|
1831
|
+
_soaA2[i] = be;
|
|
1832
|
+
};
|
|
1833
|
+
_setImportant = (r) => {
|
|
1834
|
+
_soaFl[_ix(r)] |= 1;
|
|
1835
|
+
};
|
|
1836
|
+
// A simple block's token is derived from its opening char on read.
|
|
1837
|
+
_setToken = (r, ch) => {};
|
|
1838
|
+
_setValue = (r, list) => {
|
|
1839
|
+
_soaL0[_ix(r)] = list;
|
|
1840
|
+
};
|
|
1841
|
+
_setPrelude = (r, list) => {
|
|
1842
|
+
_soaL0[_ix(r)] = list;
|
|
1843
|
+
};
|
|
1844
|
+
_setBody = (r, decls, childRules) => {
|
|
1845
|
+
const i = _ix(r);
|
|
1846
|
+
_soaL1[i] = decls;
|
|
1847
|
+
_soaL2[i] = childRules;
|
|
1848
|
+
};
|
|
1849
|
+
_setRules = (r, list) => {
|
|
1850
|
+
_soaL0[_ix(r)] = list;
|
|
1851
|
+
};
|
|
1852
|
+
_nType = (r) => _soaTy[_ix(r)];
|
|
1853
|
+
_nStart = (r) => _soaSt[_ix(r)];
|
|
1854
|
+
_nValue = (r) => _soaValueOf(_ix(r));
|
|
1855
|
+
_nToken = (r) => /** @type {SimpleBlockToken} */ (_soaInput[_soaSt[_ix(r)]]);
|
|
1856
|
+
};
|
|
1857
|
+
|
|
1433
1858
|
/**
|
|
1434
1859
|
* Materialize a single non-block, non-function lexer token as its leaf AST node — the spec's "consume a token" result (§5.4.8 "anything else"), preserving stray closers / CDO / CDC.
|
|
1435
1860
|
* @param {MutableToken} t token from the lexer
|
|
1436
|
-
* @
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
return new Token(T_IDENT, t.start, t.end, locConverter);
|
|
1446
|
-
case TT_STRING:
|
|
1447
|
-
return new Token(T_STRING, t.start, t.end, locConverter);
|
|
1448
|
-
case TT_DELIM:
|
|
1449
|
-
return new Token(T_DELIM, t.start, t.end, locConverter);
|
|
1450
|
-
// Numeric tokens: construct only — `numericValue` / `typeFlag` / `sign` /
|
|
1451
|
-
// `unit` are lazy `Token` getters, so the `Number()` parse + slices +
|
|
1452
|
-
// `toLowerCase` are skipped for the (common) tokens never read numerically.
|
|
1453
|
-
case TT_NUMBER:
|
|
1454
|
-
return new Token(T_NUMBER, t.start, t.end, locConverter);
|
|
1455
|
-
case TT_PERCENTAGE:
|
|
1456
|
-
return new Token(T_PERCENTAGE, t.start, t.end, locConverter);
|
|
1457
|
-
case TT_DIMENSION:
|
|
1458
|
-
return new Token(T_DIMENSION, t.start, t.end, locConverter);
|
|
1459
|
-
case TT_HASH: {
|
|
1460
|
-
const hash = new Token(T_HASH, t.start, t.end, locConverter);
|
|
1461
|
-
hash._value = input.slice(t.start + 1, t.end);
|
|
1462
|
-
// Store the raw id-ness; the `typeFlag` getter maps it to "id" /
|
|
1463
|
-
// "unrestricted". Kept off `Token`'s declared fields so non-hash
|
|
1464
|
-
// tokens don't carry the slot.
|
|
1465
|
-
/** @type {Token & { _isId: boolean }} */ (hash)._isId = t.isId;
|
|
1466
|
-
return hash;
|
|
1467
|
-
}
|
|
1468
|
-
case TT_AT_KEYWORD: {
|
|
1469
|
-
const at = new Token(T_AT_KEYWORD, t.start, t.end, locConverter);
|
|
1470
|
-
at._value = input.slice(t.start + 1, t.end);
|
|
1471
|
-
return at;
|
|
1472
|
-
}
|
|
1473
|
-
case TT_URL: {
|
|
1474
|
-
const ut = /** @type {CssUrlToken} */ (t);
|
|
1475
|
-
const url = /** @type {UrlToken} */ (
|
|
1476
|
-
new Token(T_URL, t.start, t.end, locConverter)
|
|
1477
|
-
);
|
|
1478
|
-
url._value = input.slice(ut.contentStart, ut.contentEnd);
|
|
1479
|
-
url.contentStart = ut.contentStart;
|
|
1480
|
-
url.contentEnd = ut.contentEnd;
|
|
1481
|
-
return url;
|
|
1482
|
-
}
|
|
1483
|
-
case TT_BAD_STRING_TOKEN:
|
|
1484
|
-
return new Token(T_BAD_STRING, t.start, t.end, locConverter);
|
|
1485
|
-
case TT_BAD_URL_TOKEN:
|
|
1486
|
-
return new Token(T_BAD_URL, t.start, t.end, locConverter);
|
|
1487
|
-
case TT_COLON:
|
|
1488
|
-
return new Token(T_COLON, t.start, t.end, locConverter);
|
|
1489
|
-
case TT_COMMA:
|
|
1490
|
-
return new Token(T_COMMA, t.start, t.end, locConverter);
|
|
1491
|
-
case TT_SEMICOLON:
|
|
1492
|
-
return new Token(T_SEMICOLON, t.start, t.end, locConverter);
|
|
1493
|
-
// Stray closers / CDO / CDC reach here only on malformed input; the spec
|
|
1494
|
-
// preserves them as component values ("consume a token and return it").
|
|
1495
|
-
case TT_RIGHT_PARENTHESIS:
|
|
1496
|
-
return new Token(T_RIGHT_PARENTHESIS, t.start, t.end, locConverter);
|
|
1497
|
-
case TT_RIGHT_SQUARE_BRACKET:
|
|
1498
|
-
return new Token(T_RIGHT_SQUARE_BRACKET, t.start, t.end, locConverter);
|
|
1499
|
-
case TT_RIGHT_CURLY_BRACKET:
|
|
1500
|
-
return new Token(T_RIGHT_CURLY_BRACKET, t.start, t.end, locConverter);
|
|
1501
|
-
case TT_CDO:
|
|
1502
|
-
return new Token(T_CDO, t.start, t.end, locConverter);
|
|
1503
|
-
case TT_CDC:
|
|
1504
|
-
return new Token(T_CDC, t.start, t.end, locConverter);
|
|
1505
|
-
/* istanbul ignore next -- @preserve: unreachable; blocks/functions are routed earlier, comments filtered, EOF guarded by callers */
|
|
1506
|
-
default:
|
|
1507
|
-
throw new Error(`Unexpected token type "${t.type}"`);
|
|
1861
|
+
* @returns {Node} the leaf token node
|
|
1862
|
+
*/
|
|
1863
|
+
const tokenToNode = (t) => {
|
|
1864
|
+
const tt = t.type;
|
|
1865
|
+
// URL is the only leaf with own state (its content range); all others are a
|
|
1866
|
+
// plain leaf whose node type comes from the map.
|
|
1867
|
+
if (tt === TT_URL) {
|
|
1868
|
+
const ut = /** @type {CssUrlToken} */ (t);
|
|
1869
|
+
return _mkUrl(t.start, t.end, ut.contentStart, ut.contentEnd);
|
|
1508
1870
|
}
|
|
1871
|
+
return _mkLeaf(_ttToNodeType[tt], t.start, t.end);
|
|
1509
1872
|
};
|
|
1510
1873
|
|
|
1511
1874
|
/**
|
|
@@ -1697,15 +2060,13 @@ const parseAStylesheet = (input, comment) => {
|
|
|
1697
2060
|
// 1. If input is a byte stream for a stylesheet, decode bytes from input, and set input to the result.
|
|
1698
2061
|
// 2. Normalize input, and set input to the result.
|
|
1699
2062
|
const ts = normalizeIntoTokenStream(input, 0, comment);
|
|
2063
|
+
useObjectBackend(ts.locConverter);
|
|
1700
2064
|
// 3. Create a new stylesheet, with its location set to location (or null, if location was not passed).
|
|
1701
2065
|
const start = ts.next().start;
|
|
1702
|
-
const stylesheet = /** @type {Stylesheet} */ (
|
|
1703
|
-
new Node(T_STYLESHEET, start, start, ts.locConverter)
|
|
1704
|
-
);
|
|
1705
|
-
stylesheet.rules = /** @type {Rule[]} */ ([]);
|
|
2066
|
+
const stylesheet = /** @type {Stylesheet} */ (_mkStylesheet(start));
|
|
1706
2067
|
// 4. Consume a stylesheet's contents from input, and set the stylesheet's rules to the result.
|
|
1707
|
-
stylesheet
|
|
1708
|
-
stylesheet
|
|
2068
|
+
_setRules(stylesheet, consumeAStylesheetsContents(ts));
|
|
2069
|
+
_setEnd(stylesheet, ts.next().start);
|
|
1709
2070
|
// 5. Return the stylesheet.
|
|
1710
2071
|
return stylesheet;
|
|
1711
2072
|
};
|
|
@@ -1723,6 +2084,7 @@ const parseAStylesheet = (input, comment) => {
|
|
|
1723
2084
|
const parseAStylesheetsContents = (input, comment) => {
|
|
1724
2085
|
// 1. Normalize input, and set input to the result.
|
|
1725
2086
|
const ts = normalizeIntoTokenStream(input, 0, comment);
|
|
2087
|
+
useObjectBackend(ts.locConverter);
|
|
1726
2088
|
// 2. Consume a stylesheet’s contents from input, and return the result.
|
|
1727
2089
|
return consumeAStylesheetsContents(ts);
|
|
1728
2090
|
};
|
|
@@ -1738,6 +2100,7 @@ const parseAStylesheetsContents = (input, comment) => {
|
|
|
1738
2100
|
const parseABlocksContents = (input, pos, comment) => {
|
|
1739
2101
|
// 1. Normalize input, and set input to the result.
|
|
1740
2102
|
const ts = normalizeIntoTokenStream(input, pos, comment);
|
|
2103
|
+
useObjectBackend(ts.locConverter);
|
|
1741
2104
|
// 2. Consume a block’s contents from input, and return the result.
|
|
1742
2105
|
return consumeABlocksContents(ts);
|
|
1743
2106
|
};
|
|
@@ -1755,6 +2118,7 @@ const parseABlocksContents = (input, pos, comment) => {
|
|
|
1755
2118
|
const parseARule = (input, pos, comment) => {
|
|
1756
2119
|
// 1. Normalize input, and set input to the result.
|
|
1757
2120
|
const ts = normalizeIntoTokenStream(input, pos, comment);
|
|
2121
|
+
useObjectBackend(ts.locConverter);
|
|
1758
2122
|
// 2. Discard whitespace from input.
|
|
1759
2123
|
while (ts.next().type === TT_WHITESPACE) ts.discard();
|
|
1760
2124
|
// 3. If the next token from input is an <EOF-token>, return a syntax error.
|
|
@@ -1785,6 +2149,7 @@ const parseARule = (input, pos, comment) => {
|
|
|
1785
2149
|
const parseADeclaration = (input, pos, comment) => {
|
|
1786
2150
|
// 1. Normalize input, and set input to the result.
|
|
1787
2151
|
const ts = normalizeIntoTokenStream(input, pos, comment);
|
|
2152
|
+
useObjectBackend(ts.locConverter);
|
|
1788
2153
|
// 2. Discard whitespace from input.
|
|
1789
2154
|
while (ts.next().type === TT_WHITESPACE) ts.discard();
|
|
1790
2155
|
// 3. Consume a declaration from input. If anything was returned, return it. Otherwise, return a syntax error.
|
|
@@ -1801,6 +2166,7 @@ const parseADeclaration = (input, pos, comment) => {
|
|
|
1801
2166
|
const parseAComponentValue = (input, pos, options = {}) => {
|
|
1802
2167
|
// 1. Normalize input, and set input to the result.
|
|
1803
2168
|
const ts = normalizeIntoTokenStream(input, pos, options.comment);
|
|
2169
|
+
useObjectBackend(ts.locConverter);
|
|
1804
2170
|
// 2. Discard whitespace from input.
|
|
1805
2171
|
while (ts.next().type === TT_WHITESPACE) ts.discard();
|
|
1806
2172
|
// 3. If input is empty, return a syntax error.
|
|
@@ -1825,6 +2191,7 @@ const parseAComponentValue = (input, pos, options = {}) => {
|
|
|
1825
2191
|
const parseAListOfComponentValues = (input, pos, options = {}) => {
|
|
1826
2192
|
// 1. Normalize input, and set input to the result.
|
|
1827
2193
|
const ts = normalizeIntoTokenStream(input, pos, options.comment);
|
|
2194
|
+
useObjectBackend(ts.locConverter);
|
|
1828
2195
|
// 2. Consume a list of component values from input, and return the result.
|
|
1829
2196
|
return consumeAListOfComponentValues(ts);
|
|
1830
2197
|
};
|
|
@@ -1843,6 +2210,7 @@ const parseACommaSeparatedListOfComponentValues = (
|
|
|
1843
2210
|
) => {
|
|
1844
2211
|
// 1. Normalize input, and set input to the result.
|
|
1845
2212
|
const ts = normalizeIntoTokenStream(input, pos, options.comment);
|
|
2213
|
+
useObjectBackend(ts.locConverter);
|
|
1846
2214
|
// 2. Let groups be an empty list.
|
|
1847
2215
|
/** @type {ComponentValue[][]} */
|
|
1848
2216
|
const groups = [];
|
|
@@ -1924,17 +2292,18 @@ const consumeAnAtRule = (ts, nested = false) => {
|
|
|
1924
2292
|
// Consume a token from input, and let rule be a new at-rule with its name set to the returned token’s value, its prelude initially set to an empty list, and no declarations or child rules.
|
|
1925
2293
|
const head = ts.consume();
|
|
1926
2294
|
const rule = /** @type {AtRule} */ (
|
|
1927
|
-
|
|
2295
|
+
_mkContainer(T_AT_RULE, head.start, head.end)
|
|
2296
|
+
);
|
|
2297
|
+
_setName(
|
|
2298
|
+
rule,
|
|
2299
|
+
ts.input.slice(head.start + 1, head.end),
|
|
2300
|
+
head.start,
|
|
2301
|
+
head.end
|
|
1928
2302
|
);
|
|
1929
|
-
|
|
1930
|
-
rule
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
rule.declarations = null;
|
|
1934
|
-
rule.childRules = null;
|
|
1935
|
-
// -1 = no block (the `;` / EOF / nested-`}` at-rule forms).
|
|
1936
|
-
rule.blockStart = -1;
|
|
1937
|
-
rule.blockEnd = -1;
|
|
2303
|
+
const prelude = _list();
|
|
2304
|
+
_setPrelude(rule, prelude);
|
|
2305
|
+
// declarations / childRules / blockStart (-1) / blockEnd (-1) keep their
|
|
2306
|
+
// defaults (no block: the `;` / EOF / nested-`}` at-rule forms).
|
|
1938
2307
|
|
|
1939
2308
|
// Process input
|
|
1940
2309
|
for (;;) {
|
|
@@ -1945,7 +2314,7 @@ const consumeAnAtRule = (ts, nested = false) => {
|
|
|
1945
2314
|
// Discard a token from input. If rule is valid in the current context, return it; otherwise return nothing.
|
|
1946
2315
|
if (t.type === TT_SEMICOLON || t.type === TT_EOF) {
|
|
1947
2316
|
ts.discard();
|
|
1948
|
-
rule
|
|
2317
|
+
_setEnd(rule, t.start);
|
|
1949
2318
|
return rule;
|
|
1950
2319
|
}
|
|
1951
2320
|
// <}-token>
|
|
@@ -1953,27 +2322,25 @@ const consumeAnAtRule = (ts, nested = false) => {
|
|
|
1953
2322
|
// Otherwise, consume a token and append the result to rule’s prelude.
|
|
1954
2323
|
else if (t.type === TT_RIGHT_CURLY_BRACKET) {
|
|
1955
2324
|
if (nested) {
|
|
1956
|
-
rule
|
|
2325
|
+
_setEnd(rule, t.start);
|
|
1957
2326
|
return rule;
|
|
1958
2327
|
}
|
|
1959
|
-
|
|
2328
|
+
prelude.push(consumeATokenAsNode(ts));
|
|
1960
2329
|
continue;
|
|
1961
2330
|
}
|
|
1962
2331
|
// <{-token>
|
|
1963
2332
|
// Consume a block from input, and assign the result to rule's declarations and child rules.
|
|
1964
2333
|
else if (t.type === TT_LEFT_CURLY_BRACKET) {
|
|
1965
2334
|
const block = consumeABlock(ts);
|
|
1966
|
-
rule.
|
|
1967
|
-
rule.
|
|
1968
|
-
rule
|
|
1969
|
-
rule.blockEnd = block.blockEnd;
|
|
1970
|
-
rule.end = block.blockEnd;
|
|
2335
|
+
_setBody(rule, block.decls, block.rules);
|
|
2336
|
+
_setBlock(rule, block.blockStart, block.blockEnd);
|
|
2337
|
+
_setEnd(rule, block.blockEnd);
|
|
1971
2338
|
return rule;
|
|
1972
2339
|
}
|
|
1973
2340
|
|
|
1974
2341
|
// anything else
|
|
1975
2342
|
// Consume a component value from input and append the returned value to rule’s prelude.
|
|
1976
|
-
|
|
2343
|
+
prelude.push(consumeAComponentValue(ts, t));
|
|
1977
2344
|
}
|
|
1978
2345
|
};
|
|
1979
2346
|
|
|
@@ -1988,7 +2355,7 @@ const consumeAnAtRule = (ts, nested = false) => {
|
|
|
1988
2355
|
*/
|
|
1989
2356
|
const consumeATokenAsNode = (ts) => {
|
|
1990
2357
|
const t = ts.consume();
|
|
1991
|
-
return tokenToNode(t
|
|
2358
|
+
return /** @type {Token} */ (tokenToNode(t));
|
|
1992
2359
|
};
|
|
1993
2360
|
|
|
1994
2361
|
/**
|
|
@@ -2002,14 +2369,12 @@ const consumeAQualifiedRule = (ts, stopToken, nested = false) => {
|
|
|
2002
2369
|
const start = ts.next().start;
|
|
2003
2370
|
// Let rule be a new qualified rule with its prelude, declarations, and child rules all initially set to empty lists.
|
|
2004
2371
|
const rule = /** @type {QualifiedRule} */ (
|
|
2005
|
-
|
|
2372
|
+
_mkContainer(T_QUALIFIED_RULE, start, start)
|
|
2006
2373
|
);
|
|
2007
|
-
|
|
2008
|
-
rule
|
|
2009
|
-
|
|
2010
|
-
//
|
|
2011
|
-
rule.blockStart = -1;
|
|
2012
|
-
rule.blockEnd = -1;
|
|
2374
|
+
const prelude = _list();
|
|
2375
|
+
_setPrelude(rule, prelude);
|
|
2376
|
+
// declarations / childRules / blockStart (-1) / blockEnd (-1) keep their
|
|
2377
|
+
// defaults (no block until a `{` is reached).
|
|
2013
2378
|
|
|
2014
2379
|
// Process input
|
|
2015
2380
|
for (;;) {
|
|
@@ -2024,7 +2389,7 @@ const consumeAQualifiedRule = (ts, stopToken, nested = false) => {
|
|
|
2024
2389
|
// This is a parse error. If nested is true, return nothing. Otherwise, consume a token and append the result to rule’s prelude.
|
|
2025
2390
|
else if (t.type === TT_RIGHT_CURLY_BRACKET) {
|
|
2026
2391
|
if (nested) return undefined;
|
|
2027
|
-
|
|
2392
|
+
prelude.push(consumeATokenAsNode(ts));
|
|
2028
2393
|
continue;
|
|
2029
2394
|
}
|
|
2030
2395
|
// <{-token>
|
|
@@ -2037,28 +2402,28 @@ const consumeAQualifiedRule = (ts, stopToken, nested = false) => {
|
|
|
2037
2402
|
let firstIdx = 0;
|
|
2038
2403
|
/* istanbul ignore next -- @preserve: leading whitespace is discarded before the rule, so the prelude never starts with it */
|
|
2039
2404
|
while (
|
|
2040
|
-
firstIdx <
|
|
2041
|
-
|
|
2405
|
+
firstIdx < prelude.length &&
|
|
2406
|
+
_nType(prelude[firstIdx]) === T_WHITESPACE
|
|
2042
2407
|
) {
|
|
2043
2408
|
firstIdx++;
|
|
2044
2409
|
}
|
|
2045
2410
|
let secondIdx = firstIdx + 1;
|
|
2046
2411
|
while (
|
|
2047
|
-
secondIdx <
|
|
2048
|
-
|
|
2412
|
+
secondIdx < prelude.length &&
|
|
2413
|
+
_nType(prelude[secondIdx]) === T_WHITESPACE
|
|
2049
2414
|
) {
|
|
2050
2415
|
secondIdx++;
|
|
2051
2416
|
}
|
|
2052
|
-
const first =
|
|
2053
|
-
const second =
|
|
2417
|
+
const first = prelude[firstIdx];
|
|
2418
|
+
const second = prelude[secondIdx];
|
|
2054
2419
|
if (
|
|
2055
2420
|
first &&
|
|
2056
|
-
first
|
|
2421
|
+
_nType(first) === T_IDENT &&
|
|
2057
2422
|
// Test the source bytes directly — avoids forcing the lazy `value`
|
|
2058
2423
|
// slice just to check the `--` custom-property prefix.
|
|
2059
|
-
ts.input.startsWith("--", first
|
|
2424
|
+
ts.input.startsWith("--", _nStart(first)) &&
|
|
2060
2425
|
second &&
|
|
2061
|
-
second
|
|
2426
|
+
_nType(second) === T_COLON
|
|
2062
2427
|
) {
|
|
2063
2428
|
/* istanbul ignore if -- @preserve: when nested, `declarationStartLikely` routes every `--x:` to consumeADeclaration (which accepts custom properties), so this fallthrough is unreachable */
|
|
2064
2429
|
if (nested) {
|
|
@@ -2069,17 +2434,15 @@ const consumeAQualifiedRule = (ts, stopToken, nested = false) => {
|
|
|
2069
2434
|
return undefined;
|
|
2070
2435
|
}
|
|
2071
2436
|
const block = consumeABlock(ts);
|
|
2072
|
-
rule.
|
|
2073
|
-
rule.
|
|
2074
|
-
rule
|
|
2075
|
-
rule.blockEnd = block.blockEnd;
|
|
2076
|
-
rule.end = block.blockEnd;
|
|
2437
|
+
_setBody(rule, block.decls, block.rules);
|
|
2438
|
+
_setBlock(rule, block.blockStart, block.blockEnd);
|
|
2439
|
+
_setEnd(rule, block.blockEnd);
|
|
2077
2440
|
return rule;
|
|
2078
2441
|
}
|
|
2079
2442
|
|
|
2080
2443
|
// anything else
|
|
2081
2444
|
// Consume a component value from input and append the result to rule’s prelude.
|
|
2082
|
-
|
|
2445
|
+
prelude.push(consumeAComponentValue(ts, t));
|
|
2083
2446
|
}
|
|
2084
2447
|
};
|
|
2085
2448
|
|
|
@@ -2245,22 +2608,17 @@ const consumeADeclaration = (ts, nested = false) => {
|
|
|
2245
2608
|
const { input } = ts;
|
|
2246
2609
|
// Let decl be a new declaration, with an initially empty name and a value set to an empty list.
|
|
2247
2610
|
const start = ts.next().start;
|
|
2611
|
+
// name "" / nameStart / nameEnd (= start) / important (false) keep their
|
|
2612
|
+
// `Container` defaults; `value` is set unconditionally at step 5 below.
|
|
2248
2613
|
const decl = /** @type {Declaration} */ (
|
|
2249
|
-
|
|
2614
|
+
_mkContainer(T_DECLARATION, start, start)
|
|
2250
2615
|
);
|
|
2251
|
-
decl.name = "";
|
|
2252
|
-
decl.nameStart = start;
|
|
2253
|
-
decl.nameEnd = start;
|
|
2254
|
-
decl.value = /** @type {ComponentValue[]} */ ([]);
|
|
2255
|
-
decl.important = false;
|
|
2256
2616
|
|
|
2257
2617
|
// 1. If the next token is an <ident-token>, consume a token from input and set decl's name to the returned token's value.
|
|
2258
2618
|
// Otherwise, consume the remnants of a bad declaration from input, with nested, and return nothing.
|
|
2259
2619
|
if (ts.next().type === TT_IDENTIFIER) {
|
|
2260
2620
|
const head = ts.consume();
|
|
2261
|
-
decl.
|
|
2262
|
-
decl.nameEnd = head.end;
|
|
2263
|
-
decl.name = input.slice(head.start, head.end);
|
|
2621
|
+
_setName(decl, input.slice(head.start, head.end), head.start, head.end);
|
|
2264
2622
|
} else {
|
|
2265
2623
|
consumeTheRemnantsOfABadDeclaration(ts, nested);
|
|
2266
2624
|
return undefined;
|
|
@@ -2282,51 +2640,42 @@ const consumeADeclaration = (ts, nested = false) => {
|
|
|
2282
2640
|
while (ts.next().type === TT_WHITESPACE) ts.discard();
|
|
2283
2641
|
|
|
2284
2642
|
// 5. Consume a list of component values from input, with nested, and with <semicolon-token> as the stop token, and set decl's value to the result.
|
|
2285
|
-
|
|
2286
|
-
decl
|
|
2643
|
+
const value = consumeAListOfComponentValues(ts, TT_SEMICOLON, nested);
|
|
2644
|
+
_setValue(decl, value);
|
|
2645
|
+
_setEnd(decl, ts.next().start);
|
|
2287
2646
|
|
|
2288
2647
|
// 6. If the last two non-<whitespace-token>s in decl's value are a <delim-token> with the value "!" followed by an <ident-token> with a value that is an ASCII case-insensitive match for "important", remove them from decl's value and set decl's important flag.
|
|
2289
2648
|
{
|
|
2290
|
-
let last =
|
|
2291
|
-
while (last >= 0 &&
|
|
2649
|
+
let last = value.length - 1;
|
|
2650
|
+
while (last >= 0 && _nType(value[last]) === T_WHITESPACE) last--;
|
|
2292
2651
|
let prev = last - 1;
|
|
2293
|
-
while (prev >= 0 &&
|
|
2652
|
+
while (prev >= 0 && _nType(value[prev]) === T_WHITESPACE) prev--;
|
|
2294
2653
|
if (
|
|
2295
2654
|
prev >= 0 &&
|
|
2296
|
-
|
|
2297
|
-
equalsLowerCase(
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
) &&
|
|
2301
|
-
decl.value[prev].type === T_DELIM &&
|
|
2302
|
-
input.charCodeAt(decl.value[prev].start) === CC_EXCLAMATION
|
|
2655
|
+
_nType(value[last]) === T_IDENT &&
|
|
2656
|
+
equalsLowerCase(_nValue(value[last]), "important") &&
|
|
2657
|
+
_nType(value[prev]) === T_DELIM &&
|
|
2658
|
+
input.charCodeAt(_nStart(value[prev])) === CC_EXCLAMATION
|
|
2303
2659
|
) {
|
|
2304
|
-
decl
|
|
2305
|
-
|
|
2660
|
+
_setImportant(decl);
|
|
2661
|
+
value.length = prev;
|
|
2306
2662
|
}
|
|
2307
2663
|
}
|
|
2308
2664
|
|
|
2309
2665
|
// 7. While the last item in decl's value is a <whitespace-token>, remove that token.
|
|
2310
|
-
while (
|
|
2311
|
-
|
|
2312
|
-
decl.value[decl.value.length - 1].type === T_WHITESPACE
|
|
2313
|
-
) {
|
|
2314
|
-
decl.value.pop();
|
|
2666
|
+
while (value.length > 0 && _nType(value[value.length - 1]) === T_WHITESPACE) {
|
|
2667
|
+
value.pop();
|
|
2315
2668
|
}
|
|
2316
2669
|
|
|
2317
2670
|
// 8. If decl's name starts with "--" (a custom property), it can contain any value (including a top-level `{}` block) — accept it.
|
|
2318
2671
|
// Otherwise, if decl's value contains a top-level simple block with an associated token of <{-token>, return nothing.
|
|
2319
2672
|
// (That is, a top-level {}-block is only allowed as the entire value of a non-custom property — for CSS Nesting, `consumeABlocksContents`'s `mark` / `restore a mark` will retry the input as a qualified rule.)
|
|
2320
2673
|
// Otherwise, accept the declaration. (The spec also checks "contains any non-whitespace-tokens at the top level" → return nothing; we keep empty-value declarations because callers — e.g. `@value name:;` — rely on them.)
|
|
2321
|
-
const isCustomProperty = input.startsWith("--",
|
|
2674
|
+
const isCustomProperty = input.startsWith("--", start);
|
|
2322
2675
|
if (!isCustomProperty) {
|
|
2323
|
-
const value = decl.value;
|
|
2324
2676
|
for (let i = 0; i < value.length; i++) {
|
|
2325
2677
|
const v = value[i];
|
|
2326
|
-
if (
|
|
2327
|
-
v.type === T_SIMPLE_BLOCK &&
|
|
2328
|
-
/** @type {SimpleBlock} */ (v).token === "{"
|
|
2329
|
-
) {
|
|
2678
|
+
if (_nType(v) === T_SIMPLE_BLOCK && _nToken(v) === "{") {
|
|
2330
2679
|
return undefined;
|
|
2331
2680
|
}
|
|
2332
2681
|
}
|
|
@@ -2366,17 +2715,19 @@ const consumeAListOfComponentValues = (ts, stopToken, nested = false) => {
|
|
|
2366
2715
|
}
|
|
2367
2716
|
// anything else
|
|
2368
2717
|
// Consume a component value from input, and append the result to values.
|
|
2369
|
-
values.push(consumeAComponentValue(ts));
|
|
2718
|
+
values.push(consumeAComponentValue(ts, t));
|
|
2370
2719
|
}
|
|
2371
2720
|
};
|
|
2372
2721
|
|
|
2373
2722
|
/**
|
|
2374
2723
|
* Consume a component value, CSS Syntax Level 3 [§5.4.8](https://drafts.csswg.org/css-syntax/#consume-component-value) — consumes the next value (simple block, function, or single token); callers guard against EOF before calling.
|
|
2375
2724
|
* @param {TokenStream} ts token stream
|
|
2725
|
+
* @param {MutableToken=} t the next token, if the caller already peeked it (defaults to `ts.next()`)
|
|
2376
2726
|
* @returns {SimpleBlock | FunctionNode | ComponentValue} the consumed component value
|
|
2377
2727
|
*/
|
|
2378
|
-
const consumeAComponentValue = (ts) => {
|
|
2379
|
-
|
|
2728
|
+
const consumeAComponentValue = (ts, t = ts.next()) => {
|
|
2729
|
+
// `t` is the next token; hot callers already peeked it and pass it in to
|
|
2730
|
+
// skip a redundant `ts.next()` per component value.
|
|
2380
2731
|
// <{-token> / <[-token> / <(-token> (the three contiguous opening brackets)
|
|
2381
2732
|
// Consume a simple block from input and return the result.
|
|
2382
2733
|
if (t.type >= TT_LEFT_PARENTHESIS && t.type <= TT_LEFT_CURLY_BRACKET) {
|
|
@@ -2389,7 +2740,11 @@ const consumeAComponentValue = (ts) => {
|
|
|
2389
2740
|
}
|
|
2390
2741
|
// anything else
|
|
2391
2742
|
// Consume a token from input and return the result. (Asserted: not EOF.)
|
|
2392
|
-
|
|
2743
|
+
// Inlined `consumeATokenAsNode`: `t` is already the peeked next token, so
|
|
2744
|
+
// advance past it and materialize it directly — one fewer call per leaf
|
|
2745
|
+
// component value (the bulk of the nodes on a large stylesheet).
|
|
2746
|
+
ts.consume();
|
|
2747
|
+
return /** @type {ComponentValue} */ (tokenToNode(t));
|
|
2393
2748
|
};
|
|
2394
2749
|
|
|
2395
2750
|
/**
|
|
@@ -2406,10 +2761,11 @@ const consumeASimpleBlock = (ts) => {
|
|
|
2406
2761
|
|
|
2407
2762
|
// Let block be a new simple block with its associated token set to the next token and with its value initially set to an empty list.
|
|
2408
2763
|
const block = /** @type {SimpleBlock} */ (
|
|
2409
|
-
|
|
2764
|
+
_mkContainer(T_SIMPLE_BLOCK, open.start, open.end)
|
|
2410
2765
|
);
|
|
2411
|
-
block
|
|
2412
|
-
|
|
2766
|
+
_setToken(block, token);
|
|
2767
|
+
const val = _list();
|
|
2768
|
+
_setValue(block, val);
|
|
2413
2769
|
|
|
2414
2770
|
// Discard a token from input.
|
|
2415
2771
|
ts.discard();
|
|
@@ -2423,13 +2779,13 @@ const consumeASimpleBlock = (ts) => {
|
|
|
2423
2779
|
// Discard a token from input. Return block.
|
|
2424
2780
|
if (t.type === TT_EOF || t.type === ending) {
|
|
2425
2781
|
ts.discard();
|
|
2426
|
-
block
|
|
2782
|
+
_setEnd(block, t.end);
|
|
2427
2783
|
return block;
|
|
2428
2784
|
}
|
|
2429
2785
|
|
|
2430
2786
|
// anything else
|
|
2431
2787
|
// Consume a component value from input and append the result to block’s value.
|
|
2432
|
-
|
|
2788
|
+
val.push(consumeAComponentValue(ts, t));
|
|
2433
2789
|
}
|
|
2434
2790
|
};
|
|
2435
2791
|
|
|
@@ -2439,17 +2795,16 @@ const consumeASimpleBlock = (ts) => {
|
|
|
2439
2795
|
* @returns {FunctionNode | undefined} the consumed function node
|
|
2440
2796
|
*/
|
|
2441
2797
|
const consumeAFunction = (ts) => {
|
|
2442
|
-
const { input
|
|
2798
|
+
const { input } = ts;
|
|
2443
2799
|
// Assert (spec): the next token is a <function-token>.
|
|
2444
2800
|
// Consume a token from input, and let function be a new function with its name equal the returned token’s value, and a value set to an empty list.
|
|
2445
2801
|
const tFn = ts.consume();
|
|
2446
2802
|
const fn = /** @type {FunctionNode} */ (
|
|
2447
|
-
|
|
2803
|
+
_mkContainer(T_FUNCTION, tFn.start, tFn.end)
|
|
2448
2804
|
);
|
|
2449
|
-
fn
|
|
2450
|
-
|
|
2451
|
-
fn
|
|
2452
|
-
fn.value = /** @type {ComponentValue[]} */ ([]);
|
|
2805
|
+
_setName(fn, input.slice(tFn.start, tFn.end - 1), tFn.start, tFn.end - 1);
|
|
2806
|
+
const val = _list();
|
|
2807
|
+
_setValue(fn, val);
|
|
2453
2808
|
|
|
2454
2809
|
// Process input
|
|
2455
2810
|
for (;;) {
|
|
@@ -2460,13 +2815,13 @@ const consumeAFunction = (ts) => {
|
|
|
2460
2815
|
// <)-token>
|
|
2461
2816
|
// Discard a token from input. Return function.
|
|
2462
2817
|
ts.discard();
|
|
2463
|
-
fn
|
|
2818
|
+
_setEnd(fn, t.end);
|
|
2464
2819
|
return fn;
|
|
2465
2820
|
}
|
|
2466
2821
|
|
|
2467
2822
|
// anything else
|
|
2468
2823
|
// Consume a component value from input and append the result to function’s value.
|
|
2469
|
-
|
|
2824
|
+
val.push(consumeAComponentValue(ts, t));
|
|
2470
2825
|
}
|
|
2471
2826
|
};
|
|
2472
2827
|
|
|
@@ -2690,6 +3045,7 @@ const TOP_LEVEL_CONSUMERS = {
|
|
|
2690
3045
|
const grammar = (input, visitors, options) => {
|
|
2691
3046
|
const { comment } = options;
|
|
2692
3047
|
const locConverter = options.locConverter || new LocConverter(input);
|
|
3048
|
+
useSoaBackend(input, locConverter);
|
|
2693
3049
|
const recurseBlocks = options.recurseBlocks !== false;
|
|
2694
3050
|
|
|
2695
3051
|
// Babel's `path.skip()`, children-only. Reset per `enter` dispatch.
|
|
@@ -2708,7 +3064,8 @@ const grammar = (input, visitors, options) => {
|
|
|
2708
3064
|
* @param {Node | null} parent enclosing node
|
|
2709
3065
|
*/
|
|
2710
3066
|
const walkValue = (node, parent) => {
|
|
2711
|
-
const
|
|
3067
|
+
const ty = _soaTy[_ix(node)];
|
|
3068
|
+
const b = visitors[ty];
|
|
2712
3069
|
let skip = false;
|
|
2713
3070
|
if (b !== undefined && b.enter.length !== 0) {
|
|
2714
3071
|
skipFlag = false;
|
|
@@ -2717,16 +3074,9 @@ const grammar = (input, visitors, options) => {
|
|
|
2717
3074
|
skip = skipFlag;
|
|
2718
3075
|
skipFlag = false;
|
|
2719
3076
|
}
|
|
2720
|
-
if (!skip) {
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
case T_SIMPLE_BLOCK: {
|
|
2724
|
-
const v = /** @type {FunctionNode | SimpleBlock} */ (node).value;
|
|
2725
|
-
for (let i = 0; i < v.length; i++) walkValue(v[i], node);
|
|
2726
|
-
break;
|
|
2727
|
-
}
|
|
2728
|
-
// All other types are leaf tokens.
|
|
2729
|
-
}
|
|
3077
|
+
if (!skip && (ty === T_FUNCTION || ty === T_SIMPLE_BLOCK)) {
|
|
3078
|
+
const v = /** @type {Node[]} */ (_soaL0[_ix(node)]);
|
|
3079
|
+
for (let i = 0; i < v.length; i++) walkValue(v[i], node);
|
|
2730
3080
|
}
|
|
2731
3081
|
if (b !== undefined) {
|
|
2732
3082
|
const x = b.exit;
|
|
@@ -2741,7 +3091,9 @@ const grammar = (input, visitors, options) => {
|
|
|
2741
3091
|
* @param {Node | null} parent enclosing node
|
|
2742
3092
|
*/
|
|
2743
3093
|
const walkRule = (node, parent) => {
|
|
2744
|
-
const
|
|
3094
|
+
const i0 = _ix(node);
|
|
3095
|
+
const ty = _soaTy[i0];
|
|
3096
|
+
const b = visitors[ty];
|
|
2745
3097
|
let skip = false;
|
|
2746
3098
|
if (b !== undefined && b.enter.length !== 0) {
|
|
2747
3099
|
skipFlag = false;
|
|
@@ -2751,28 +3103,21 @@ const grammar = (input, visitors, options) => {
|
|
|
2751
3103
|
skipFlag = false;
|
|
2752
3104
|
}
|
|
2753
3105
|
if (!skip) {
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
if (
|
|
2761
|
-
|
|
2762
|
-
const decls = r.declarations;
|
|
2763
|
-
if (decls) {
|
|
2764
|
-
for (let i = 0; i < decls.length; i++) walkRule(decls[i], node);
|
|
2765
|
-
}
|
|
2766
|
-
const ch = r.childRules;
|
|
2767
|
-
if (ch) for (let i = 0; i < ch.length; i++) walkRule(ch[i], node);
|
|
3106
|
+
if (ty === T_AT_RULE || ty === T_QUALIFIED_RULE) {
|
|
3107
|
+
const p = /** @type {Node[]} */ (_soaL0[i0]);
|
|
3108
|
+
for (let i = 0; i < p.length; i++) walkValue(p[i], node);
|
|
3109
|
+
if (recurseBlocks) {
|
|
3110
|
+
// Declarations then child rules — downstream consumers don't need them strictly interleaved in source order.
|
|
3111
|
+
const decls = _soaL1[i0];
|
|
3112
|
+
if (decls) {
|
|
3113
|
+
for (let i = 0; i < decls.length; i++) walkRule(decls[i], node);
|
|
2768
3114
|
}
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
case T_DECLARATION: {
|
|
2772
|
-
const v = /** @type {Declaration} */ (node).value;
|
|
2773
|
-
for (let i = 0; i < v.length; i++) walkValue(v[i], node);
|
|
2774
|
-
break;
|
|
3115
|
+
const ch = _soaL2[i0];
|
|
3116
|
+
if (ch) for (let i = 0; i < ch.length; i++) walkRule(ch[i], node);
|
|
2775
3117
|
}
|
|
3118
|
+
} else if (ty === T_DECLARATION) {
|
|
3119
|
+
const v = /** @type {Node[]} */ (_soaL0[i0]);
|
|
3120
|
+
for (let i = 0; i < v.length; i++) walkValue(v[i], node);
|
|
2776
3121
|
}
|
|
2777
3122
|
}
|
|
2778
3123
|
if (b !== undefined) {
|
|
@@ -2788,7 +3133,10 @@ const grammar = (input, visitors, options) => {
|
|
|
2788
3133
|
const consume =
|
|
2789
3134
|
TOP_LEVEL_CONSUMERS[options.as || "stylesheet"] ||
|
|
2790
3135
|
consumeAStylesheetsContents;
|
|
2791
|
-
consume(ts, (node) =>
|
|
3136
|
+
consume(ts, (node) => {
|
|
3137
|
+
walkRule(node, null);
|
|
3138
|
+
_soaN = 0;
|
|
3139
|
+
});
|
|
2792
3140
|
};
|
|
2793
3141
|
|
|
2794
3142
|
/**
|
|
@@ -2807,12 +3155,127 @@ class SourceProcessor extends GenericSourceProcessor {
|
|
|
2807
3155
|
}
|
|
2808
3156
|
}
|
|
2809
3157
|
|
|
3158
|
+
// AST field-access seam. Every AST-node field read by `CssParser` goes through
|
|
3159
|
+
// one of these accessors so the node representation can change underneath the
|
|
3160
|
+
// consumer without touching it. Today they are backed by the `Node` / `Token` /
|
|
3161
|
+
// `Container` objects (`n` is a node); the Struct-of-Arrays migration rewrites
|
|
3162
|
+
// the bodies to index typed arrays (`n` becomes an integer node id) without any
|
|
3163
|
+
// consumer edit. `value` is the leaf-token string; container child lists are
|
|
3164
|
+
// `children` / `prelude` / `declarations` / `childRules`.
|
|
3165
|
+
const A = {
|
|
3166
|
+
/** @type {(n: Node) => number} */
|
|
3167
|
+
type: (n) => _soaTy[_ix(n)],
|
|
3168
|
+
/** @type {(n: Node) => number} */
|
|
3169
|
+
start: (n) => _soaSt[_ix(n)],
|
|
3170
|
+
/** @type {(n: Node) => number} */
|
|
3171
|
+
end: (n) => _soaEn[_ix(n)],
|
|
3172
|
+
/** @type {(n: Node) => [number, number]} */
|
|
3173
|
+
range: (n) => {
|
|
3174
|
+
const i = _ix(n);
|
|
3175
|
+
return [_soaSt[i], _soaEn[i]];
|
|
3176
|
+
},
|
|
3177
|
+
/** @type {(n: Node) => { start: { line: number, column: number }, end: { line: number, column: number } }} */
|
|
3178
|
+
loc: (n) => {
|
|
3179
|
+
const i = _ix(n);
|
|
3180
|
+
const lc = _soaLC;
|
|
3181
|
+
const s = lc.get(_soaSt[i]);
|
|
3182
|
+
const sl = s.line;
|
|
3183
|
+
const sc = s.column;
|
|
3184
|
+
const e = lc.get(_soaEn[i]);
|
|
3185
|
+
return {
|
|
3186
|
+
start: { line: sl, column: sc },
|
|
3187
|
+
end: { line: e.line, column: e.column }
|
|
3188
|
+
};
|
|
3189
|
+
},
|
|
3190
|
+
/** @type {(n: Node) => string} */
|
|
3191
|
+
source: (n) => {
|
|
3192
|
+
const i = _ix(n);
|
|
3193
|
+
return _soaInput.slice(_soaSt[i], _soaEn[i]);
|
|
3194
|
+
},
|
|
3195
|
+
/** @type {(n: Node) => string} */
|
|
3196
|
+
value: (n) => _soaValueOf(_ix(n)),
|
|
3197
|
+
/** @type {(n: Node) => string} */
|
|
3198
|
+
unescaped: (n) => {
|
|
3199
|
+
const i = _ix(n);
|
|
3200
|
+
const v = _soaValueOf(i);
|
|
3201
|
+
return _soaTy[i] === T_STRING
|
|
3202
|
+
? unescapeIdentifier(v.slice(1, -1))
|
|
3203
|
+
: unescapeIdentifier(v);
|
|
3204
|
+
},
|
|
3205
|
+
/** @type {(n: Node) => string} */
|
|
3206
|
+
typeFlag: (n) => {
|
|
3207
|
+
const i = _ix(n);
|
|
3208
|
+
if (_soaTy[i] === T_HASH) {
|
|
3209
|
+
const input = _soaInput;
|
|
3210
|
+
const p = _soaSt[i] + 1;
|
|
3211
|
+
return _ifThreeCodePointsWouldStartAnIdentSequence(
|
|
3212
|
+
input,
|
|
3213
|
+
p,
|
|
3214
|
+
input.charCodeAt(p),
|
|
3215
|
+
input.charCodeAt(p + 1),
|
|
3216
|
+
input.charCodeAt(p + 2)
|
|
3217
|
+
)
|
|
3218
|
+
? "id"
|
|
3219
|
+
: "unrestricted";
|
|
3220
|
+
}
|
|
3221
|
+
const v = _soaValueOf(i);
|
|
3222
|
+
return _typeFlagOf(
|
|
3223
|
+
_soaTy[i] === T_DIMENSION ? v.slice(0, _consumeANumber(v, 0)) : v
|
|
3224
|
+
);
|
|
3225
|
+
},
|
|
3226
|
+
/** @type {(n: Node) => number} */
|
|
3227
|
+
contentStart: (n) => _soaA0[_ix(n)],
|
|
3228
|
+
/** @type {(n: Node) => number} */
|
|
3229
|
+
contentEnd: (n) => _soaA1[_ix(n)],
|
|
3230
|
+
/** @type {(n: Node) => string} */
|
|
3231
|
+
name: (n) => {
|
|
3232
|
+
const i = _ix(n);
|
|
3233
|
+
return _soaTy[i] === T_AT_RULE
|
|
3234
|
+
? _soaInput.slice(_soaSt[i] + 1, _soaA0[i])
|
|
3235
|
+
: _soaInput.slice(_soaSt[i], _soaA0[i]);
|
|
3236
|
+
},
|
|
3237
|
+
/** @type {(n: Node) => number} */
|
|
3238
|
+
nameStart: (n) => _soaSt[_ix(n)],
|
|
3239
|
+
/** @type {(n: Node) => number} */
|
|
3240
|
+
nameEnd: (n) => _soaA0[_ix(n)],
|
|
3241
|
+
/** @type {(n: Node) => string} */
|
|
3242
|
+
unescapedName: (n) => unescapeIdentifier(A.name(n)),
|
|
3243
|
+
/** @type {(n: Node) => ComponentValue[]} */
|
|
3244
|
+
children: (n) => /** @type {ComponentValue[]} */ (_soaL0[_ix(n)]),
|
|
3245
|
+
/** @type {(n: Node) => ComponentValue[]} */
|
|
3246
|
+
prelude: (n) => /** @type {ComponentValue[]} */ (_soaL0[_ix(n)]),
|
|
3247
|
+
/** @type {(n: Node) => Declaration[] | null} */
|
|
3248
|
+
declarations: (n) => /** @type {Declaration[] | null} */ (_soaL1[_ix(n)]),
|
|
3249
|
+
/** @type {(n: Node) => Rule[] | null} */
|
|
3250
|
+
childRules: (n) => /** @type {Rule[] | null} */ (_soaL2[_ix(n)]),
|
|
3251
|
+
/** @type {(n: Node) => number} */
|
|
3252
|
+
blockStart: (n) => _soaA1[_ix(n)],
|
|
3253
|
+
/** @type {(n: Node) => number} */
|
|
3254
|
+
blockEnd: (n) => _soaA2[_ix(n)],
|
|
3255
|
+
/** @type {(n: Node) => boolean} */
|
|
3256
|
+
important: (n) => (_soaFl[_ix(n)] & 1) !== 0,
|
|
3257
|
+
/** @type {(n: Node) => SimpleBlockToken} */
|
|
3258
|
+
blockToken: (n) =>
|
|
3259
|
+
/** @type {SimpleBlockToken} */ (_soaInput[_soaSt[_ix(n)]]),
|
|
3260
|
+
// Writers — `CssParser` rewrites a rule's end / block-end when it folds an
|
|
3261
|
+
// inline ICSS `:import` / `:export` body into a single dependency.
|
|
3262
|
+
/** @type {(n: Node, v: number) => void} */
|
|
3263
|
+
setEnd: (n, v) => {
|
|
3264
|
+
_soaEn[_ix(n)] = v;
|
|
3265
|
+
},
|
|
3266
|
+
/** @type {(n: Node, v: number) => void} */
|
|
3267
|
+
setBlockEnd: (n, v) => {
|
|
3268
|
+
_soaA2[_ix(n)] = v;
|
|
3269
|
+
}
|
|
3270
|
+
};
|
|
3271
|
+
|
|
2810
3272
|
// The two AST runtime classes — `Node` and its sole subclass `Token` (the
|
|
2811
3273
|
// other node shapes are `@typedef`s over `Node`, exported as types only). Plus
|
|
2812
3274
|
// the full CSS-Syntax-3 §5.3 `parseA*` entry-point surface, `consumeASimpleBlock`
|
|
2813
3275
|
// (the one §5.4 algorithm exposed as a byte entry point for `CssParser`), the
|
|
2814
3276
|
// `TokenStream` (so callers can pass a pre-built stream to any `parseA*`), and
|
|
2815
3277
|
// the `escape` / `unescapeIdentifier` string utils.
|
|
3278
|
+
module.exports.A = A;
|
|
2816
3279
|
module.exports.Node = Node;
|
|
2817
3280
|
module.exports.NodeType = NodeType;
|
|
2818
3281
|
module.exports.SourceProcessor = SourceProcessor;
|