webpack 5.108.2 → 5.108.4
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/Compilation.js +1 -4
- package/lib/FlagDependencyExportsPlugin.js +55 -8
- package/lib/LazyBarrel.js +30 -3
- package/lib/NormalModule.js +8 -12
- package/lib/config/defaults.js +3 -3
- package/lib/css/CssGenerator.js +33 -42
- package/lib/css/CssModulesPlugin.js +79 -53
- package/lib/css/CssParser.js +699 -449
- package/lib/css/syntax.js +1146 -360
- package/lib/dependencies/CssIcssExportDependency.js +28 -16
- package/lib/dependencies/HarmonyAcceptDependency.js +8 -16
- package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +23 -96
- package/lib/dependencies/HarmonyImportGuard.js +192 -20
- package/lib/dependencies/ImportParserPlugin.js +7 -9
- package/lib/html/HtmlGenerator.js +53 -76
- package/lib/html/HtmlModule.js +1 -0
- package/lib/html/HtmlModulesPlugin.js +24 -13
- package/lib/html/HtmlParser.js +240 -124
- package/lib/html/syntax.js +1362 -683
- package/lib/javascript/JavascriptParser.js +10 -0
- package/lib/url/URLParserPlugin.js +33 -7
- package/lib/util/LocConverter.js +9 -8
- package/lib/util/SourceProcessor.js +41 -28
- package/package.json +3 -3
- package/types.d.ts +79 -221
package/lib/css/CssParser.js
CHANGED
|
@@ -29,8 +29,10 @@ const {
|
|
|
29
29
|
} = require("../util/magicComment");
|
|
30
30
|
const topologicalSort = require("../util/topologicalSort");
|
|
31
31
|
const {
|
|
32
|
+
A,
|
|
32
33
|
NodeType,
|
|
33
34
|
SourceProcessor,
|
|
35
|
+
buildSkipSet,
|
|
34
36
|
equalsLowerCase,
|
|
35
37
|
unescapeIdentifier
|
|
36
38
|
} = require("./syntax");
|
|
@@ -65,6 +67,7 @@ const {
|
|
|
65
67
|
/** @typedef {{ localName: string, value: string }} ValueAtRuleValue */
|
|
66
68
|
|
|
67
69
|
const CC_COLON = ":".charCodeAt(0);
|
|
70
|
+
const CC_HYPHEN_MINUS = "-".charCodeAt(0);
|
|
68
71
|
const CC_SEMICOLON = ";".charCodeAt(0);
|
|
69
72
|
const CC_TAB = "\t".charCodeAt(0);
|
|
70
73
|
const CC_SPACE = " ".charCodeAt(0);
|
|
@@ -91,8 +94,32 @@ const IMAGE_SET_FUNCTION = /^(?:-\w+-)?image-set$/i;
|
|
|
91
94
|
const MAGIC_COMMENT_FAST_PATH =
|
|
92
95
|
/^\s*(webpack[A-Z][A-Za-z]+)\s*:\s*(true|false|null|-?\d+(?:\.\d+)?)\s*$/;
|
|
93
96
|
const OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE = /^@(?:-\w+-)?keyframes$/;
|
|
97
|
+
const VENDOR_PREFIX = /^-\w+-/;
|
|
94
98
|
const COMPOSES_PROPERTY = /^(?:composes|compose-with)$/i;
|
|
95
99
|
const IS_MODULES = /\.modules?\.[^.]+$/i;
|
|
100
|
+
|
|
101
|
+
// Skip options for a non-CSS-Modules parse: drop the selector prelude (never
|
|
102
|
+
// walked without modules) plus value / function-arg leaves nothing reads (the
|
|
103
|
+
// `Ident` visitor no-ops, the `Declaration` visitor returns early, no ICSS).
|
|
104
|
+
// `url` / functions / strings / blocks / commas are kept — they carry url()
|
|
105
|
+
// rewrites and image-set fences. At-rule preludes are kept (`@media` / `@import`
|
|
106
|
+
// are read). CSS-Modules parses skip nothing: selectors are walked and ICSS
|
|
107
|
+
// `:export { k: v }` captures each value's byte range from its first / last node.
|
|
108
|
+
const SKIP_NON_MODULES = {
|
|
109
|
+
types: buildSkipSet([
|
|
110
|
+
NodeType.Number,
|
|
111
|
+
NodeType.Dimension,
|
|
112
|
+
NodeType.Percentage,
|
|
113
|
+
NodeType.Ident,
|
|
114
|
+
NodeType.Hash,
|
|
115
|
+
NodeType.Colon,
|
|
116
|
+
NodeType.Delim,
|
|
117
|
+
// Nothing reads value/arg whitespace either — consumers use
|
|
118
|
+
// `nextNonWhitespace` / type checks that tolerate its absence.
|
|
119
|
+
NodeType.Whitespace
|
|
120
|
+
]),
|
|
121
|
+
selectorPrelude: true
|
|
122
|
+
};
|
|
96
123
|
const CSS_COMMENT = /\/\*((?!\*\/)[\s\S]*?)\*\//g;
|
|
97
124
|
// `@value` recognizers (postcss-modules-values shape): the import form `<names> from <source>`, and the `<importName> as <localName>` alias inside it.
|
|
98
125
|
const VALUE_IMPORT_FORM = /from(\/\*|\s)(?:[\s\S]+)$/i;
|
|
@@ -182,6 +209,109 @@ const normalizeUrl = (str, isString) => {
|
|
|
182
209
|
const isDashedIdentifier = (identifier) =>
|
|
183
210
|
identifier.startsWith("--") && identifier.length >= 3;
|
|
184
211
|
|
|
212
|
+
/**
|
|
213
|
+
* `s.toLowerCase()` that returns `s` itself (no allocation) when it can't
|
|
214
|
+
* change — no ASCII uppercase and no non-ASCII (whose Unicode case mapping is
|
|
215
|
+
* left to the real `toLowerCase`).
|
|
216
|
+
* @param {string} s string
|
|
217
|
+
* @returns {string} lowercased string
|
|
218
|
+
*/
|
|
219
|
+
const toLowerCaseIfNeeded = (s) => {
|
|
220
|
+
for (let i = 0; i < s.length; i++) {
|
|
221
|
+
const c = s.charCodeAt(i);
|
|
222
|
+
if ((c >= 65 && c <= 90) || c > 127) return s.toLowerCase();
|
|
223
|
+
}
|
|
224
|
+
return s;
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Case-sensitive equality of a source range against a literal — no slice.
|
|
229
|
+
* @param {string} input source
|
|
230
|
+
* @param {number} start range start
|
|
231
|
+
* @param {number} end range end (exclusive)
|
|
232
|
+
* @param {string} lit literal to match
|
|
233
|
+
* @returns {boolean} true when the range equals `lit`
|
|
234
|
+
*/
|
|
235
|
+
const rangeEquals = (input, start, end, lit) =>
|
|
236
|
+
end - start === lit.length && input.startsWith(lit, start);
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* ASCII case-insensitive equality of a source range against a lowercase ASCII literal — no slice.
|
|
240
|
+
* @param {string} input source
|
|
241
|
+
* @param {number} start range start
|
|
242
|
+
* @param {number} end range end (exclusive)
|
|
243
|
+
* @param {string} lit lowercase ASCII literal to match
|
|
244
|
+
* @returns {boolean} true when the range equals `lit` ignoring ASCII case
|
|
245
|
+
*/
|
|
246
|
+
const rangeEqualsLowerCase = (input, start, end, lit) => {
|
|
247
|
+
if (end - start !== lit.length) return false;
|
|
248
|
+
for (let i = 0; i < lit.length; i++) {
|
|
249
|
+
let c = input.charCodeAt(start + i);
|
|
250
|
+
if (c >= 65 && c <= 90) c |= 0x20;
|
|
251
|
+
if (c !== lit.charCodeAt(i)) return false;
|
|
252
|
+
}
|
|
253
|
+
return true;
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Range-keyed index over a known-properties table: ASCII-case-folded 31-hash
|
|
258
|
+
* of the name bytes → canonical key(s). Lets the Declaration visitor answer
|
|
259
|
+
* "is this a known property" (and get the canonical lowercase name) without
|
|
260
|
+
* slicing the property name out of the source per declaration.
|
|
261
|
+
* @type {WeakMap<Map<string, Record<string, number>>, Map<number, string | string[]>>}
|
|
262
|
+
*/
|
|
263
|
+
const KNOWN_PROPERTY_INDEX_CACHE = new WeakMap();
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Gets (or builds) the hash index for a known-properties table.
|
|
267
|
+
* @param {Map<string, Record<string, number>>} knownProperties known properties table
|
|
268
|
+
* @returns {Map<number, string | string[]>} hash → canonical name(s)
|
|
269
|
+
*/
|
|
270
|
+
const getKnownPropertyIndex = (knownProperties) => {
|
|
271
|
+
let index = KNOWN_PROPERTY_INDEX_CACHE.get(knownProperties);
|
|
272
|
+
if (index === undefined) {
|
|
273
|
+
index = new Map();
|
|
274
|
+
for (const name of knownProperties.keys()) {
|
|
275
|
+
let h = name.length;
|
|
276
|
+
for (let i = 0; i < name.length; i++) {
|
|
277
|
+
h = ((h << 5) - h + name.charCodeAt(i)) | 0;
|
|
278
|
+
}
|
|
279
|
+
const hit = index.get(h);
|
|
280
|
+
if (hit === undefined) index.set(h, name);
|
|
281
|
+
else if (typeof hit === "string") index.set(h, [hit, name]);
|
|
282
|
+
else hit.push(name);
|
|
283
|
+
}
|
|
284
|
+
KNOWN_PROPERTY_INDEX_CACHE.set(knownProperties, index);
|
|
285
|
+
}
|
|
286
|
+
return index;
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Canonical known-property name for a source range (ASCII case-insensitive), without slicing.
|
|
291
|
+
* @param {Map<number, string | string[]>} index hash index from `getKnownPropertyIndex`
|
|
292
|
+
* @param {string} input source
|
|
293
|
+
* @param {number} start name start
|
|
294
|
+
* @param {number} end name end (exclusive)
|
|
295
|
+
* @returns {string | undefined} canonical lowercase name, or undefined when unknown
|
|
296
|
+
*/
|
|
297
|
+
const knownPropertyForRange = (index, input, start, end) => {
|
|
298
|
+
let h = end - start;
|
|
299
|
+
for (let i = start; i < end; i++) {
|
|
300
|
+
let c = input.charCodeAt(i);
|
|
301
|
+
if (c >= 65 && c <= 90) c |= 0x20;
|
|
302
|
+
h = ((h << 5) - h + c) | 0;
|
|
303
|
+
}
|
|
304
|
+
const hit = index.get(h);
|
|
305
|
+
if (hit === undefined) return undefined;
|
|
306
|
+
if (typeof hit === "string") {
|
|
307
|
+
return rangeEqualsLowerCase(input, start, end, hit) ? hit : undefined;
|
|
308
|
+
}
|
|
309
|
+
for (let i = 0; i < hit.length; i++) {
|
|
310
|
+
if (rangeEqualsLowerCase(input, start, end, hit[i])) return hit[i];
|
|
311
|
+
}
|
|
312
|
+
return undefined;
|
|
313
|
+
};
|
|
314
|
+
|
|
185
315
|
/**
|
|
186
316
|
* `binarySearchBounds` comparator for `getComments` — hoisted so the lookup
|
|
187
317
|
* doesn't allocate a fresh closure per call.
|
|
@@ -577,26 +707,27 @@ const isPureBodyAtRule = (name) =>
|
|
|
577
707
|
|
|
578
708
|
/**
|
|
579
709
|
* Scan a rule body once: does it hold a direct declaration counted against the enclosing rule (a declaration, or one in a transparent conditional-group at-rule like `@media`/`@supports`/…) and does it hold a nested block (qualified rule or any block-bearing at-rule)?
|
|
580
|
-
* @param {
|
|
710
|
+
* @param {Declaration[] | null} declarations rule-body declarations
|
|
711
|
+
* @param {Rule[] | null} childRules rule-body child rules
|
|
581
712
|
* @returns {{ hasDirectDecl: boolean, hasNestedBlock: boolean }} scan result
|
|
582
713
|
*/
|
|
583
|
-
const scanRuleBody = (
|
|
584
|
-
let hasDirectDecl = Boolean(
|
|
585
|
-
body.declarations && body.declarations.length > 0
|
|
586
|
-
);
|
|
714
|
+
const scanRuleBody = (declarations, childRules) => {
|
|
715
|
+
let hasDirectDecl = Boolean(declarations && declarations.length > 0);
|
|
587
716
|
let hasNestedBlock = false;
|
|
588
|
-
if (
|
|
589
|
-
for (const child of
|
|
590
|
-
|
|
717
|
+
if (childRules) {
|
|
718
|
+
for (const child of childRules) {
|
|
719
|
+
const t = A.type(child);
|
|
720
|
+
if (t === NodeType.QualifiedRule) {
|
|
591
721
|
hasNestedBlock = true;
|
|
592
|
-
} else if (
|
|
593
|
-
const
|
|
594
|
-
|
|
722
|
+
} else if (t === NodeType.AtRule) {
|
|
723
|
+
const atDecls = A.declarations(child);
|
|
724
|
+
const atChildRules = A.childRules(child);
|
|
725
|
+
if (!atDecls && !atChildRules) continue;
|
|
595
726
|
hasNestedBlock = true;
|
|
596
727
|
if (
|
|
597
728
|
!hasDirectDecl &&
|
|
598
|
-
!isPureBodyAtRule(`@${
|
|
599
|
-
scanRuleBody(
|
|
729
|
+
!isPureBodyAtRule(`@${toLowerCaseIfNeeded(A.name(child))}`) &&
|
|
730
|
+
scanRuleBody(atDecls, atChildRules).hasDirectDecl
|
|
600
731
|
) {
|
|
601
732
|
hasDirectDecl = true;
|
|
602
733
|
}
|
|
@@ -686,7 +817,7 @@ const parseValueAtRuleParams = (str) => {
|
|
|
686
817
|
*/
|
|
687
818
|
const nextNonWhitespace = (nodes, from) => {
|
|
688
819
|
let i = from;
|
|
689
|
-
while (i < nodes.length && nodes[i]
|
|
820
|
+
while (i < nodes.length && A.type(nodes[i]) === NodeType.Whitespace) i++;
|
|
690
821
|
return i;
|
|
691
822
|
};
|
|
692
823
|
|
|
@@ -706,21 +837,22 @@ const parseImportPrelude = (prelude) => {
|
|
|
706
837
|
let supportsNode;
|
|
707
838
|
|
|
708
839
|
for (const cv of prelude) {
|
|
709
|
-
|
|
840
|
+
const t = A.type(cv);
|
|
841
|
+
if (t === NodeType.Whitespace) continue;
|
|
710
842
|
|
|
711
843
|
if (!urlNode) {
|
|
712
|
-
if (
|
|
844
|
+
if (t === NodeType.Url || t === NodeType.String) {
|
|
713
845
|
urlNode = cv;
|
|
714
846
|
continue;
|
|
715
847
|
}
|
|
716
848
|
if (
|
|
717
|
-
|
|
718
|
-
equalsLowerCase(
|
|
849
|
+
t === NodeType.Function &&
|
|
850
|
+
equalsLowerCase(A.unescapedName(cv), "url")
|
|
719
851
|
) {
|
|
720
852
|
urlNode = cv;
|
|
721
853
|
continue;
|
|
722
854
|
}
|
|
723
|
-
if (
|
|
855
|
+
if (t === NodeType.Ident) {
|
|
724
856
|
// CSS Modules: bare ident is a `@value` reference.
|
|
725
857
|
urlNode = cv;
|
|
726
858
|
continue;
|
|
@@ -729,14 +861,14 @@ const parseImportPrelude = (prelude) => {
|
|
|
729
861
|
}
|
|
730
862
|
|
|
731
863
|
if (!layerNode && !supportsNode) {
|
|
732
|
-
if (
|
|
733
|
-
if (equalsLowerCase(
|
|
864
|
+
if (t === NodeType.Ident) {
|
|
865
|
+
if (equalsLowerCase(A.unescaped(cv), "layer")) {
|
|
734
866
|
layerNode = cv;
|
|
735
867
|
continue;
|
|
736
868
|
}
|
|
737
869
|
} else if (
|
|
738
|
-
|
|
739
|
-
equalsLowerCase(
|
|
870
|
+
t === NodeType.Function &&
|
|
871
|
+
equalsLowerCase(A.unescapedName(cv), "layer")
|
|
740
872
|
) {
|
|
741
873
|
layerNode = cv;
|
|
742
874
|
continue;
|
|
@@ -745,11 +877,8 @@ const parseImportPrelude = (prelude) => {
|
|
|
745
877
|
|
|
746
878
|
if (
|
|
747
879
|
!supportsNode &&
|
|
748
|
-
|
|
749
|
-
equalsLowerCase(
|
|
750
|
-
/** @type {FunctionNode} */ (cv).unescapedName,
|
|
751
|
-
"supports"
|
|
752
|
-
)
|
|
880
|
+
t === NodeType.Function &&
|
|
881
|
+
equalsLowerCase(A.unescapedName(cv), "supports")
|
|
753
882
|
) {
|
|
754
883
|
supportsNode = /** @type {FunctionNode} */ (cv);
|
|
755
884
|
continue;
|
|
@@ -772,31 +901,28 @@ const parseImportPrelude = (prelude) => {
|
|
|
772
901
|
const parseIcssImportRequest = (second, rule, source) => {
|
|
773
902
|
/** @type {AstNode[] | undefined} */
|
|
774
903
|
let args;
|
|
775
|
-
if (
|
|
776
|
-
args =
|
|
904
|
+
if (A.type(second) === NodeType.Function) {
|
|
905
|
+
args = A.children(second);
|
|
777
906
|
} else {
|
|
778
|
-
for (const p of
|
|
779
|
-
if (
|
|
780
|
-
|
|
781
|
-
/** @type {SimpleBlock} */ (p).token === "("
|
|
782
|
-
) {
|
|
783
|
-
args = /** @type {SimpleBlock} */ (p).value;
|
|
907
|
+
for (const p of A.prelude(rule)) {
|
|
908
|
+
if (A.type(p) === NodeType.SimpleBlock && A.blockToken(p) === "(") {
|
|
909
|
+
args = A.children(p);
|
|
784
910
|
break;
|
|
785
911
|
}
|
|
786
912
|
}
|
|
787
913
|
}
|
|
788
914
|
// The first non-whitespace value inside `(...)` must be a string.
|
|
789
915
|
const innerStrToken =
|
|
790
|
-
args && args.find((v) =>
|
|
791
|
-
if (!innerStrToken ||
|
|
916
|
+
args && args.find((v) => A.type(v) !== NodeType.Whitespace);
|
|
917
|
+
if (!innerStrToken || A.type(innerStrToken) !== NodeType.String) {
|
|
792
918
|
const errorPos =
|
|
793
|
-
|
|
794
|
-
?
|
|
795
|
-
:
|
|
919
|
+
A.type(second) === NodeType.Function
|
|
920
|
+
? A.nameEnd(second) + 1
|
|
921
|
+
: A.end(second);
|
|
796
922
|
return { errorPos };
|
|
797
923
|
}
|
|
798
924
|
return {
|
|
799
|
-
request: source.slice(
|
|
925
|
+
request: source.slice(A.start(innerStrToken) + 1, A.end(innerStrToken) - 1)
|
|
800
926
|
};
|
|
801
927
|
};
|
|
802
928
|
|
|
@@ -918,6 +1044,8 @@ class CssParser extends Parser {
|
|
|
918
1044
|
exportMode = CssIcssExportDependency.EXPORT_MODE.REPLACE,
|
|
919
1045
|
exportType = CssIcssExportDependency.EXPORT_TYPE.NORMAL
|
|
920
1046
|
) => {
|
|
1047
|
+
// Flat location numbers — the nested loc objects were the parser's
|
|
1048
|
+
// hottest allocation (3 objects per exported name).
|
|
921
1049
|
cssExportEntries.push({
|
|
922
1050
|
name,
|
|
923
1051
|
value,
|
|
@@ -925,7 +1053,10 @@ class CssParser extends Parser {
|
|
|
925
1053
|
interpolate,
|
|
926
1054
|
exportMode,
|
|
927
1055
|
exportType,
|
|
928
|
-
|
|
1056
|
+
locStartLine: sl,
|
|
1057
|
+
locStartColumn: sc,
|
|
1058
|
+
locEndLine: el,
|
|
1059
|
+
locEndColumn: ec
|
|
929
1060
|
});
|
|
930
1061
|
};
|
|
931
1062
|
|
|
@@ -942,12 +1073,29 @@ class CssParser extends Parser {
|
|
|
942
1073
|
|
|
943
1074
|
const isModules = mode === "global" || mode === "local";
|
|
944
1075
|
|
|
1076
|
+
/** @type {Map<string, boolean>} */
|
|
1077
|
+
const selfReferenceCache = new Map();
|
|
1078
|
+
|
|
945
1079
|
/**
|
|
946
1080
|
* Whether a relative `from "<request>"` resolves back to the current module (matching query/fragment too).
|
|
1081
|
+
* Memoized per parse — `composes … from "./x.css"` repeats the same request many times per file.
|
|
947
1082
|
* @param {string} request request string from `from "<request>"`
|
|
948
1083
|
* @returns {boolean} true if request resolves to the current module
|
|
949
1084
|
*/
|
|
950
1085
|
const isSelfReferenceRequest = (request) => {
|
|
1086
|
+
const cached = selfReferenceCache.get(request);
|
|
1087
|
+
if (cached !== undefined) return cached;
|
|
1088
|
+
const result = isSelfReferenceRequestUncached(request);
|
|
1089
|
+
selfReferenceCache.set(request, result);
|
|
1090
|
+
return result;
|
|
1091
|
+
};
|
|
1092
|
+
|
|
1093
|
+
/**
|
|
1094
|
+
* Uncached `isSelfReferenceRequest`.
|
|
1095
|
+
* @param {string} request request string from `from "<request>"`
|
|
1096
|
+
* @returns {boolean} true if request resolves to the current module
|
|
1097
|
+
*/
|
|
1098
|
+
const isSelfReferenceRequestUncached = (request) => {
|
|
951
1099
|
if (!RELATIVE_REQUEST.test(request)) return false;
|
|
952
1100
|
if (!module.context) return false;
|
|
953
1101
|
const parsedRequest = parseResource(request);
|
|
@@ -971,6 +1119,7 @@ class CssParser extends Parser {
|
|
|
971
1119
|
customIdents: this.options.customIdents,
|
|
972
1120
|
grid: this.options.grid
|
|
973
1121
|
});
|
|
1122
|
+
const knownPropertyIndex = getKnownPropertyIndex(knownProperties);
|
|
974
1123
|
|
|
975
1124
|
/** @type {CssModuleBuildMeta} */
|
|
976
1125
|
(module.buildMeta).isCssModule = isModules;
|
|
@@ -1054,7 +1203,7 @@ class CssParser extends Parser {
|
|
|
1054
1203
|
/**
|
|
1055
1204
|
* Unescape a CSS identifier from a source byte range — for value spans not
|
|
1056
1205
|
* backed by a single token (string contents, `--` dashed-ident bodies,
|
|
1057
|
-
* composed names). Token-backed names use `
|
|
1206
|
+
* composed names). Token-backed names use `A.unescaped(node)` instead.
|
|
1058
1207
|
* @param {number} start start offset
|
|
1059
1208
|
* @param {number} end end offset
|
|
1060
1209
|
* @returns {string} the unescaped identifier
|
|
@@ -1170,10 +1319,10 @@ class CssParser extends Parser {
|
|
|
1170
1319
|
const hasBody = Boolean(declarations || childRules);
|
|
1171
1320
|
let leaf = treatAsLeaf || !hasBody;
|
|
1172
1321
|
if (!leaf && hasBody) {
|
|
1173
|
-
const { hasDirectDecl, hasNestedBlock } = scanRuleBody(
|
|
1322
|
+
const { hasDirectDecl, hasNestedBlock } = scanRuleBody(
|
|
1174
1323
|
declarations,
|
|
1175
1324
|
childRules
|
|
1176
|
-
|
|
1325
|
+
);
|
|
1177
1326
|
leaf = hasDirectDecl || !hasNestedBlock;
|
|
1178
1327
|
}
|
|
1179
1328
|
if (leaf) this.report(preludeStart, preludeEnd);
|
|
@@ -1244,18 +1393,17 @@ class CssParser extends Parser {
|
|
|
1244
1393
|
modeData ? modeData === "local" : mode === "local";
|
|
1245
1394
|
|
|
1246
1395
|
/**
|
|
1247
|
-
* Comment
|
|
1248
|
-
* @param {
|
|
1249
|
-
* @param {number} start start
|
|
1250
|
-
* @param {number} end end
|
|
1251
|
-
* @returns {number} end
|
|
1396
|
+
* Comment visitor (`NodeType.Comment`): push every comment (in source order) onto the local `comments`, read back by `advanceCommentCursor` (pure-mode flags) and `parseCommentOptions` (magic comments).
|
|
1397
|
+
* @param {import("./syntax").CssPath} path walk path at the comment node
|
|
1252
1398
|
*/
|
|
1253
|
-
const
|
|
1399
|
+
const commentVisitor = (path) => {
|
|
1400
|
+
const node = path.node;
|
|
1401
|
+
const start = A.start(node);
|
|
1402
|
+
const end = A.end(node);
|
|
1254
1403
|
comments.push({
|
|
1255
|
-
value:
|
|
1404
|
+
value: source.slice(start + 2, end - 2),
|
|
1256
1405
|
range: [start, end]
|
|
1257
1406
|
});
|
|
1258
|
-
return end;
|
|
1259
1407
|
};
|
|
1260
1408
|
|
|
1261
1409
|
/**
|
|
@@ -1457,21 +1605,22 @@ class CssParser extends Parser {
|
|
|
1457
1605
|
};
|
|
1458
1606
|
|
|
1459
1607
|
// Body `{ name: value; … }` is parsed eagerly (§5.4.4) — emit a dep per declaration.
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1608
|
+
const ruleDecls = A.declarations(rule);
|
|
1609
|
+
if (!ruleDecls || A.blockStart(rule) === -1) return A.end(second);
|
|
1610
|
+
for (const decl of ruleDecls) {
|
|
1611
|
+
const vals = A.children(decl);
|
|
1463
1612
|
if (vals.length === 0) continue;
|
|
1464
|
-
const rawStart = vals[0]
|
|
1465
|
-
const rawEnd = vals[vals.length - 1]
|
|
1613
|
+
const rawStart = A.start(vals[0]);
|
|
1614
|
+
const rawEnd = A.end(vals[vals.length - 1]);
|
|
1466
1615
|
createDep(
|
|
1467
|
-
source.slice(
|
|
1616
|
+
source.slice(A.nameStart(decl), A.nameEnd(decl)),
|
|
1468
1617
|
source.slice(rawStart, rawEnd),
|
|
1469
|
-
|
|
1618
|
+
A.nameEnd(decl),
|
|
1470
1619
|
rawEnd
|
|
1471
1620
|
);
|
|
1472
1621
|
}
|
|
1473
1622
|
|
|
1474
|
-
return skipWhiteLine(source,
|
|
1623
|
+
return skipWhiteLine(source, A.blockEnd(rule));
|
|
1475
1624
|
};
|
|
1476
1625
|
|
|
1477
1626
|
/**
|
|
@@ -1506,20 +1655,20 @@ class CssParser extends Parser {
|
|
|
1506
1655
|
*/
|
|
1507
1656
|
const processLocalOrGlobalFunction = (fn, type) => {
|
|
1508
1657
|
// Replace `local(` / `global(` (and a leading `:` for the `:local(`/`:global(` selector form) with empty.
|
|
1509
|
-
const
|
|
1510
|
-
const
|
|
1658
|
+
const fnStart = A.start(fn);
|
|
1659
|
+
const isColon = input.charCodeAt(fnStart - 1) === CC_COLON;
|
|
1660
|
+
const openEnd = A.nameEnd(fn) + 1;
|
|
1511
1661
|
module.addPresentationalDependency(
|
|
1512
|
-
new ConstDependency("", [isColon ?
|
|
1662
|
+
new ConstDependency("", [isColon ? fnStart - 1 : fnStart, openEnd])
|
|
1513
1663
|
);
|
|
1514
1664
|
|
|
1515
1665
|
if (type === 1) {
|
|
1516
|
-
for (const cv of fn
|
|
1517
|
-
if (
|
|
1518
|
-
let identifier =
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
} = cv.loc;
|
|
1666
|
+
for (const cv of A.children(fn)) {
|
|
1667
|
+
if (A.type(cv) !== NodeType.Ident) continue;
|
|
1668
|
+
let identifier = A.unescaped(cv);
|
|
1669
|
+
// Cursor reads instead of `A.loc` — no location objects allocated.
|
|
1670
|
+
const { line: sl, column: sc } = locConverter.get(A.start(cv));
|
|
1671
|
+
const { line: el, column: ec } = locConverter.get(A.end(cv));
|
|
1523
1672
|
const isDashedIdent = isDashedIdentifier(identifier);
|
|
1524
1673
|
if (isDashedIdent) identifier = identifier.slice(2);
|
|
1525
1674
|
addCssExport(
|
|
@@ -1529,7 +1678,7 @@ class CssParser extends Parser {
|
|
|
1529
1678
|
ec,
|
|
1530
1679
|
identifier,
|
|
1531
1680
|
getReexport(identifier),
|
|
1532
|
-
[
|
|
1681
|
+
[A.start(cv), A.end(cv)],
|
|
1533
1682
|
true,
|
|
1534
1683
|
CssIcssExportDependency.EXPORT_MODE.ONCE,
|
|
1535
1684
|
isDashedIdent
|
|
@@ -1541,7 +1690,7 @@ class CssParser extends Parser {
|
|
|
1541
1690
|
|
|
1542
1691
|
// Replace the closing `)`.
|
|
1543
1692
|
module.addPresentationalDependency(
|
|
1544
|
-
new ConstDependency("", [
|
|
1693
|
+
new ConstDependency("", [A.end(fn) - 1, A.end(fn)])
|
|
1545
1694
|
);
|
|
1546
1695
|
};
|
|
1547
1696
|
|
|
@@ -1553,16 +1702,15 @@ class CssParser extends Parser {
|
|
|
1553
1702
|
*/
|
|
1554
1703
|
const processLocalAtRule = (atRule, options) => {
|
|
1555
1704
|
let found = false;
|
|
1556
|
-
for (const cv of
|
|
1557
|
-
|
|
1705
|
+
for (const cv of A.prelude(atRule)) {
|
|
1706
|
+
const cvType = A.type(cv);
|
|
1707
|
+
if (cvType === NodeType.Whitespace) continue;
|
|
1558
1708
|
|
|
1559
|
-
if (
|
|
1709
|
+
if (cvType === NodeType.String) {
|
|
1560
1710
|
if (!found && options.string) {
|
|
1561
|
-
const value =
|
|
1562
|
-
const {
|
|
1563
|
-
|
|
1564
|
-
end: { line: el, column: ec }
|
|
1565
|
-
} = cv.loc;
|
|
1711
|
+
const value = A.unescaped(cv);
|
|
1712
|
+
const { line: sl, column: sc } = locConverter.get(A.start(cv));
|
|
1713
|
+
const { line: el, column: ec } = locConverter.get(A.end(cv));
|
|
1566
1714
|
addCssExport(
|
|
1567
1715
|
sl,
|
|
1568
1716
|
sc,
|
|
@@ -1570,7 +1718,7 @@ class CssParser extends Parser {
|
|
|
1570
1718
|
ec,
|
|
1571
1719
|
value,
|
|
1572
1720
|
value,
|
|
1573
|
-
[
|
|
1721
|
+
[A.start(cv), A.end(cv)],
|
|
1574
1722
|
true,
|
|
1575
1723
|
CssIcssExportDependency.EXPORT_MODE.ONCE
|
|
1576
1724
|
);
|
|
@@ -1580,19 +1728,17 @@ class CssParser extends Parser {
|
|
|
1580
1728
|
continue;
|
|
1581
1729
|
}
|
|
1582
1730
|
|
|
1583
|
-
if (
|
|
1731
|
+
if (cvType === NodeType.Ident) {
|
|
1584
1732
|
if (!found && options.identifier) {
|
|
1585
|
-
const identifier =
|
|
1733
|
+
const identifier = A.unescaped(cv);
|
|
1586
1734
|
if (
|
|
1587
1735
|
options.identifier instanceof RegExp &&
|
|
1588
1736
|
options.identifier.test(identifier)
|
|
1589
1737
|
) {
|
|
1590
1738
|
continue;
|
|
1591
1739
|
}
|
|
1592
|
-
const {
|
|
1593
|
-
|
|
1594
|
-
end: { line: el, column: ec }
|
|
1595
|
-
} = cv.loc;
|
|
1740
|
+
const { line: sl, column: sc } = locConverter.get(A.start(cv));
|
|
1741
|
+
const { line: el, column: ec } = locConverter.get(A.end(cv));
|
|
1596
1742
|
addCssExport(
|
|
1597
1743
|
sl,
|
|
1598
1744
|
sc,
|
|
@@ -1600,7 +1746,7 @@ class CssParser extends Parser {
|
|
|
1600
1746
|
ec,
|
|
1601
1747
|
identifier,
|
|
1602
1748
|
getReexport(identifier),
|
|
1603
|
-
[
|
|
1749
|
+
[A.start(cv), A.end(cv)],
|
|
1604
1750
|
true,
|
|
1605
1751
|
CssIcssExportDependency.EXPORT_MODE.ONCE,
|
|
1606
1752
|
CssIcssExportDependency.EXPORT_TYPE.NORMAL
|
|
@@ -1611,11 +1757,14 @@ class CssParser extends Parser {
|
|
|
1611
1757
|
continue;
|
|
1612
1758
|
}
|
|
1613
1759
|
|
|
1614
|
-
if (
|
|
1760
|
+
if (cvType === NodeType.Function) {
|
|
1615
1761
|
const fn = /** @type {FunctionNode} */ (cv);
|
|
1616
|
-
const fname =
|
|
1617
|
-
const type =
|
|
1618
|
-
|
|
1762
|
+
const fname = A.unescapedName(fn);
|
|
1763
|
+
const type = equalsLowerCase(fname, "local")
|
|
1764
|
+
? 1
|
|
1765
|
+
: equalsLowerCase(fname, "global")
|
|
1766
|
+
? 2
|
|
1767
|
+
: undefined;
|
|
1619
1768
|
if (!found && type) {
|
|
1620
1769
|
found = true;
|
|
1621
1770
|
if (type === 1) pure.markLocal();
|
|
@@ -1625,13 +1774,13 @@ class CssParser extends Parser {
|
|
|
1625
1774
|
if (
|
|
1626
1775
|
this.options.dashedIdents &&
|
|
1627
1776
|
isLocalMode() &&
|
|
1628
|
-
(fname
|
|
1777
|
+
(equalsLowerCase(fname, "var") || equalsLowerCase(fname, "style"))
|
|
1629
1778
|
) {
|
|
1630
1779
|
processDashedIdentInVarFunction(fn);
|
|
1631
1780
|
}
|
|
1632
1781
|
}
|
|
1633
1782
|
}
|
|
1634
|
-
return
|
|
1783
|
+
return A.end(atRule);
|
|
1635
1784
|
};
|
|
1636
1785
|
/**
|
|
1637
1786
|
* Emit the ICSS export declaring this module exports the given custom property.
|
|
@@ -1724,56 +1873,67 @@ class CssParser extends Parser {
|
|
|
1724
1873
|
/** @type {Token | undefined} */
|
|
1725
1874
|
let identNode;
|
|
1726
1875
|
let identIdx = -1;
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
if (
|
|
1876
|
+
const fv = A.children(fn);
|
|
1877
|
+
for (let i = 0; i < fv.length; i++) {
|
|
1878
|
+
const cv = fv[i];
|
|
1879
|
+
if (A.type(cv) === NodeType.Whitespace) continue;
|
|
1880
|
+
if (A.type(cv) === NodeType.Ident) {
|
|
1731
1881
|
identNode = /** @type {Token} */ (cv);
|
|
1732
1882
|
identIdx = i;
|
|
1733
1883
|
}
|
|
1734
1884
|
break;
|
|
1735
1885
|
}
|
|
1736
|
-
if (!identNode
|
|
1886
|
+
if (!identNode) return;
|
|
1737
1887
|
|
|
1738
|
-
const identStart =
|
|
1739
|
-
const identEnd =
|
|
1888
|
+
const identStart = A.start(identNode);
|
|
1889
|
+
const identEnd = A.end(identNode);
|
|
1890
|
+
// `isDashedIdentifier` on the value without slicing it: a literal `--`
|
|
1891
|
+
// prefix of length >= 3 (escaped dashes don't match, same as the string
|
|
1892
|
+
// form, since the raw bytes aren't `--`).
|
|
1893
|
+
if (
|
|
1894
|
+
identEnd - identStart < 3 ||
|
|
1895
|
+
input.charCodeAt(identStart) !== CC_HYPHEN_MINUS ||
|
|
1896
|
+
input.charCodeAt(identStart + 1) !== CC_HYPHEN_MINUS
|
|
1897
|
+
) {
|
|
1898
|
+
return;
|
|
1899
|
+
}
|
|
1740
1900
|
|
|
1741
1901
|
let j = identIdx + 1;
|
|
1742
|
-
while (j <
|
|
1902
|
+
while (j < fv.length && A.type(fv[j]) === NodeType.Whitespace) {
|
|
1743
1903
|
j++;
|
|
1744
1904
|
}
|
|
1745
1905
|
|
|
1746
1906
|
if (
|
|
1747
|
-
j >=
|
|
1748
|
-
|
|
1749
|
-
!
|
|
1907
|
+
j >= fv.length ||
|
|
1908
|
+
A.type(fv[j]) !== NodeType.Ident ||
|
|
1909
|
+
!rangeEqualsLowerCase(input, A.start(fv[j]), A.end(fv[j]), "from")
|
|
1750
1910
|
) {
|
|
1751
1911
|
emitDashedIdentExport(identStart, identEnd);
|
|
1752
1912
|
return;
|
|
1753
1913
|
}
|
|
1754
1914
|
|
|
1755
|
-
const fromIdent =
|
|
1915
|
+
const fromIdent = fv[j];
|
|
1756
1916
|
j++;
|
|
1757
|
-
while (j <
|
|
1917
|
+
while (j < fv.length && A.type(fv[j]) === NodeType.Whitespace) {
|
|
1758
1918
|
j++;
|
|
1759
1919
|
}
|
|
1760
|
-
if (j >=
|
|
1920
|
+
if (j >= fv.length) return;
|
|
1761
1921
|
|
|
1762
|
-
const
|
|
1922
|
+
const src = fv[j];
|
|
1763
1923
|
if (
|
|
1764
|
-
|
|
1765
|
-
|
|
1924
|
+
A.type(src) === NodeType.Ident &&
|
|
1925
|
+
rangeEquals(input, A.start(src), A.end(src), "global")
|
|
1766
1926
|
) {
|
|
1767
|
-
emitDashedIdentFromGlobal(identEnd,
|
|
1927
|
+
emitDashedIdentFromGlobal(identEnd, A.end(src));
|
|
1768
1928
|
return;
|
|
1769
1929
|
}
|
|
1770
|
-
if (
|
|
1930
|
+
if (A.type(src) === NodeType.String) {
|
|
1771
1931
|
emitDashedIdentImport(
|
|
1772
1932
|
identStart,
|
|
1773
1933
|
identEnd,
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
input.slice(
|
|
1934
|
+
A.start(fromIdent),
|
|
1935
|
+
A.end(src),
|
|
1936
|
+
input.slice(A.start(src) + 1, A.end(src) - 1)
|
|
1777
1937
|
);
|
|
1778
1938
|
}
|
|
1779
1939
|
};
|
|
@@ -1785,16 +1945,14 @@ class CssParser extends Parser {
|
|
|
1785
1945
|
*/
|
|
1786
1946
|
const childrenOf = (parent) => {
|
|
1787
1947
|
if (!parent) return undefined;
|
|
1788
|
-
switch (
|
|
1948
|
+
switch (A.type(parent)) {
|
|
1789
1949
|
case NodeType.Function:
|
|
1790
|
-
return /** @type {FunctionNode} */ (parent).value;
|
|
1791
1950
|
case NodeType.SimpleBlock:
|
|
1792
|
-
return /** @type {SimpleBlock} */ (parent).value;
|
|
1793
1951
|
case NodeType.Declaration:
|
|
1794
|
-
return
|
|
1952
|
+
return A.children(parent);
|
|
1795
1953
|
case NodeType.AtRule:
|
|
1796
1954
|
case NodeType.QualifiedRule:
|
|
1797
|
-
return
|
|
1955
|
+
return A.prelude(parent);
|
|
1798
1956
|
default:
|
|
1799
1957
|
return undefined;
|
|
1800
1958
|
}
|
|
@@ -1833,6 +1991,8 @@ class CssParser extends Parser {
|
|
|
1833
1991
|
let currentStructural;
|
|
1834
1992
|
// Cached on each structural enter and read per value token, so the hot Function / Ident / Url visitors don't re-derive the property / at-rule name on every visit.
|
|
1835
1993
|
let currentAtRuleName = "";
|
|
1994
|
+
// Set by `handleImportAtRule` for a malformed `@import` so its prelude still emits orphan url() deps; read by `urlActive`. Reset per at-rule enter (replaces an ad-hoc property on the node).
|
|
1995
|
+
let currentUrlRecovery = false;
|
|
1836
1996
|
/** Whether the current Declaration's property is a localizable known property. */
|
|
1837
1997
|
let currentDeclIsKnownProperty = false;
|
|
1838
1998
|
/** Whether the current `composes:` declaration owns the whole value (suppresses value rewrites). */
|
|
@@ -1853,13 +2013,16 @@ class CssParser extends Parser {
|
|
|
1853
2013
|
*/
|
|
1854
2014
|
const stripBareMarker = (colon, ident, after) => {
|
|
1855
2015
|
const afterIsWhitespace = Boolean(
|
|
1856
|
-
after &&
|
|
2016
|
+
after && A.type(after) === NodeType.Whitespace
|
|
1857
2017
|
);
|
|
2018
|
+
const identEnd = A.end(ident);
|
|
1858
2019
|
const stripEnd =
|
|
1859
|
-
afterIsWhitespace &&
|
|
2020
|
+
afterIsWhitespace && A.start(after) === identEnd
|
|
2021
|
+
? A.end(after)
|
|
2022
|
+
: identEnd;
|
|
1860
2023
|
if (isModules) {
|
|
1861
2024
|
module.addPresentationalDependency(
|
|
1862
|
-
new ConstDependency("", [
|
|
2025
|
+
new ConstDependency("", [A.start(colon), stripEnd])
|
|
1863
2026
|
);
|
|
1864
2027
|
}
|
|
1865
2028
|
return afterIsWhitespace;
|
|
@@ -1874,17 +2037,18 @@ class CssParser extends Parser {
|
|
|
1874
2037
|
*/
|
|
1875
2038
|
const stripFunctionMarker = (colon, fn, isLocal) => {
|
|
1876
2039
|
if (!isModules) return;
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
2040
|
+
const fnEnd = A.end(fn);
|
|
2041
|
+
let stripLeadEnd = fnEnd - 1;
|
|
2042
|
+
for (const arg of A.children(fn)) {
|
|
2043
|
+
if (A.type(arg) !== NodeType.Whitespace) {
|
|
2044
|
+
stripLeadEnd = A.start(arg);
|
|
1881
2045
|
break;
|
|
1882
2046
|
}
|
|
1883
2047
|
}
|
|
1884
2048
|
module.addPresentationalDependency(
|
|
1885
|
-
new ConstDependency("", [
|
|
2049
|
+
new ConstDependency("", [A.start(colon), stripLeadEnd])
|
|
1886
2050
|
);
|
|
1887
|
-
let trailStart =
|
|
2051
|
+
let trailStart = fnEnd - 1; // position of `)`
|
|
1888
2052
|
if (isLocal) {
|
|
1889
2053
|
while (
|
|
1890
2054
|
trailStart > 0 &&
|
|
@@ -1894,7 +2058,7 @@ class CssParser extends Parser {
|
|
|
1894
2058
|
}
|
|
1895
2059
|
}
|
|
1896
2060
|
module.addPresentationalDependency(
|
|
1897
|
-
new ConstDependency("", [trailStart,
|
|
2061
|
+
new ConstDependency("", [trailStart, fnEnd])
|
|
1898
2062
|
);
|
|
1899
2063
|
};
|
|
1900
2064
|
|
|
@@ -1904,37 +2068,33 @@ class CssParser extends Parser {
|
|
|
1904
2068
|
* @returns {void}
|
|
1905
2069
|
*/
|
|
1906
2070
|
const handleAttributeSelector = (block) => {
|
|
1907
|
-
const attrParts = block
|
|
2071
|
+
const attrParts = A.children(block);
|
|
1908
2072
|
let ai = 0;
|
|
1909
2073
|
while (
|
|
1910
2074
|
ai < attrParts.length &&
|
|
1911
|
-
attrParts[ai]
|
|
2075
|
+
A.type(attrParts[ai]) === NodeType.Whitespace
|
|
1912
2076
|
) {
|
|
1913
2077
|
ai++;
|
|
1914
2078
|
}
|
|
1915
2079
|
const attrNameNode = attrParts[ai];
|
|
1916
|
-
if (!attrNameNode ||
|
|
1917
|
-
const attrName =
|
|
2080
|
+
if (!attrNameNode || A.type(attrNameNode) !== NodeType.Ident) return;
|
|
2081
|
+
const attrName = A.unescaped(attrNameNode);
|
|
1918
2082
|
if (!equalsLowerCase(attrName, "class")) return;
|
|
1919
2083
|
ai++;
|
|
1920
2084
|
while (
|
|
1921
2085
|
ai < attrParts.length &&
|
|
1922
|
-
attrParts[ai]
|
|
2086
|
+
A.type(attrParts[ai]) === NodeType.Whitespace
|
|
1923
2087
|
) {
|
|
1924
2088
|
ai++;
|
|
1925
2089
|
}
|
|
1926
2090
|
// `=` or `~=` (two `Delim` tokens for the latter).
|
|
1927
2091
|
const op1 = attrParts[ai];
|
|
1928
|
-
if (!op1 ||
|
|
1929
|
-
const op1v =
|
|
2092
|
+
if (!op1 || A.type(op1) !== NodeType.Delim) return;
|
|
2093
|
+
const op1v = A.value(op1);
|
|
1930
2094
|
if (op1v === "~") {
|
|
1931
2095
|
ai++;
|
|
1932
2096
|
const op2 = attrParts[ai];
|
|
1933
|
-
if (
|
|
1934
|
-
!op2 ||
|
|
1935
|
-
op2.type !== NodeType.Delim ||
|
|
1936
|
-
/** @type {Token} */ (op2).value !== "="
|
|
1937
|
-
) {
|
|
2097
|
+
if (!op2 || A.type(op2) !== NodeType.Delim || A.value(op2) !== "=") {
|
|
1938
2098
|
return;
|
|
1939
2099
|
}
|
|
1940
2100
|
} else if (op1v !== "=") {
|
|
@@ -1943,7 +2103,7 @@ class CssParser extends Parser {
|
|
|
1943
2103
|
ai++;
|
|
1944
2104
|
while (
|
|
1945
2105
|
ai < attrParts.length &&
|
|
1946
|
-
attrParts[ai]
|
|
2106
|
+
A.type(attrParts[ai]) === NodeType.Whitespace
|
|
1947
2107
|
) {
|
|
1948
2108
|
ai++;
|
|
1949
2109
|
}
|
|
@@ -1953,12 +2113,12 @@ class CssParser extends Parser {
|
|
|
1953
2113
|
let classNameStart;
|
|
1954
2114
|
/** @type {number} */
|
|
1955
2115
|
let classNameEnd;
|
|
1956
|
-
if (
|
|
1957
|
-
classNameStart =
|
|
1958
|
-
classNameEnd =
|
|
1959
|
-
} else if (
|
|
1960
|
-
classNameStart =
|
|
1961
|
-
classNameEnd =
|
|
2116
|
+
if (A.type(attrValueNode) === NodeType.String) {
|
|
2117
|
+
classNameStart = A.start(attrValueNode) + 1;
|
|
2118
|
+
classNameEnd = A.end(attrValueNode) - 1;
|
|
2119
|
+
} else if (A.type(attrValueNode) === NodeType.Ident) {
|
|
2120
|
+
classNameStart = A.start(attrValueNode);
|
|
2121
|
+
classNameEnd = A.end(attrValueNode);
|
|
1962
2122
|
} else {
|
|
1963
2123
|
return;
|
|
1964
2124
|
}
|
|
@@ -1998,7 +2158,7 @@ class CssParser extends Parser {
|
|
|
1998
2158
|
}
|
|
1999
2159
|
for (let i = 0; i < values.length; i++) {
|
|
2000
2160
|
const v = values[i];
|
|
2001
|
-
switch (
|
|
2161
|
+
switch (A.type(v)) {
|
|
2002
2162
|
case NodeType.Whitespace:
|
|
2003
2163
|
break;
|
|
2004
2164
|
case NodeType.Comma:
|
|
@@ -2013,8 +2173,9 @@ class CssParser extends Parser {
|
|
|
2013
2173
|
// Look ahead for `:local` / `:global` markers; other pseudos fall through.
|
|
2014
2174
|
const next = values[i + 1];
|
|
2015
2175
|
if (!next) break;
|
|
2016
|
-
|
|
2017
|
-
|
|
2176
|
+
const nextType = A.type(next);
|
|
2177
|
+
if (nextType === NodeType.Ident) {
|
|
2178
|
+
const raw = A.value(next);
|
|
2018
2179
|
const isLocal = equalsLowerCase(raw, "local");
|
|
2019
2180
|
if (isLocal || equalsLowerCase(raw, "global")) {
|
|
2020
2181
|
const id = isLocal ? "local" : "global";
|
|
@@ -2029,12 +2190,12 @@ class CssParser extends Parser {
|
|
|
2029
2190
|
this._emitWarning(
|
|
2030
2191
|
state,
|
|
2031
2192
|
`Missing whitespace after ':${id}' in '${source.slice(
|
|
2032
|
-
|
|
2033
|
-
findLeftCurly(source,
|
|
2193
|
+
A.start(v),
|
|
2194
|
+
findLeftCurly(source, A.end(next)) + 1
|
|
2034
2195
|
)}'`,
|
|
2035
2196
|
locConverter,
|
|
2036
|
-
|
|
2037
|
-
|
|
2197
|
+
A.start(v),
|
|
2198
|
+
A.end(next)
|
|
2038
2199
|
);
|
|
2039
2200
|
}
|
|
2040
2201
|
segmentMode = id;
|
|
@@ -2042,14 +2203,18 @@ class CssParser extends Parser {
|
|
|
2042
2203
|
// Skip past the colon + ident.
|
|
2043
2204
|
i += 1;
|
|
2044
2205
|
}
|
|
2045
|
-
} else if (
|
|
2206
|
+
} else if (nextType === NodeType.Function) {
|
|
2046
2207
|
const fn = /** @type {FunctionNode} */ (next);
|
|
2047
|
-
const rawName =
|
|
2208
|
+
const rawName = A.unescapedName(fn);
|
|
2048
2209
|
const isLocal = equalsLowerCase(rawName, "local");
|
|
2049
2210
|
if (isLocal || equalsLowerCase(rawName, "global")) {
|
|
2050
2211
|
// `:local(…)` / `:global(…)`: scope mode to the args and strip the `:name(` … `)` wrapper.
|
|
2051
2212
|
stripFunctionMarker(v, fn, isLocal);
|
|
2052
|
-
walkSelectorList(
|
|
2213
|
+
walkSelectorList(
|
|
2214
|
+
A.children(fn),
|
|
2215
|
+
isLocal ? "local" : "global",
|
|
2216
|
+
false
|
|
2217
|
+
);
|
|
2053
2218
|
// Skip past the colon + function.
|
|
2054
2219
|
i += 1;
|
|
2055
2220
|
}
|
|
@@ -2058,26 +2223,17 @@ class CssParser extends Parser {
|
|
|
2058
2223
|
}
|
|
2059
2224
|
case NodeType.Function:
|
|
2060
2225
|
// Any other function (`:not(…)`, `:is(…)`, …): recurse with the segment mode preserved (only `:local(…)` / `:global(…)`, handled above, switch mode).
|
|
2061
|
-
walkSelectorList(
|
|
2062
|
-
/** @type {FunctionNode} */ (v).value,
|
|
2063
|
-
segmentMode,
|
|
2064
|
-
false
|
|
2065
|
-
);
|
|
2226
|
+
walkSelectorList(A.children(v), segmentMode, false);
|
|
2066
2227
|
break;
|
|
2067
2228
|
case NodeType.Hash: {
|
|
2068
|
-
if (
|
|
2069
|
-
/** @type {HashToken} */ (v).typeFlag !== "id" ||
|
|
2070
|
-
segmentMode !== "local"
|
|
2071
|
-
) {
|
|
2229
|
+
if (A.typeFlag(v) !== "id" || segmentMode !== "local") {
|
|
2072
2230
|
break;
|
|
2073
2231
|
}
|
|
2074
2232
|
// ID selectors emit the ICSS export but aren't a `composes:` anchor.
|
|
2075
|
-
const idValueStart =
|
|
2076
|
-
const idName =
|
|
2077
|
-
const {
|
|
2078
|
-
|
|
2079
|
-
end: { line: idEl, column: idEc }
|
|
2080
|
-
} = v.loc;
|
|
2233
|
+
const idValueStart = A.start(v) + 1;
|
|
2234
|
+
const idName = A.unescaped(v);
|
|
2235
|
+
const { line: idSl, column: idSc } = locConverter.get(A.start(v));
|
|
2236
|
+
const { line: idEl, column: idEc } = locConverter.get(A.end(v));
|
|
2081
2237
|
addCssExport(
|
|
2082
2238
|
idSl,
|
|
2083
2239
|
idSc,
|
|
@@ -2085,7 +2241,7 @@ class CssParser extends Parser {
|
|
|
2085
2241
|
idEc,
|
|
2086
2242
|
idName,
|
|
2087
2243
|
getReexport(idName),
|
|
2088
|
-
[idValueStart,
|
|
2244
|
+
[idValueStart, A.end(v)],
|
|
2089
2245
|
true,
|
|
2090
2246
|
CssIcssExportDependency.EXPORT_MODE.ONCE
|
|
2091
2247
|
);
|
|
@@ -2094,17 +2250,18 @@ class CssParser extends Parser {
|
|
|
2094
2250
|
}
|
|
2095
2251
|
case NodeType.SimpleBlock: {
|
|
2096
2252
|
const block = /** @type {SimpleBlock} */ (v);
|
|
2097
|
-
|
|
2253
|
+
const bt = A.blockToken(block);
|
|
2254
|
+
if (bt === "[") {
|
|
2098
2255
|
// Attribute selectors `[class="foo"]` localize only in local mode.
|
|
2099
2256
|
if (segmentMode === "local") handleAttributeSelector(block);
|
|
2100
|
-
} else if (
|
|
2257
|
+
} else if (bt === "(") {
|
|
2101
2258
|
// `@scope (.foo)` and other parenthesised selector wrappers — recurse into the `(…)` block.
|
|
2102
|
-
walkSelectorList(block
|
|
2259
|
+
walkSelectorList(A.children(block), segmentMode, false);
|
|
2103
2260
|
}
|
|
2104
2261
|
break;
|
|
2105
2262
|
}
|
|
2106
2263
|
case NodeType.Delim: {
|
|
2107
|
-
const delim =
|
|
2264
|
+
const delim = A.value(v);
|
|
2108
2265
|
if (delim === "&") {
|
|
2109
2266
|
// Pure-mode: a nesting `&` inherits a pure ancestor's purity.
|
|
2110
2267
|
if (topLevel && pure.ancestorHadLocal()) pure.markLocal();
|
|
@@ -2112,14 +2269,13 @@ class CssParser extends Parser {
|
|
|
2112
2269
|
}
|
|
2113
2270
|
if (delim !== ".") break;
|
|
2114
2271
|
const next = values[i + 1];
|
|
2115
|
-
if (!next ||
|
|
2272
|
+
if (!next || A.type(next) !== NodeType.Ident) break;
|
|
2116
2273
|
if (segmentMode === "local") {
|
|
2117
2274
|
// `.<ident>` in local mode is a class selector (dep covers the ident bytes only).
|
|
2118
|
-
const name =
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
} = next.loc;
|
|
2275
|
+
const name = A.unescaped(next);
|
|
2276
|
+
// Cursor reads instead of `A.loc` — this is the hottest export site.
|
|
2277
|
+
const { line: sl, column: sc } = locConverter.get(A.start(next));
|
|
2278
|
+
const { line: el, column: ec } = locConverter.get(A.end(next));
|
|
2123
2279
|
addCssExport(
|
|
2124
2280
|
sl,
|
|
2125
2281
|
sc,
|
|
@@ -2127,18 +2283,18 @@ class CssParser extends Parser {
|
|
|
2127
2283
|
ec,
|
|
2128
2284
|
name,
|
|
2129
2285
|
getReexport(name),
|
|
2130
|
-
[
|
|
2286
|
+
[A.start(next), A.end(next)],
|
|
2131
2287
|
true,
|
|
2132
2288
|
CssIcssExportDependency.EXPORT_MODE.ONCE
|
|
2133
2289
|
);
|
|
2134
2290
|
currentRule.hasLocalAnchor = true;
|
|
2135
2291
|
currentRule.localIdentifiers.push(name);
|
|
2136
2292
|
pure.markLocal();
|
|
2137
|
-
} else {
|
|
2293
|
+
} else if (icssDefinitions.size !== 0) {
|
|
2138
2294
|
// `.<ident>` in global mode: not localized, but the ident may be `@value`-defined and need ICSS rewrite.
|
|
2139
|
-
const ident =
|
|
2295
|
+
const ident = A.value(next);
|
|
2140
2296
|
if (!isDashedIdentifier(ident) && icssDefinitions.has(ident)) {
|
|
2141
|
-
emitICSSSymbol(ident,
|
|
2297
|
+
emitICSSSymbol(ident, A.start(next), A.end(next));
|
|
2142
2298
|
}
|
|
2143
2299
|
}
|
|
2144
2300
|
// Skip the consumed ident.
|
|
@@ -2146,10 +2302,11 @@ class CssParser extends Parser {
|
|
|
2146
2302
|
break;
|
|
2147
2303
|
}
|
|
2148
2304
|
case NodeType.Ident: {
|
|
2149
|
-
// ICSS rewrite for a bare `@value`-defined ident used as a type-style selector.
|
|
2150
|
-
|
|
2305
|
+
// ICSS rewrite for a bare `@value`-defined ident used as a type-style selector; only worth the slice when definitions exist.
|
|
2306
|
+
if (icssDefinitions.size === 0) break;
|
|
2307
|
+
const ident = A.value(v);
|
|
2151
2308
|
if (!isDashedIdentifier(ident) && icssDefinitions.has(ident)) {
|
|
2152
|
-
emitICSSSymbol(ident,
|
|
2309
|
+
emitICSSSymbol(ident, A.start(v), A.end(v));
|
|
2153
2310
|
}
|
|
2154
2311
|
break;
|
|
2155
2312
|
}
|
|
@@ -2172,11 +2329,9 @@ class CssParser extends Parser {
|
|
|
2172
2329
|
*/
|
|
2173
2330
|
const urlActive = () => {
|
|
2174
2331
|
if (!this.options.url || !currentStructural) return false;
|
|
2175
|
-
if (
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
);
|
|
2179
|
-
return !equalsLowerCase(at.name, "import") || Boolean(at.urlRecovery);
|
|
2332
|
+
if (A.type(currentStructural) === NodeType.AtRule) {
|
|
2333
|
+
// `currentAtRuleName` is cached on at-rule enter — no per-value slice.
|
|
2334
|
+
return currentAtRuleName !== "@import" || currentUrlRecovery;
|
|
2180
2335
|
}
|
|
2181
2336
|
return true;
|
|
2182
2337
|
};
|
|
@@ -2204,10 +2359,11 @@ class CssParser extends Parser {
|
|
|
2204
2359
|
*/
|
|
2205
2360
|
const localGlobalActive = () => {
|
|
2206
2361
|
if (!isModules || !currentStructural) return false;
|
|
2207
|
-
|
|
2362
|
+
const t = A.type(currentStructural);
|
|
2363
|
+
if (t === NodeType.AtRule) {
|
|
2208
2364
|
return !isLocalHandledAtRule(currentAtRuleName);
|
|
2209
2365
|
}
|
|
2210
|
-
if (
|
|
2366
|
+
if (t === NodeType.Declaration) {
|
|
2211
2367
|
return !currentDeclComposesSkip;
|
|
2212
2368
|
}
|
|
2213
2369
|
return false;
|
|
@@ -2219,12 +2375,13 @@ class CssParser extends Parser {
|
|
|
2219
2375
|
*/
|
|
2220
2376
|
const icssActive = () => {
|
|
2221
2377
|
if (!isModules || !currentStructural) return false;
|
|
2222
|
-
|
|
2378
|
+
const t = A.type(currentStructural);
|
|
2379
|
+
if (t === NodeType.AtRule) {
|
|
2223
2380
|
return (
|
|
2224
2381
|
currentAtRuleName !== "@value" && currentAtRuleName !== "@import"
|
|
2225
2382
|
);
|
|
2226
2383
|
}
|
|
2227
|
-
if (
|
|
2384
|
+
if (t === NodeType.Declaration) {
|
|
2228
2385
|
return !currentDeclComposesSkip && !currentDeclIsKnownProperty;
|
|
2229
2386
|
}
|
|
2230
2387
|
return false;
|
|
@@ -2237,8 +2394,7 @@ class CssParser extends Parser {
|
|
|
2237
2394
|
* @returns {void}
|
|
2238
2395
|
*/
|
|
2239
2396
|
const finishTopLevelRule = (node, blockBearing) => {
|
|
2240
|
-
|
|
2241
|
-
if (!blockBearing || at.declarations || at.childRules) {
|
|
2397
|
+
if (!blockBearing || A.declarations(node) || A.childRules(node)) {
|
|
2242
2398
|
allowImport = false;
|
|
2243
2399
|
}
|
|
2244
2400
|
pure.markSeenTopLevelRule();
|
|
@@ -2383,8 +2539,8 @@ class CssParser extends Parser {
|
|
|
2383
2539
|
'", "'
|
|
2384
2540
|
)}"`,
|
|
2385
2541
|
locConverter,
|
|
2386
|
-
|
|
2387
|
-
|
|
2542
|
+
A.start(decl),
|
|
2543
|
+
A.end(decl)
|
|
2388
2544
|
);
|
|
2389
2545
|
return;
|
|
2390
2546
|
}
|
|
@@ -2395,8 +2551,8 @@ class CssParser extends Parser {
|
|
|
2395
2551
|
const groups = [];
|
|
2396
2552
|
/** @type {AstNode[]} */
|
|
2397
2553
|
let currentGroup = [];
|
|
2398
|
-
for (const cv of decl
|
|
2399
|
-
if (
|
|
2554
|
+
for (const cv of A.children(decl)) {
|
|
2555
|
+
if (A.type(cv) === NodeType.Comma) {
|
|
2400
2556
|
groups.push(currentGroup);
|
|
2401
2557
|
currentGroup = [];
|
|
2402
2558
|
} else {
|
|
@@ -2419,20 +2575,20 @@ class CssParser extends Parser {
|
|
|
2419
2575
|
|
|
2420
2576
|
for (let i = 0; i < group.length; i++) {
|
|
2421
2577
|
const cv = group[i];
|
|
2422
|
-
if (
|
|
2578
|
+
if (A.type(cv) === NodeType.Whitespace) continue;
|
|
2423
2579
|
|
|
2424
2580
|
if (phase === "expecting-source") {
|
|
2425
|
-
if (
|
|
2581
|
+
if (A.type(cv) === NodeType.String) {
|
|
2426
2582
|
fromSource = {
|
|
2427
2583
|
kind: "string",
|
|
2428
|
-
path: source.slice(
|
|
2584
|
+
path: source.slice(A.start(cv) + 1, A.end(cv) - 1)
|
|
2429
2585
|
};
|
|
2430
2586
|
phase = "done";
|
|
2431
2587
|
continue;
|
|
2432
2588
|
}
|
|
2433
2589
|
if (
|
|
2434
|
-
|
|
2435
|
-
equalsLowerCase(
|
|
2590
|
+
A.type(cv) === NodeType.Ident &&
|
|
2591
|
+
equalsLowerCase(A.value(cv), "global")
|
|
2436
2592
|
) {
|
|
2437
2593
|
fromSource = { kind: "global" };
|
|
2438
2594
|
phase = "done";
|
|
@@ -2448,8 +2604,8 @@ class CssParser extends Parser {
|
|
|
2448
2604
|
continue;
|
|
2449
2605
|
}
|
|
2450
2606
|
|
|
2451
|
-
if (
|
|
2452
|
-
const identValue =
|
|
2607
|
+
if (A.type(cv) === NodeType.Ident) {
|
|
2608
|
+
const identValue = A.value(cv);
|
|
2453
2609
|
if (
|
|
2454
2610
|
equalsLowerCase(identValue, "from") &&
|
|
2455
2611
|
classNames.length > 0 &&
|
|
@@ -2459,21 +2615,21 @@ class CssParser extends Parser {
|
|
|
2459
2615
|
continue;
|
|
2460
2616
|
}
|
|
2461
2617
|
classNames.push({
|
|
2462
|
-
start:
|
|
2463
|
-
end:
|
|
2618
|
+
start: A.start(cv),
|
|
2619
|
+
end: A.end(cv),
|
|
2464
2620
|
isGlobal: false
|
|
2465
2621
|
});
|
|
2466
2622
|
continue;
|
|
2467
2623
|
}
|
|
2468
2624
|
|
|
2469
|
-
if (
|
|
2625
|
+
if (A.type(cv) === NodeType.Function) {
|
|
2470
2626
|
const fn = /** @type {FunctionNode} */ (cv);
|
|
2471
|
-
const isGlobal = equalsLowerCase(
|
|
2472
|
-
for (const inner of fn
|
|
2473
|
-
if (
|
|
2627
|
+
const isGlobal = equalsLowerCase(A.unescapedName(fn), "global");
|
|
2628
|
+
for (const inner of A.children(fn)) {
|
|
2629
|
+
if (A.type(inner) === NodeType.Ident) {
|
|
2474
2630
|
classNames.push({
|
|
2475
|
-
start:
|
|
2476
|
-
end:
|
|
2631
|
+
start: A.start(inner),
|
|
2632
|
+
end: A.end(inner),
|
|
2477
2633
|
isGlobal
|
|
2478
2634
|
});
|
|
2479
2635
|
break;
|
|
@@ -2500,8 +2656,8 @@ class CssParser extends Parser {
|
|
|
2500
2656
|
state,
|
|
2501
2657
|
errorMessage,
|
|
2502
2658
|
locConverter,
|
|
2503
|
-
|
|
2504
|
-
|
|
2659
|
+
A.start(errorToken),
|
|
2660
|
+
A.end(errorToken)
|
|
2505
2661
|
);
|
|
2506
2662
|
return;
|
|
2507
2663
|
}
|
|
@@ -2512,81 +2668,87 @@ class CssParser extends Parser {
|
|
|
2512
2668
|
}
|
|
2513
2669
|
|
|
2514
2670
|
// Strip the whole `composes: …;` (property name included) plus trailing same-line whitespace. The `;` and that whitespace aren't AST nodes (a block's contents drop them), so scan the source here.
|
|
2515
|
-
let resumeAt =
|
|
2516
|
-
if (source.charCodeAt(
|
|
2517
|
-
resumeAt =
|
|
2671
|
+
let resumeAt = A.end(decl);
|
|
2672
|
+
if (source.charCodeAt(A.end(decl)) === CC_SEMICOLON) {
|
|
2673
|
+
resumeAt = A.end(decl) + 1;
|
|
2518
2674
|
while (isCssWhitespace(source.charCodeAt(resumeAt))) resumeAt++;
|
|
2519
2675
|
}
|
|
2520
2676
|
module.addPresentationalDependency(
|
|
2521
|
-
new ConstDependency("", [
|
|
2677
|
+
new ConstDependency("", [A.nameStart(decl), resumeAt])
|
|
2522
2678
|
);
|
|
2523
2679
|
};
|
|
2524
2680
|
|
|
2525
2681
|
/**
|
|
2526
2682
|
* Emit url() deps for a `url(...)` / `src(...)` / `image-set(...)` value function.
|
|
2527
2683
|
* @param {FunctionNode} fn the function node
|
|
2528
|
-
* @param {string} fname the function name
|
|
2684
|
+
* @param {string} fname the unescaped function name (any case)
|
|
2529
2685
|
*/
|
|
2530
2686
|
const emitUrlFunction = (fn, fname) => {
|
|
2531
|
-
if (fname
|
|
2687
|
+
if (equalsLowerCase(fname, "url") || equalsLowerCase(fname, "src")) {
|
|
2532
2688
|
// Quoted `url("…")` / `src("…")`: first non-whitespace value must be the string token.
|
|
2533
|
-
const first = fn
|
|
2534
|
-
if (!first ||
|
|
2689
|
+
const first = A.children(fn)[nextNonWhitespace(A.children(fn), 0)];
|
|
2690
|
+
if (!first || A.type(first) !== NodeType.String) return;
|
|
2535
2691
|
const string = /** @type {Token} */ (first);
|
|
2536
2692
|
if (
|
|
2537
2693
|
webpackIgnored(
|
|
2538
|
-
[lastTokenEndForComments,
|
|
2539
|
-
|
|
2540
|
-
|
|
2694
|
+
[lastTokenEndForComments, A.start(fn)],
|
|
2695
|
+
A.start(string),
|
|
2696
|
+
A.end(string)
|
|
2541
2697
|
)
|
|
2542
2698
|
) {
|
|
2543
2699
|
return;
|
|
2544
2700
|
}
|
|
2545
2701
|
const value = normalizeUrl(
|
|
2546
|
-
input.slice(
|
|
2702
|
+
input.slice(A.start(string) + 1, A.end(string) - 1),
|
|
2547
2703
|
true
|
|
2548
2704
|
);
|
|
2549
2705
|
// Ignore `url()`, `url('')` and `url("")`, they are valid by spec
|
|
2550
2706
|
if (value.length === 0) return;
|
|
2551
2707
|
const dep = new CssUrlDependency(
|
|
2552
2708
|
value,
|
|
2553
|
-
[
|
|
2709
|
+
[A.start(string), A.end(string)],
|
|
2554
2710
|
"string"
|
|
2555
2711
|
);
|
|
2556
|
-
setDepLoc(dep,
|
|
2712
|
+
setDepLoc(dep, A.start(string), A.end(string));
|
|
2557
2713
|
module.addDependency(dep);
|
|
2558
2714
|
module.addCodeGenerationDependency(dep);
|
|
2559
2715
|
} else if (IMAGE_SET_FUNCTION.test(fname)) {
|
|
2560
2716
|
// `image-set(…)`: each comma segment's first string is the URL; advance the magic-comment fence per string.
|
|
2561
|
-
lastTokenEndForComments =
|
|
2562
|
-
let prevStringEnd =
|
|
2717
|
+
lastTokenEndForComments = A.nameEnd(fn) + 1;
|
|
2718
|
+
let prevStringEnd = A.start(fn);
|
|
2563
2719
|
let firstInSegment = true;
|
|
2564
|
-
for (const cv of fn
|
|
2565
|
-
if (
|
|
2720
|
+
for (const cv of A.children(fn)) {
|
|
2721
|
+
if (A.type(cv) === NodeType.Comma) {
|
|
2566
2722
|
firstInSegment = true;
|
|
2567
2723
|
continue;
|
|
2568
2724
|
}
|
|
2569
|
-
if (
|
|
2725
|
+
if (A.type(cv) === NodeType.Whitespace) continue;
|
|
2570
2726
|
const wasFirst = firstInSegment;
|
|
2571
2727
|
firstInSegment = false;
|
|
2572
|
-
if (!wasFirst ||
|
|
2728
|
+
if (!wasFirst || A.type(cv) !== NodeType.String) continue;
|
|
2573
2729
|
const string = /** @type {Token} */ (cv);
|
|
2574
2730
|
const start = prevStringEnd;
|
|
2575
|
-
prevStringEnd =
|
|
2731
|
+
prevStringEnd = A.end(string);
|
|
2576
2732
|
const value = normalizeUrl(
|
|
2577
|
-
input.slice(
|
|
2733
|
+
input.slice(A.start(string) + 1, A.end(string) - 1),
|
|
2578
2734
|
true
|
|
2579
2735
|
);
|
|
2580
2736
|
if (value.length === 0) continue;
|
|
2581
|
-
if (
|
|
2737
|
+
if (
|
|
2738
|
+
webpackIgnored(
|
|
2739
|
+
[start, A.end(string)],
|
|
2740
|
+
A.start(string),
|
|
2741
|
+
A.end(string)
|
|
2742
|
+
)
|
|
2743
|
+
) {
|
|
2582
2744
|
continue;
|
|
2583
2745
|
}
|
|
2584
2746
|
const dep = new CssUrlDependency(
|
|
2585
2747
|
value,
|
|
2586
|
-
[
|
|
2748
|
+
[A.start(string), A.end(string)],
|
|
2587
2749
|
"url"
|
|
2588
2750
|
);
|
|
2589
|
-
setDepLoc(dep,
|
|
2751
|
+
setDepLoc(dep, A.start(string), A.end(string));
|
|
2590
2752
|
module.addDependency(dep);
|
|
2591
2753
|
module.addCodeGenerationDependency(dep);
|
|
2592
2754
|
}
|
|
@@ -2605,24 +2767,24 @@ class CssParser extends Parser {
|
|
|
2605
2767
|
state,
|
|
2606
2768
|
"Any '@import' rules must precede all other rules",
|
|
2607
2769
|
locConverter,
|
|
2608
|
-
|
|
2609
|
-
|
|
2770
|
+
A.start(at),
|
|
2771
|
+
A.nameEnd(at)
|
|
2610
2772
|
);
|
|
2611
2773
|
return;
|
|
2612
2774
|
}
|
|
2613
|
-
const importStart =
|
|
2614
|
-
const importNameEnd =
|
|
2775
|
+
const importStart = A.start(at);
|
|
2776
|
+
const importNameEnd = A.nameEnd(at);
|
|
2615
2777
|
// We only accept `;`-terminated @import; block / EOF / `}` ends are silent bails.
|
|
2616
|
-
if (source.charCodeAt(
|
|
2778
|
+
if (source.charCodeAt(A.end(at)) !== CC_SEMICOLON) return;
|
|
2617
2779
|
|
|
2618
2780
|
// Walk the prelude in spec order (URL → layer? → supports? → media query); anything else joins the media query.
|
|
2619
2781
|
const { urlNode, layerNode, supportsNode } = parseImportPrelude(
|
|
2620
|
-
|
|
2782
|
+
A.prelude(at)
|
|
2621
2783
|
);
|
|
2622
2784
|
|
|
2623
|
-
const semi =
|
|
2785
|
+
const semi = A.end(at) + 1; // position past `;`
|
|
2624
2786
|
|
|
2625
|
-
if (!urlNode || (
|
|
2787
|
+
if (!urlNode || (A.type(urlNode) === NodeType.Ident && !isModules)) {
|
|
2626
2788
|
this._emitWarning(
|
|
2627
2789
|
state,
|
|
2628
2790
|
`Expected URL in '${input.slice(importStart, semi)}'`,
|
|
@@ -2630,17 +2792,16 @@ class CssParser extends Parser {
|
|
|
2630
2792
|
importStart,
|
|
2631
2793
|
semi
|
|
2632
2794
|
);
|
|
2633
|
-
// A malformed `@import` still emits orphan url() deps from its prelude — flag
|
|
2634
|
-
|
|
2635
|
-
true;
|
|
2795
|
+
// A malformed `@import` still emits orphan url() deps from its prelude — flag it so the value visitors enable url().
|
|
2796
|
+
currentUrlRecovery = true;
|
|
2636
2797
|
return;
|
|
2637
2798
|
}
|
|
2638
2799
|
|
|
2639
2800
|
/** @type {string} */
|
|
2640
2801
|
let url;
|
|
2641
|
-
if (
|
|
2802
|
+
if (A.type(urlNode) === NodeType.Ident) {
|
|
2642
2803
|
// URL given as identifier — resolve via CSS Modules `@value`.
|
|
2643
|
-
const identName =
|
|
2804
|
+
const identName = A.value(urlNode);
|
|
2644
2805
|
const def = icssDefinitions.get(identName);
|
|
2645
2806
|
if (!def) {
|
|
2646
2807
|
this._emitWarning(
|
|
@@ -2676,21 +2837,24 @@ class CssParser extends Parser {
|
|
|
2676
2837
|
(raw.startsWith("'") && raw.endsWith("'"))
|
|
2677
2838
|
? normalizeUrl(raw.slice(1, -1), true)
|
|
2678
2839
|
: normalizeUrl(raw, false);
|
|
2679
|
-
} else if (
|
|
2840
|
+
} else if (A.type(urlNode) === NodeType.Url) {
|
|
2680
2841
|
const ut = /** @type {UrlToken} */ (urlNode);
|
|
2681
|
-
url = normalizeUrl(input.slice(ut.contentStart, ut.contentEnd), false);
|
|
2682
|
-
} else if (urlNode.type === NodeType.String) {
|
|
2683
2842
|
url = normalizeUrl(
|
|
2684
|
-
input.slice(
|
|
2843
|
+
input.slice(A.contentStart(ut), A.contentEnd(ut)),
|
|
2844
|
+
false
|
|
2845
|
+
);
|
|
2846
|
+
} else if (A.type(urlNode) === NodeType.String) {
|
|
2847
|
+
url = normalizeUrl(
|
|
2848
|
+
input.slice(A.start(urlNode) + 1, A.end(urlNode) - 1),
|
|
2685
2849
|
true
|
|
2686
2850
|
);
|
|
2687
2851
|
} else {
|
|
2688
2852
|
// url(...) function — first non-whitespace child is the string.
|
|
2689
2853
|
/** @type {Token | undefined} */
|
|
2690
2854
|
let string;
|
|
2691
|
-
for (const inner of
|
|
2692
|
-
if (
|
|
2693
|
-
if (
|
|
2855
|
+
for (const inner of A.children(urlNode)) {
|
|
2856
|
+
if (A.type(inner) === NodeType.Whitespace) continue;
|
|
2857
|
+
if (A.type(inner) === NodeType.String) {
|
|
2694
2858
|
string = /** @type {Token} */ (inner);
|
|
2695
2859
|
}
|
|
2696
2860
|
break;
|
|
@@ -2705,11 +2869,16 @@ class CssParser extends Parser {
|
|
|
2705
2869
|
);
|
|
2706
2870
|
return;
|
|
2707
2871
|
}
|
|
2708
|
-
url = normalizeUrl(
|
|
2872
|
+
url = normalizeUrl(
|
|
2873
|
+
input.slice(A.start(string) + 1, A.end(string) - 1),
|
|
2874
|
+
true
|
|
2875
|
+
);
|
|
2709
2876
|
}
|
|
2710
2877
|
|
|
2711
2878
|
const newline = skipWhiteLine(input, semi);
|
|
2712
|
-
if (
|
|
2879
|
+
if (
|
|
2880
|
+
webpackIgnored([importNameEnd, A.end(urlNode)], importStart, newline)
|
|
2881
|
+
) {
|
|
2713
2882
|
return;
|
|
2714
2883
|
}
|
|
2715
2884
|
if (url.length === 0) {
|
|
@@ -2723,10 +2892,10 @@ class CssParser extends Parser {
|
|
|
2723
2892
|
/** @type {undefined | string} */
|
|
2724
2893
|
let layer;
|
|
2725
2894
|
if (layerNode) {
|
|
2726
|
-
if (
|
|
2895
|
+
if (A.type(layerNode) === NodeType.Function) {
|
|
2727
2896
|
// `layer(<ident>)` — extract content between `(` and `)`.
|
|
2728
2897
|
const fn = /** @type {FunctionNode} */ (layerNode);
|
|
2729
|
-
layer = input.slice(
|
|
2898
|
+
layer = input.slice(A.nameEnd(fn) + 1, A.end(fn) - 1).trim();
|
|
2730
2899
|
} else {
|
|
2731
2900
|
// Bare `layer` ident — anonymous layer.
|
|
2732
2901
|
layer = "";
|
|
@@ -2737,21 +2906,23 @@ class CssParser extends Parser {
|
|
|
2737
2906
|
let supports;
|
|
2738
2907
|
if (supportsNode) {
|
|
2739
2908
|
supports = input
|
|
2740
|
-
.slice(
|
|
2909
|
+
.slice(A.nameEnd(supportsNode) + 1, A.end(supportsNode) - 1)
|
|
2741
2910
|
.trim();
|
|
2742
2911
|
}
|
|
2743
2912
|
|
|
2744
2913
|
// Media query = whatever sits between the last url/layer/supports part and the closing `;`, trimmed. Start at the next non-whitespace prelude node (skips the gap, comments included).
|
|
2745
2914
|
const lastPrefixPart = supportsNode || layerNode || urlNode;
|
|
2746
2915
|
const afterIdx =
|
|
2747
|
-
/** @type {AstNode[]} */ (
|
|
2748
|
-
const nextIdx = nextNonWhitespace(
|
|
2916
|
+
/** @type {AstNode[]} */ (A.prelude(at)).indexOf(lastPrefixPart) + 1;
|
|
2917
|
+
const nextIdx = nextNonWhitespace(A.prelude(at), afterIdx);
|
|
2749
2918
|
const mediaStart =
|
|
2750
|
-
nextIdx <
|
|
2919
|
+
nextIdx < A.prelude(at).length
|
|
2920
|
+
? A.start(A.prelude(at)[nextIdx])
|
|
2921
|
+
: A.end(at);
|
|
2751
2922
|
/** @type {undefined | string} */
|
|
2752
2923
|
let media;
|
|
2753
|
-
if (mediaStart !==
|
|
2754
|
-
media = input.slice(mediaStart,
|
|
2924
|
+
if (mediaStart !== A.end(at)) {
|
|
2925
|
+
media = input.slice(mediaStart, A.end(at)).trim();
|
|
2755
2926
|
}
|
|
2756
2927
|
|
|
2757
2928
|
const { line: sl, column: sc } = locConverter.get(importStart);
|
|
@@ -2793,9 +2964,9 @@ class CssParser extends Parser {
|
|
|
2793
2964
|
* @param {AtRule} at the `@value` at-rule
|
|
2794
2965
|
*/
|
|
2795
2966
|
const handleValueAtRule = (at) => {
|
|
2796
|
-
const start =
|
|
2797
|
-
const nameEnd =
|
|
2798
|
-
const semi =
|
|
2967
|
+
const start = A.start(at);
|
|
2968
|
+
const nameEnd = A.nameEnd(at);
|
|
2969
|
+
const semi = A.end(at);
|
|
2799
2970
|
const atRuleEnd =
|
|
2800
2971
|
source.charCodeAt(semi) === CC_SEMICOLON ? semi + 1 : semi;
|
|
2801
2972
|
const params = input.slice(nameEnd, semi);
|
|
@@ -2956,12 +3127,12 @@ class CssParser extends Parser {
|
|
|
2956
3127
|
/** @type {(cvs: AstNode[]) => void} */
|
|
2957
3128
|
const walkExports = (cvs) => {
|
|
2958
3129
|
for (const cv of cvs) {
|
|
2959
|
-
switch (
|
|
3130
|
+
switch (A.type(cv)) {
|
|
2960
3131
|
case NodeType.Comma:
|
|
2961
3132
|
parsedKeywords = Object.create(null);
|
|
2962
3133
|
break;
|
|
2963
3134
|
case NodeType.Delim:
|
|
2964
|
-
afterExclamation =
|
|
3135
|
+
afterExclamation = A.value(cv) === "!";
|
|
2965
3136
|
break;
|
|
2966
3137
|
case NodeType.Ident: {
|
|
2967
3138
|
if (isGridTemplate) break;
|
|
@@ -2969,8 +3140,9 @@ class CssParser extends Parser {
|
|
|
2969
3140
|
afterExclamation = false;
|
|
2970
3141
|
break;
|
|
2971
3142
|
}
|
|
2972
|
-
const identifier =
|
|
2973
|
-
|
|
3143
|
+
const identifier = A.value(cv);
|
|
3144
|
+
// Values are almost always lowercase already — avoid the copy.
|
|
3145
|
+
const keyword = toLowerCaseIfNeeded(identifier);
|
|
2974
3146
|
parsedKeywords[keyword] =
|
|
2975
3147
|
typeof parsedKeywords[keyword] !== "undefined"
|
|
2976
3148
|
? parsedKeywords[keyword] + 1
|
|
@@ -2981,7 +3153,7 @@ class CssParser extends Parser {
|
|
|
2981
3153
|
) {
|
|
2982
3154
|
break;
|
|
2983
3155
|
}
|
|
2984
|
-
emit(
|
|
3156
|
+
emit(A.start(cv), A.end(cv));
|
|
2985
3157
|
break;
|
|
2986
3158
|
}
|
|
2987
3159
|
case NodeType.String: {
|
|
@@ -2989,17 +3161,17 @@ class CssParser extends Parser {
|
|
|
2989
3161
|
declPropertyName === "animation" ||
|
|
2990
3162
|
declPropertyName === "animation-name"
|
|
2991
3163
|
) {
|
|
2992
|
-
emit(
|
|
3164
|
+
emit(A.start(cv), A.end(cv), true);
|
|
2993
3165
|
}
|
|
2994
3166
|
if (
|
|
2995
3167
|
declPropertyName === "grid" ||
|
|
2996
3168
|
declPropertyName === "grid-template" ||
|
|
2997
3169
|
declPropertyName === "grid-template-areas"
|
|
2998
3170
|
) {
|
|
2999
|
-
const areas =
|
|
3171
|
+
const areas = A.unescaped(cv);
|
|
3000
3172
|
const matches = matchAll(/\b\w+\b/g, areas);
|
|
3001
3173
|
for (const match of matches) {
|
|
3002
|
-
const areaStart =
|
|
3174
|
+
const areaStart = A.start(cv) + 1 + match.index;
|
|
3003
3175
|
emit(areaStart, areaStart + match[0].length, false);
|
|
3004
3176
|
}
|
|
3005
3177
|
}
|
|
@@ -3007,28 +3179,28 @@ class CssParser extends Parser {
|
|
|
3007
3179
|
}
|
|
3008
3180
|
case NodeType.SimpleBlock: {
|
|
3009
3181
|
const block = /** @type {SimpleBlock} */ (cv);
|
|
3010
|
-
if (block
|
|
3182
|
+
if (A.blockToken(block) === "[") {
|
|
3011
3183
|
// Collect identifiers until the first non-ident token (`<line-names> = '[' <custom-ident>* ']'`).
|
|
3012
|
-
for (const inner of block
|
|
3013
|
-
if (
|
|
3014
|
-
if (
|
|
3015
|
-
emit(
|
|
3184
|
+
for (const inner of A.children(block)) {
|
|
3185
|
+
if (A.type(inner) === NodeType.Whitespace) continue;
|
|
3186
|
+
if (A.type(inner) !== NodeType.Ident) break;
|
|
3187
|
+
emit(A.start(inner), A.end(inner));
|
|
3016
3188
|
}
|
|
3017
3189
|
} else if (isGridTemplate) {
|
|
3018
|
-
walkExports(block
|
|
3190
|
+
walkExports(A.children(block));
|
|
3019
3191
|
}
|
|
3020
3192
|
break;
|
|
3021
3193
|
}
|
|
3022
3194
|
case NodeType.Function:
|
|
3023
3195
|
if (isGridTemplate) {
|
|
3024
|
-
walkExports(
|
|
3196
|
+
walkExports(A.children(cv));
|
|
3025
3197
|
}
|
|
3026
3198
|
break;
|
|
3027
3199
|
// Other types carry no ICSS-export information.
|
|
3028
3200
|
}
|
|
3029
3201
|
}
|
|
3030
3202
|
};
|
|
3031
|
-
walkExports(decl
|
|
3203
|
+
walkExports(A.children(decl));
|
|
3032
3204
|
};
|
|
3033
3205
|
|
|
3034
3206
|
/**
|
|
@@ -3047,27 +3219,26 @@ class CssParser extends Parser {
|
|
|
3047
3219
|
) => {
|
|
3048
3220
|
const acceptIdent = isKeyframes || isCounterStyle || isContainer;
|
|
3049
3221
|
const acceptString = isKeyframes;
|
|
3050
|
-
for (const cv of
|
|
3051
|
-
|
|
3052
|
-
if (
|
|
3222
|
+
for (const cv of A.prelude(at)) {
|
|
3223
|
+
const cvType = A.type(cv);
|
|
3224
|
+
if (cvType === NodeType.Whitespace) continue;
|
|
3225
|
+
if (cvType === NodeType.String) {
|
|
3053
3226
|
if (acceptString) pure.markLocal();
|
|
3054
3227
|
break;
|
|
3055
3228
|
}
|
|
3056
|
-
if (
|
|
3229
|
+
if (cvType === NodeType.Ident) {
|
|
3057
3230
|
if (!acceptIdent) break;
|
|
3058
|
-
if (
|
|
3231
|
+
if (
|
|
3232
|
+
isContainer &&
|
|
3233
|
+
isContainerKeyword(source, A.start(cv), A.end(cv))
|
|
3234
|
+
) {
|
|
3059
3235
|
continue;
|
|
3060
3236
|
}
|
|
3061
3237
|
pure.markLocal();
|
|
3062
3238
|
break;
|
|
3063
3239
|
}
|
|
3064
|
-
if (
|
|
3065
|
-
if (
|
|
3066
|
-
equalsLowerCase(
|
|
3067
|
-
/** @type {FunctionNode} */ (cv).unescapedName,
|
|
3068
|
-
"local"
|
|
3069
|
-
)
|
|
3070
|
-
) {
|
|
3240
|
+
if (cvType === NodeType.Function) {
|
|
3241
|
+
if (equalsLowerCase(A.unescapedName(cv), "local")) {
|
|
3071
3242
|
pure.markLocal();
|
|
3072
3243
|
}
|
|
3073
3244
|
break;
|
|
@@ -3078,12 +3249,15 @@ class CssParser extends Parser {
|
|
|
3078
3249
|
// Drive the walk through SourceProcessor: structural enter / exit map to the `walkAst…Enter` / `…Exit` halves; value visitors handle url / ICSS / local-global.
|
|
3079
3250
|
/** @type {VisitorMap} */
|
|
3080
3251
|
const visitors = {
|
|
3252
|
+
[NodeType.Comment]: commentVisitor,
|
|
3081
3253
|
[NodeType.AtRule]: {
|
|
3082
3254
|
// At-rule enter: scope save, name dispatch, prelude value context, pure-block push.
|
|
3083
|
-
enter: (
|
|
3255
|
+
enter: (path) => {
|
|
3256
|
+
const node = path.node;
|
|
3084
3257
|
const at = /** @type {AtRule} */ (node);
|
|
3085
|
-
const topLevel = parent === null;
|
|
3086
|
-
|
|
3258
|
+
const topLevel = path.parent === null;
|
|
3259
|
+
currentUrlRecovery = false;
|
|
3260
|
+
advanceCommentCursor(A.start(at));
|
|
3087
3261
|
const savedAnchor = currentRule.hasLocalAnchor;
|
|
3088
3262
|
const savedLocalIdentifiers = currentRule.localIdentifiers;
|
|
3089
3263
|
// Only modules-mode walks mutate `localIdentifiers`; otherwise share
|
|
@@ -3091,33 +3265,32 @@ class CssParser extends Parser {
|
|
|
3091
3265
|
currentRule.localIdentifiers = isModules
|
|
3092
3266
|
? [...savedLocalIdentifiers]
|
|
3093
3267
|
: savedLocalIdentifiers;
|
|
3094
|
-
const name = `@${
|
|
3268
|
+
const name = `@${toLowerCaseIfNeeded(A.name(at))}`;
|
|
3095
3269
|
switch (name) {
|
|
3096
3270
|
case "@namespace": {
|
|
3097
3271
|
this._emitWarning(
|
|
3098
3272
|
state,
|
|
3099
3273
|
"'@namespace' is not supported in bundled CSS",
|
|
3100
3274
|
locConverter,
|
|
3101
|
-
|
|
3102
|
-
|
|
3275
|
+
A.start(at),
|
|
3276
|
+
A.nameEnd(at)
|
|
3103
3277
|
);
|
|
3104
3278
|
break;
|
|
3105
3279
|
}
|
|
3106
3280
|
case "@charset": {
|
|
3107
3281
|
if (/** @type {CssModule} */ (module).exportType !== "style") {
|
|
3282
|
+
const atEnd = A.end(at);
|
|
3108
3283
|
const atRuleEnd =
|
|
3109
|
-
source.charCodeAt(
|
|
3110
|
-
|
|
3111
|
-
: at.end;
|
|
3112
|
-
const dep = new ConstDependency("", [at.start, atRuleEnd]);
|
|
3284
|
+
source.charCodeAt(atEnd) === CC_SEMICOLON ? atEnd + 1 : atEnd;
|
|
3285
|
+
const dep = new ConstDependency("", [A.start(at), atRuleEnd]);
|
|
3113
3286
|
module.addPresentationalDependency(dep);
|
|
3114
|
-
const string =
|
|
3115
|
-
(v) =>
|
|
3287
|
+
const string = A.prelude(at).find(
|
|
3288
|
+
(v) => A.type(v) !== NodeType.Whitespace
|
|
3116
3289
|
);
|
|
3117
|
-
if (string &&
|
|
3290
|
+
if (string && A.type(string) === NodeType.String) {
|
|
3118
3291
|
/** @type {CssModuleBuildInfo} */
|
|
3119
3292
|
(module.buildInfo).charset = source
|
|
3120
|
-
.slice(
|
|
3293
|
+
.slice(A.start(string) + 1, A.end(string) - 1)
|
|
3121
3294
|
.toUpperCase();
|
|
3122
3295
|
}
|
|
3123
3296
|
}
|
|
@@ -3158,11 +3331,11 @@ class CssParser extends Parser {
|
|
|
3158
3331
|
// `@scope (.x) to (.y)` — walk the prelude as a selector list.
|
|
3159
3332
|
if (
|
|
3160
3333
|
isModules &&
|
|
3161
|
-
equalsLowerCase(
|
|
3162
|
-
|
|
3334
|
+
equalsLowerCase(A.name(at), "scope") &&
|
|
3335
|
+
A.prelude(at).length > 0
|
|
3163
3336
|
) {
|
|
3164
3337
|
walkSelectorList(
|
|
3165
|
-
|
|
3338
|
+
A.prelude(at),
|
|
3166
3339
|
/** @type {"local" | "global"} */ (
|
|
3167
3340
|
mode === "local" ? "local" : "global"
|
|
3168
3341
|
)
|
|
@@ -3175,14 +3348,9 @@ class CssParser extends Parser {
|
|
|
3175
3348
|
currentStructural = at;
|
|
3176
3349
|
currentAtRuleName = name;
|
|
3177
3350
|
dashed.active = false;
|
|
3178
|
-
// `@import` url() is the import target — only walk its prelude for url deps on malformed-import recovery
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
if (
|
|
3182
|
-
this.options.url &&
|
|
3183
|
-
(name !== "@import" || atWithRecovery.urlRecovery)
|
|
3184
|
-
) {
|
|
3185
|
-
lastTokenEndForComments = at.nameEnd;
|
|
3351
|
+
// `@import` url() is the import target — only walk its prelude for url deps on malformed-import recovery.
|
|
3352
|
+
if (this.options.url && (name !== "@import" || currentUrlRecovery)) {
|
|
3353
|
+
lastTokenEndForComments = A.nameEnd(at);
|
|
3186
3354
|
}
|
|
3187
3355
|
// Dashed-ident scoping over the prelude (the Ident / Function visitors emit).
|
|
3188
3356
|
dashed.active = Boolean(
|
|
@@ -3219,18 +3387,21 @@ class CssParser extends Parser {
|
|
|
3219
3387
|
}
|
|
3220
3388
|
|
|
3221
3389
|
// pure.stack push for block-bearing at-rules.
|
|
3222
|
-
const
|
|
3223
|
-
|
|
3390
|
+
const atDecls = A.declarations(at);
|
|
3391
|
+
const atChildRules = A.childRules(at);
|
|
3392
|
+
const atHasBlock = Boolean(atDecls || atChildRules);
|
|
3393
|
+
const atBlockStart = A.blockStart(at);
|
|
3394
|
+
if (atHasBlock && atBlockStart !== -1) {
|
|
3224
3395
|
const isAtRulePrelude = isPureBodyAtRule(name);
|
|
3225
3396
|
if (isAtRulePrelude) pure.finalizeSelector();
|
|
3226
3397
|
pure.enterBlock({
|
|
3227
3398
|
isRulePrelude: isAtRulePrelude,
|
|
3228
3399
|
treatAsLeaf: atTreatAsLeaf,
|
|
3229
3400
|
ownSkip: atSkipChildren,
|
|
3230
|
-
declarations:
|
|
3231
|
-
childRules:
|
|
3232
|
-
preludeStart:
|
|
3233
|
-
preludeEnd:
|
|
3401
|
+
declarations: atDecls,
|
|
3402
|
+
childRules: atChildRules,
|
|
3403
|
+
preludeStart: A.start(at),
|
|
3404
|
+
preludeEnd: atBlockStart
|
|
3234
3405
|
});
|
|
3235
3406
|
}
|
|
3236
3407
|
|
|
@@ -3239,11 +3410,12 @@ class CssParser extends Parser {
|
|
|
3239
3410
|
savedLocalIdentifiers,
|
|
3240
3411
|
name,
|
|
3241
3412
|
hasBlock: atHasBlock,
|
|
3242
|
-
endsWithSemicolon: source.charCodeAt(
|
|
3413
|
+
endsWithSemicolon: source.charCodeAt(A.end(at)) === CC_SEMICOLON
|
|
3243
3414
|
});
|
|
3244
3415
|
},
|
|
3245
3416
|
// At-rule exit: pure-frame finalization, `suppressNextRulePrelude`, scope restore, top-level reset.
|
|
3246
|
-
exit: (
|
|
3417
|
+
exit: (path) => {
|
|
3418
|
+
const node = path.node;
|
|
3247
3419
|
const state = atRuleStateStack.pop();
|
|
3248
3420
|
if (!state) return;
|
|
3249
3421
|
if (state.hasBlock) {
|
|
@@ -3258,33 +3430,36 @@ class CssParser extends Parser {
|
|
|
3258
3430
|
}
|
|
3259
3431
|
currentRule.hasLocalAnchor = state.savedAnchor;
|
|
3260
3432
|
currentRule.localIdentifiers = state.savedLocalIdentifiers;
|
|
3261
|
-
if (parent === null) finishTopLevelRule(node, true);
|
|
3433
|
+
if (path.parent === null) finishTopLevelRule(node, true);
|
|
3262
3434
|
}
|
|
3263
3435
|
},
|
|
3264
3436
|
[NodeType.QualifiedRule]: {
|
|
3265
|
-
// Qualified-rule enter: scope setup, selector + prelude context, pure-block push; `:import` / `:export` bail via `
|
|
3266
|
-
enter: (
|
|
3437
|
+
// Qualified-rule enter: scope setup, selector + prelude context, pure-block push; `:import` / `:export` bail via `path.skipChildren()`.
|
|
3438
|
+
enter: (path) => {
|
|
3439
|
+
const node = path.node;
|
|
3267
3440
|
const rule = /** @type {QualifiedRule} */ (node);
|
|
3268
|
-
const topLevel = parent === null;
|
|
3269
|
-
advanceCommentCursor(
|
|
3441
|
+
const topLevel = path.parent === null;
|
|
3442
|
+
advanceCommentCursor(A.start(rule));
|
|
3270
3443
|
// `:import(…) { … }` / `:export { … }` ICSS pseudo-rules are processed inline at top level; nested ones bail out.
|
|
3271
3444
|
if (isModules) {
|
|
3272
|
-
const
|
|
3445
|
+
const rulePrelude = A.prelude(rule);
|
|
3446
|
+
const firstIdx = nextNonWhitespace(rulePrelude, 0);
|
|
3273
3447
|
if (
|
|
3274
|
-
firstIdx + 1 <
|
|
3275
|
-
|
|
3448
|
+
firstIdx + 1 < rulePrelude.length &&
|
|
3449
|
+
A.type(rulePrelude[firstIdx]) === NodeType.Colon
|
|
3276
3450
|
) {
|
|
3277
|
-
const second =
|
|
3451
|
+
const second = rulePrelude[firstIdx + 1];
|
|
3452
|
+
const secondType = A.type(second);
|
|
3278
3453
|
const rawName =
|
|
3279
|
-
|
|
3280
|
-
?
|
|
3281
|
-
:
|
|
3282
|
-
?
|
|
3454
|
+
secondType === NodeType.Ident
|
|
3455
|
+
? A.value(second)
|
|
3456
|
+
: secondType === NodeType.Function
|
|
3457
|
+
? A.name(second)
|
|
3283
3458
|
: "";
|
|
3284
3459
|
const isImport = equalsLowerCase(rawName, "import");
|
|
3285
3460
|
if (isImport || equalsLowerCase(rawName, "export")) {
|
|
3286
3461
|
if (topLevel) {
|
|
3287
|
-
const startColon =
|
|
3462
|
+
const startColon = A.start(rulePrelude[firstIdx]);
|
|
3288
3463
|
const endAfterBody = processImportOrExport(
|
|
3289
3464
|
isImport ? 0 : 1,
|
|
3290
3465
|
second,
|
|
@@ -3293,14 +3468,16 @@ class CssParser extends Parser {
|
|
|
3293
3468
|
module.addPresentationalDependency(
|
|
3294
3469
|
new ConstDependency("", [startColon, endAfterBody])
|
|
3295
3470
|
);
|
|
3296
|
-
if (
|
|
3297
|
-
|
|
3298
|
-
|
|
3471
|
+
if (A.blockStart(rule) !== -1) {
|
|
3472
|
+
A.setBlockEnd(rule, endAfterBody);
|
|
3473
|
+
}
|
|
3474
|
+
A.setEnd(rule, endAfterBody);
|
|
3475
|
+
} else if (A.blockStart(rule) !== -1) {
|
|
3299
3476
|
// Nested `:import` / `:export` — leave the body alone.
|
|
3300
|
-
rule
|
|
3477
|
+
A.setEnd(rule, A.blockEnd(rule));
|
|
3301
3478
|
}
|
|
3302
3479
|
// Don't recurse into the body — handled inline above.
|
|
3303
|
-
|
|
3480
|
+
path.skipChildren();
|
|
3304
3481
|
qualifiedRuleStateStack.push({ bailed: true });
|
|
3305
3482
|
return;
|
|
3306
3483
|
}
|
|
@@ -3327,9 +3504,10 @@ class CssParser extends Parser {
|
|
|
3327
3504
|
savedComposesFiles
|
|
3328
3505
|
});
|
|
3329
3506
|
// Selectors are only CSS-Modules-relevant when `isModules` holds.
|
|
3507
|
+
const rulePrelude = A.prelude(rule);
|
|
3330
3508
|
if (isModules) {
|
|
3331
3509
|
walkSelectorList(
|
|
3332
|
-
|
|
3510
|
+
rulePrelude,
|
|
3333
3511
|
/** @type {"local" | "global"} */ (
|
|
3334
3512
|
mode === "local" ? "local" : "global"
|
|
3335
3513
|
)
|
|
@@ -3339,20 +3517,20 @@ class CssParser extends Parser {
|
|
|
3339
3517
|
currentStructural = rule;
|
|
3340
3518
|
dashed.active = false;
|
|
3341
3519
|
dashed.emit = false;
|
|
3342
|
-
if (this.options.url &&
|
|
3343
|
-
lastTokenEndForComments =
|
|
3520
|
+
if (this.options.url && rulePrelude.length > 0) {
|
|
3521
|
+
lastTokenEndForComments = A.start(rulePrelude[0]);
|
|
3344
3522
|
}
|
|
3345
3523
|
// Dashed-ident scoping for the deprecated `--foo: { … }` custom-property-set syntax (prelude starts with a dashed-ident).
|
|
3346
3524
|
if (
|
|
3347
3525
|
this.options.dashedIdents &&
|
|
3348
3526
|
isModules &&
|
|
3349
|
-
|
|
3527
|
+
rulePrelude.length > 0
|
|
3350
3528
|
) {
|
|
3351
|
-
const first =
|
|
3529
|
+
const first = rulePrelude[nextNonWhitespace(rulePrelude, 0)];
|
|
3352
3530
|
if (
|
|
3353
3531
|
first &&
|
|
3354
|
-
|
|
3355
|
-
isDashedIdentifier(
|
|
3532
|
+
A.type(first) === NodeType.Ident &&
|
|
3533
|
+
isDashedIdentifier(A.value(first))
|
|
3356
3534
|
) {
|
|
3357
3535
|
const effectiveLocalMode = isEffectivelyLocal();
|
|
3358
3536
|
if (effectiveLocalMode) {
|
|
@@ -3362,18 +3540,20 @@ class CssParser extends Parser {
|
|
|
3362
3540
|
}
|
|
3363
3541
|
}
|
|
3364
3542
|
// Pure-mode: report an impure prelude (if leaf-ish) and push the inherited-context frame before walking the body.
|
|
3543
|
+
const ruleBlockStart = A.blockStart(rule);
|
|
3365
3544
|
pure.enterBlock({
|
|
3366
3545
|
isRulePrelude: true,
|
|
3367
3546
|
treatAsLeaf: false,
|
|
3368
3547
|
ownSkip: false,
|
|
3369
|
-
declarations:
|
|
3370
|
-
childRules:
|
|
3371
|
-
preludeStart:
|
|
3372
|
-
preludeEnd:
|
|
3548
|
+
declarations: A.declarations(rule),
|
|
3549
|
+
childRules: A.childRules(rule),
|
|
3550
|
+
preludeStart: A.start(rule),
|
|
3551
|
+
preludeEnd: ruleBlockStart !== -1 ? ruleBlockStart : A.end(rule)
|
|
3373
3552
|
});
|
|
3374
3553
|
},
|
|
3375
3554
|
// Qualified-rule exit: pure-frame finalization, scope restore, top-level reset; no-op for bailed ICSS.
|
|
3376
|
-
exit: (
|
|
3555
|
+
exit: (path) => {
|
|
3556
|
+
const node = path.node;
|
|
3377
3557
|
const state = qualifiedRuleStateStack.pop();
|
|
3378
3558
|
if (!state || state.bailed) return;
|
|
3379
3559
|
pure.exitBlock();
|
|
@@ -3381,23 +3561,19 @@ class CssParser extends Parser {
|
|
|
3381
3561
|
currentRule.localIdentifiers = state.savedLocalIdentifiers;
|
|
3382
3562
|
currentRule.composesPrevFile = state.savedPrevComposesFile;
|
|
3383
3563
|
currentRule.composesFiles = state.savedComposesFiles;
|
|
3384
|
-
if (parent === null) finishTopLevelRule(node, false);
|
|
3564
|
+
if (path.parent === null) finishTopLevelRule(node, false);
|
|
3385
3565
|
}
|
|
3386
3566
|
},
|
|
3387
3567
|
// Top-level declarations are parse errors (dropped by `parseAStylesheet`), so a declaration's parent is always a block.
|
|
3388
|
-
[NodeType.Declaration]: (
|
|
3568
|
+
[NodeType.Declaration]: (path) => {
|
|
3569
|
+
const node = path.node;
|
|
3389
3570
|
const decl = /** @type {Declaration} */ (node);
|
|
3390
3571
|
// Reset value-visitor context, read by the value visitors below.
|
|
3391
3572
|
currentStructural = decl;
|
|
3392
3573
|
dashed.active = false;
|
|
3393
3574
|
dashed.emit = false;
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
.toLowerCase();
|
|
3397
|
-
// Cache the known-property flag so the per-token value visitors don't recompute it.
|
|
3398
|
-
currentDeclIsKnownProperty = knownProperties.has(declPropertyName);
|
|
3399
|
-
// Position `lastTokenEndForComments` just past the `:` so a magic comment before the url() is found.
|
|
3400
|
-
let colonPos = decl.nameEnd;
|
|
3575
|
+
// Position `lastTokenEndForComments` just past the `:` so a magic comment before a url() is found (every mode).
|
|
3576
|
+
let colonPos = A.nameEnd(decl);
|
|
3401
3577
|
while (
|
|
3402
3578
|
colonPos < source.length &&
|
|
3403
3579
|
source.charCodeAt(colonPos) !== CC_COLON
|
|
@@ -3405,49 +3581,92 @@ class CssParser extends Parser {
|
|
|
3405
3581
|
colonPos++;
|
|
3406
3582
|
}
|
|
3407
3583
|
lastTokenEndForComments = colonPos + 1;
|
|
3584
|
+
currentDeclIsKnownProperty = false;
|
|
3585
|
+
currentDeclComposesSkip = false;
|
|
3586
|
+
// Property-name analysis and value exports are CSS-Modules-only; a plain
|
|
3587
|
+
// stylesheet's declarations need no per-decl name slice / known-property lookup.
|
|
3588
|
+
if (!isModules) return;
|
|
3589
|
+
const nameStart = A.nameStart(decl);
|
|
3590
|
+
const nameEnd = A.nameEnd(decl);
|
|
3591
|
+
// Range-based name analysis — the common declaration never
|
|
3592
|
+
// slices its name out of the source.
|
|
3593
|
+
/** @type {string | undefined} */
|
|
3594
|
+
let declName;
|
|
3595
|
+
/** @type {string | undefined} */
|
|
3596
|
+
let declPropertyName;
|
|
3597
|
+
if (source.charCodeAt(nameStart) === CC_HYPHEN_MINUS) {
|
|
3598
|
+
// Vendor-prefixed or custom property — rare, take the string path.
|
|
3599
|
+
declName = A.name(decl);
|
|
3600
|
+
declPropertyName = toLowerCaseIfNeeded(
|
|
3601
|
+
declName.replace(VENDOR_PREFIX, "")
|
|
3602
|
+
);
|
|
3603
|
+
currentDeclIsKnownProperty = knownProperties.has(declPropertyName);
|
|
3604
|
+
} else {
|
|
3605
|
+
declPropertyName = knownPropertyForRange(
|
|
3606
|
+
knownPropertyIndex,
|
|
3607
|
+
source,
|
|
3608
|
+
nameStart,
|
|
3609
|
+
nameEnd
|
|
3610
|
+
);
|
|
3611
|
+
// Cache the known-property flag so the per-token value visitors don't recompute it.
|
|
3612
|
+
currentDeclIsKnownProperty = declPropertyName !== undefined;
|
|
3613
|
+
}
|
|
3408
3614
|
const effectiveLocalMode = isEffectivelyLocal();
|
|
3409
3615
|
// `composes:` with a local anchor: its strip-dep covers the whole declaration, so suppress the value's local/global/dashed/ICSS rewrites.
|
|
3410
3616
|
currentDeclComposesSkip =
|
|
3411
3617
|
currentRule.hasLocalAnchor &&
|
|
3412
|
-
|
|
3618
|
+
(declPropertyName !== undefined
|
|
3619
|
+
? COMPOSES_PROPERTY.test(declPropertyName)
|
|
3620
|
+
: rangeEqualsLowerCase(source, nameStart, nameEnd, "composes") ||
|
|
3621
|
+
rangeEqualsLowerCase(source, nameStart, nameEnd, "compose-with"));
|
|
3413
3622
|
if (currentDeclComposesSkip) emitComposesWithAnchor(decl);
|
|
3414
3623
|
const skipForComposes = currentDeclComposesSkip;
|
|
3415
3624
|
// Known-property value localization (`animation-name: foo` exports `foo`).
|
|
3416
|
-
if (
|
|
3417
|
-
emitKnownPropertyExports(
|
|
3625
|
+
if (effectiveLocalMode && currentDeclIsKnownProperty) {
|
|
3626
|
+
emitKnownPropertyExports(
|
|
3627
|
+
decl,
|
|
3628
|
+
/** @type {string} */ (declPropertyName)
|
|
3629
|
+
);
|
|
3418
3630
|
}
|
|
3419
3631
|
// Dashed-ident (custom-property) export of the property name; the value's dashed idents are scoped by the Ident / Function visitors (top-level only for unknown properties).
|
|
3420
3632
|
if (
|
|
3421
3633
|
this.options.dashedIdents &&
|
|
3422
|
-
isModules &&
|
|
3423
3634
|
effectiveLocalMode &&
|
|
3424
3635
|
!skipForComposes
|
|
3425
3636
|
) {
|
|
3426
|
-
|
|
3427
|
-
|
|
3637
|
+
// Only the `-`-prefixed path can carry a dashed ident.
|
|
3638
|
+
if (declName !== undefined && isDashedIdentifier(declName)) {
|
|
3639
|
+
emitDashedIdentExport(nameStart, nameEnd);
|
|
3428
3640
|
}
|
|
3429
3641
|
dashed.active = true;
|
|
3430
3642
|
dashed.emit = !currentDeclIsKnownProperty;
|
|
3431
3643
|
}
|
|
3432
|
-
// ICSS-symbol rewrite (`color: foo` when `foo` is `@value`-defined), skipping known properties, the composes anchor, and dashed idents (handled above).
|
|
3644
|
+
// ICSS-symbol rewrite (`color: foo` when `foo` is `@value`-defined), skipping known properties, the composes anchor, and dashed idents (handled above). Nothing to rewrite without definitions — don't slice the name.
|
|
3433
3645
|
if (
|
|
3434
|
-
isModules &&
|
|
3435
3646
|
!skipForComposes &&
|
|
3436
3647
|
!currentDeclIsKnownProperty &&
|
|
3437
|
-
|
|
3438
|
-
icssDefinitions.has(decl.name)
|
|
3648
|
+
icssDefinitions.size !== 0
|
|
3439
3649
|
) {
|
|
3440
|
-
|
|
3650
|
+
if (declName === undefined) {
|
|
3651
|
+
declName = source.slice(nameStart, nameEnd);
|
|
3652
|
+
}
|
|
3653
|
+
if (
|
|
3654
|
+
!(dashed.active && isDashedIdentifier(declName)) &&
|
|
3655
|
+
icssDefinitions.has(declName)
|
|
3656
|
+
) {
|
|
3657
|
+
emitICSSSymbol(declName, nameStart, nameEnd);
|
|
3658
|
+
}
|
|
3441
3659
|
}
|
|
3442
3660
|
},
|
|
3443
3661
|
// Value-level visitors decide handling from the enclosing node via `urlActive()` / `localGlobalActive()` / `icssActive()`.
|
|
3444
|
-
[NodeType.Url]: (
|
|
3662
|
+
[NodeType.Url]: (path) => {
|
|
3663
|
+
const node = path.node;
|
|
3445
3664
|
const url = /** @type {UrlToken} */ (node);
|
|
3446
3665
|
if (!urlActive()) return;
|
|
3447
3666
|
// Skip bare url-tokens for a known property in CSS-Modules local mode.
|
|
3448
3667
|
if (
|
|
3449
3668
|
currentStructural &&
|
|
3450
|
-
|
|
3669
|
+
A.type(currentStructural) === NodeType.Declaration &&
|
|
3451
3670
|
isModules &&
|
|
3452
3671
|
currentDeclIsKnownProperty &&
|
|
3453
3672
|
isEffectivelyLocal()
|
|
@@ -3456,15 +3675,15 @@ class CssParser extends Parser {
|
|
|
3456
3675
|
}
|
|
3457
3676
|
if (
|
|
3458
3677
|
webpackIgnored(
|
|
3459
|
-
[lastTokenEndForComments,
|
|
3678
|
+
[lastTokenEndForComments, A.end(node)],
|
|
3460
3679
|
lastTokenEndForComments,
|
|
3461
|
-
|
|
3680
|
+
A.end(node)
|
|
3462
3681
|
)
|
|
3463
3682
|
) {
|
|
3464
3683
|
return;
|
|
3465
3684
|
}
|
|
3466
3685
|
let value = normalizeUrl(
|
|
3467
|
-
input.slice(
|
|
3686
|
+
input.slice(A.contentStart(url), A.contentEnd(url)),
|
|
3468
3687
|
false
|
|
3469
3688
|
);
|
|
3470
3689
|
// Ignore `url()`, `url('')` and `url("")`, they are valid by spec
|
|
@@ -3485,55 +3704,64 @@ class CssParser extends Parser {
|
|
|
3485
3704
|
state,
|
|
3486
3705
|
`'@value' identifier '${value}' was imported from another module and cannot be used inside 'url()' — only locally defined values are supported here`,
|
|
3487
3706
|
locConverter,
|
|
3488
|
-
|
|
3489
|
-
|
|
3707
|
+
A.start(node),
|
|
3708
|
+
A.end(node)
|
|
3490
3709
|
);
|
|
3491
3710
|
return;
|
|
3492
3711
|
}
|
|
3493
3712
|
}
|
|
3494
3713
|
}
|
|
3495
|
-
const dep = new CssUrlDependency(
|
|
3496
|
-
|
|
3714
|
+
const dep = new CssUrlDependency(
|
|
3715
|
+
value,
|
|
3716
|
+
[A.start(node), A.end(node)],
|
|
3717
|
+
"url"
|
|
3718
|
+
);
|
|
3719
|
+
setDepLoc(dep, A.start(node), A.end(node));
|
|
3497
3720
|
module.addDependency(dep);
|
|
3498
3721
|
module.addCodeGenerationDependency(dep);
|
|
3499
3722
|
},
|
|
3500
|
-
[NodeType.Comma](
|
|
3501
|
-
|
|
3723
|
+
[NodeType.Comma](path) {
|
|
3724
|
+
const node = path.node;
|
|
3725
|
+
if (urlActive()) lastTokenEndForComments = A.start(node);
|
|
3502
3726
|
},
|
|
3503
3727
|
[NodeType.Function]: {
|
|
3504
|
-
enter: (
|
|
3728
|
+
enter: (path) => {
|
|
3729
|
+
const node = path.node;
|
|
3505
3730
|
const fn = /** @type {FunctionNode} */ (node);
|
|
3506
|
-
const fnameRaw =
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
) {
|
|
3513
|
-
processLocalOrGlobalFunction(fn,
|
|
3731
|
+
const fnameRaw = A.unescapedName(fn);
|
|
3732
|
+
// `equalsLowerCase` keeps this visitor free of a per-function
|
|
3733
|
+
// lowercased copy — functions are the densest value nodes.
|
|
3734
|
+
const isLocalFn = equalsLowerCase(fnameRaw, "local");
|
|
3735
|
+
const isGlobalFn = !isLocalFn && equalsLowerCase(fnameRaw, "global");
|
|
3736
|
+
if (urlActive()) emitUrlFunction(fn, fnameRaw);
|
|
3737
|
+
if (localGlobalActive() && (isLocalFn || isGlobalFn)) {
|
|
3738
|
+
processLocalOrGlobalFunction(fn, isLocalFn ? 1 : 2);
|
|
3514
3739
|
}
|
|
3515
3740
|
if (
|
|
3516
3741
|
icssActive() &&
|
|
3517
|
-
|
|
3518
|
-
|
|
3742
|
+
!isLocalFn &&
|
|
3743
|
+
!isGlobalFn &&
|
|
3519
3744
|
!(dashed.active && isDashedIdentifier(fnameRaw)) &&
|
|
3520
3745
|
icssDefinitions.has(fnameRaw)
|
|
3521
3746
|
) {
|
|
3522
|
-
emitICSSSymbol(fnameRaw,
|
|
3747
|
+
emitICSSSymbol(fnameRaw, A.nameStart(fn), A.nameEnd(fn));
|
|
3523
3748
|
}
|
|
3524
3749
|
// Dashed-ident scoping: handle this function, then set the child nesting level's state for the walk.
|
|
3525
3750
|
dashed.push();
|
|
3526
3751
|
if (dashed.active) {
|
|
3527
|
-
if (
|
|
3752
|
+
if (isLocalFn || isGlobalFn) {
|
|
3528
3753
|
// `local()` / `global()` dashed args go through the ICSS path above, not here.
|
|
3529
3754
|
dashed.active = false;
|
|
3530
|
-
} else if (
|
|
3755
|
+
} else if (
|
|
3756
|
+
equalsLowerCase(fnameRaw, "var") ||
|
|
3757
|
+
equalsLowerCase(fnameRaw, "style")
|
|
3758
|
+
) {
|
|
3531
3759
|
// `var(--foo, …)` / `style(--foo, …)`: emit the first ident; the fallback doesn't self-emit.
|
|
3532
3760
|
processDashedIdentInVarFunction(fn);
|
|
3533
3761
|
dashed.emit = false;
|
|
3534
|
-
} else if (dashed.emit && isDashedIdentifier(
|
|
3762
|
+
} else if (dashed.emit && isDashedIdentifier(A.name(fn))) {
|
|
3535
3763
|
// Custom-function call `--my-func(args)` — the name is the exported dashed-ident.
|
|
3536
|
-
emitDashedIdentExport(
|
|
3764
|
+
emitDashedIdentExport(A.nameStart(fn), A.nameEnd(fn));
|
|
3537
3765
|
}
|
|
3538
3766
|
}
|
|
3539
3767
|
},
|
|
@@ -3541,61 +3769,83 @@ class CssParser extends Parser {
|
|
|
3541
3769
|
dashed.pop();
|
|
3542
3770
|
}
|
|
3543
3771
|
},
|
|
3544
|
-
[NodeType.Ident](
|
|
3545
|
-
const
|
|
3546
|
-
|
|
3772
|
+
[NodeType.Ident](path) {
|
|
3773
|
+
const node = path.node;
|
|
3774
|
+
// Fast exit before slicing the ident value: outside dashed-ident scoping
|
|
3775
|
+
// and ICSS context (any non-CSS-Modules stylesheet) a bare ident carries
|
|
3776
|
+
// no work, and idents are the most common node, so skipping the per-ident
|
|
3777
|
+
// `value` slice matters. With no `@value`/`:import` definitions the ICSS
|
|
3778
|
+
// probe can never hit, so it doesn't warrant the slice either.
|
|
3779
|
+
const dashedActive = dashed.active;
|
|
3780
|
+
const icss = icssActive() && icssDefinitions.size !== 0;
|
|
3781
|
+
if (!dashedActive && !icss) return;
|
|
3782
|
+
const identValue = A.value(node);
|
|
3783
|
+
if (dashedActive && isDashedIdentifier(identValue)) {
|
|
3547
3784
|
// Dashed idents are scoped here, never `@value` ICSS-rewritten.
|
|
3548
3785
|
if (!dashed.emit) return;
|
|
3549
3786
|
// Resolve the `--foo from "./x.css"` / `--foo from global` import suffix via sibling lookahead.
|
|
3550
|
-
const siblings = childrenOf(parent);
|
|
3787
|
+
const siblings = childrenOf(path.parent);
|
|
3551
3788
|
const i = siblings ? siblings.indexOf(node) : -1;
|
|
3552
3789
|
if (siblings && i !== -1) {
|
|
3553
3790
|
const j = nextNonWhitespace(siblings, i + 1);
|
|
3554
3791
|
if (
|
|
3555
3792
|
j < siblings.length &&
|
|
3556
|
-
siblings[j]
|
|
3557
|
-
|
|
3793
|
+
A.type(siblings[j]) === NodeType.Ident &&
|
|
3794
|
+
rangeEqualsLowerCase(
|
|
3795
|
+
input,
|
|
3796
|
+
A.start(siblings[j]),
|
|
3797
|
+
A.end(siblings[j]),
|
|
3798
|
+
"from"
|
|
3799
|
+
)
|
|
3558
3800
|
) {
|
|
3559
3801
|
const fromIdent = siblings[j];
|
|
3560
3802
|
const sourceNode = siblings[nextNonWhitespace(siblings, j + 1)];
|
|
3561
3803
|
if (
|
|
3562
3804
|
sourceNode &&
|
|
3563
|
-
|
|
3564
|
-
|
|
3805
|
+
A.type(sourceNode) === NodeType.Ident &&
|
|
3806
|
+
rangeEquals(
|
|
3807
|
+
input,
|
|
3808
|
+
A.start(sourceNode),
|
|
3809
|
+
A.end(sourceNode),
|
|
3810
|
+
"global"
|
|
3811
|
+
)
|
|
3565
3812
|
) {
|
|
3566
|
-
emitDashedIdentFromGlobal(
|
|
3813
|
+
emitDashedIdentFromGlobal(A.end(node), A.end(sourceNode));
|
|
3567
3814
|
return;
|
|
3568
3815
|
}
|
|
3569
|
-
if (sourceNode &&
|
|
3816
|
+
if (sourceNode && A.type(sourceNode) === NodeType.String) {
|
|
3570
3817
|
emitDashedIdentImport(
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
input.slice(
|
|
3818
|
+
A.start(node),
|
|
3819
|
+
A.end(node),
|
|
3820
|
+
A.start(fromIdent),
|
|
3821
|
+
A.end(sourceNode),
|
|
3822
|
+
input.slice(A.start(sourceNode) + 1, A.end(sourceNode) - 1)
|
|
3576
3823
|
);
|
|
3577
3824
|
return;
|
|
3578
3825
|
}
|
|
3579
3826
|
}
|
|
3580
3827
|
}
|
|
3581
|
-
emitDashedIdentExport(
|
|
3828
|
+
emitDashedIdentExport(A.start(node), A.end(node));
|
|
3582
3829
|
return;
|
|
3583
3830
|
}
|
|
3584
|
-
if (!
|
|
3831
|
+
if (!icss) return;
|
|
3585
3832
|
if (icssDefinitions.has(identValue)) {
|
|
3586
|
-
emitICSSSymbol(identValue,
|
|
3833
|
+
emitICSSSymbol(identValue, A.start(node), A.end(node));
|
|
3587
3834
|
}
|
|
3588
3835
|
}
|
|
3589
3836
|
};
|
|
3590
3837
|
// `as` selects the top-level production (§5.3): a `style` attribute is a
|
|
3591
|
-
// block's contents, everything else a full stylesheet (the default).
|
|
3592
|
-
|
|
3838
|
+
// block's contents, everything else a full stylesheet (the default). `as`
|
|
3839
|
+
// and `skip` are per-parse config on the processor; only `locConverter`
|
|
3840
|
+
// (per-source) is passed to `process`. One skip set: selector prelude +
|
|
3841
|
+
// unread value leaves (non-modules only; CSS Modules needs its selectors
|
|
3842
|
+
// and ICSS-captured values).
|
|
3843
|
+
new SourceProcessor({
|
|
3844
|
+
as: /** @type {"stylesheet" | "block-contents"} */ (this.options.as),
|
|
3845
|
+
skip: isModules ? undefined : SKIP_NON_MODULES
|
|
3846
|
+
})
|
|
3593
3847
|
.use(/** @type {VisitorMap} */ (visitors))
|
|
3594
|
-
.process(source, {
|
|
3595
|
-
locConverter,
|
|
3596
|
-
comment,
|
|
3597
|
-
as: /** @type {"stylesheet" | "block-contents"} */ (this.options.as)
|
|
3598
|
-
});
|
|
3848
|
+
.process(source, { locConverter });
|
|
3599
3849
|
|
|
3600
3850
|
/** @type {BuildInfo} */
|
|
3601
3851
|
(module.buildInfo).strict = true;
|