webpack 5.96.1 → 5.97.0

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.
Files changed (64) hide show
  1. package/lib/CssModule.js +5 -0
  2. package/lib/DependencyTemplate.js +2 -2
  3. package/lib/EvalSourceMapDevToolPlugin.js +5 -0
  4. package/lib/FalseIIFEUmdWarning.js +19 -0
  5. package/lib/HotModuleReplacementPlugin.js +4 -0
  6. package/lib/Module.js +6 -0
  7. package/lib/ModuleSourceTypesConstants.js +12 -0
  8. package/lib/NormalModule.js +1 -0
  9. package/lib/RuntimeTemplate.js +7 -0
  10. package/lib/SourceMapDevToolPlugin.js +8 -0
  11. package/lib/WebpackOptionsApply.js +3 -1
  12. package/lib/asset/AssetModulesPlugin.js +7 -2
  13. package/lib/config/defaults.js +52 -36
  14. package/lib/config/normalization.js +0 -1
  15. package/lib/config/target.js +8 -8
  16. package/lib/css/CssGenerator.js +139 -35
  17. package/lib/css/CssLoadingRuntimeModule.js +108 -198
  18. package/lib/css/CssModulesPlugin.js +78 -124
  19. package/lib/css/CssParser.js +545 -121
  20. package/lib/css/walkCssTokens.js +41 -19
  21. package/lib/dependencies/CachedConstDependency.js +2 -1
  22. package/lib/dependencies/ContextDependencyTemplateAsId.js +3 -2
  23. package/lib/dependencies/{CssExportDependency.js → CssIcssExportDependency.js} +35 -35
  24. package/lib/dependencies/CssIcssImportDependency.js +118 -0
  25. package/lib/dependencies/CssIcssSymbolDependency.js +132 -0
  26. package/lib/dependencies/CssImportDependency.js +0 -8
  27. package/lib/dependencies/CssLocalIdentifierDependency.js +69 -73
  28. package/lib/dependencies/CssUrlDependency.js +1 -0
  29. package/lib/esm/ModuleChunkFormatPlugin.js +8 -4
  30. package/lib/esm/ModuleChunkLoadingRuntimeModule.js +17 -10
  31. package/lib/index.js +9 -3
  32. package/lib/javascript/EnableChunkLoadingPlugin.js +2 -4
  33. package/lib/library/AssignLibraryPlugin.js +1 -1
  34. package/lib/library/EnableLibraryPlugin.js +17 -0
  35. package/lib/node/ReadFileCompileAsyncWasmPlugin.js +81 -78
  36. package/lib/node/ReadFileCompileWasmPlugin.js +76 -57
  37. package/lib/optimize/MergeDuplicateChunksPlugin.js +22 -2
  38. package/lib/sharing/ConsumeSharedPlugin.js +35 -12
  39. package/lib/sharing/utils.js +35 -4
  40. package/lib/stats/DefaultStatsFactoryPlugin.js +0 -5
  41. package/lib/util/Queue.js +52 -24
  42. package/lib/util/generateDebugId.js +33 -0
  43. package/lib/util/internalSerializables.js +6 -2
  44. package/lib/wasm/EnableWasmLoadingPlugin.js +36 -25
  45. package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +26 -2
  46. package/lib/wasm-async/UniversalCompileAsyncWasmPlugin.js +103 -0
  47. package/lib/wasm-sync/WebAssemblyParser.js +1 -1
  48. package/lib/web/FetchCompileAsyncWasmPlugin.js +43 -44
  49. package/lib/web/FetchCompileWasmPlugin.js +4 -4
  50. package/package.json +4 -4
  51. package/schemas/WebpackOptions.check.js +1 -1
  52. package/schemas/WebpackOptions.json +34 -12
  53. package/schemas/plugins/BannerPlugin.json +1 -1
  54. package/schemas/plugins/SourceMapDevToolPlugin.check.js +1 -1
  55. package/schemas/plugins/SourceMapDevToolPlugin.json +4 -0
  56. package/schemas/plugins/css/CssAutoParserOptions.check.js +1 -1
  57. package/schemas/plugins/css/CssGlobalParserOptions.check.js +1 -1
  58. package/schemas/plugins/css/CssModuleParserOptions.check.js +1 -1
  59. package/schemas/plugins/css/CssParserOptions.check.js +1 -1
  60. package/schemas/plugins/optimize/MergeDuplicateChunksPlugin.check.d.ts +7 -0
  61. package/schemas/plugins/optimize/MergeDuplicateChunksPlugin.check.js +6 -0
  62. package/schemas/plugins/optimize/MergeDuplicateChunksPlugin.json +11 -0
  63. package/types.d.ts +84 -23
  64. package/lib/css/CssExportsGenerator.js +0 -207
@@ -13,7 +13,9 @@ const Parser = require("../Parser");
13
13
  const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning");
14
14
  const WebpackError = require("../WebpackError");
15
15
  const ConstDependency = require("../dependencies/ConstDependency");
16
- const CssExportDependency = require("../dependencies/CssExportDependency");
16
+ const CssIcssExportDependency = require("../dependencies/CssIcssExportDependency");
17
+ const CssIcssImportDependency = require("../dependencies/CssIcssImportDependency");
18
+ const CssIcssSymbolDependency = require("../dependencies/CssIcssSymbolDependency");
17
19
  const CssImportDependency = require("../dependencies/CssImportDependency");
18
20
  const CssLocalIdentifierDependency = require("../dependencies/CssLocalIdentifierDependency");
19
21
  const CssSelfLocalIdentifierDependency = require("../dependencies/CssSelfLocalIdentifierDependency");
@@ -31,17 +33,18 @@ const walkCssTokens = require("./walkCssTokens");
31
33
  /** @typedef {import("../Module").BuildMeta} BuildMeta */
32
34
  /** @typedef {import("../Parser").ParserState} ParserState */
33
35
  /** @typedef {import("../Parser").PreparsedAst} PreparsedAst */
36
+ /** @typedef {import("./walkCssTokens").CssTokenCallbacks} CssTokenCallbacks */
34
37
 
35
38
  /** @typedef {[number, number]} Range */
36
39
  /** @typedef {{ line: number, column: number }} Position */
37
40
  /** @typedef {{ value: string, range: Range, loc: { start: Position, end: Position } }} Comment */
38
41
 
39
- const CC_LEFT_CURLY = "{".charCodeAt(0);
40
- const CC_RIGHT_CURLY = "}".charCodeAt(0);
41
42
  const CC_COLON = ":".charCodeAt(0);
42
43
  const CC_SLASH = "/".charCodeAt(0);
43
- const CC_SEMICOLON = ";".charCodeAt(0);
44
44
  const CC_LEFT_PARENTHESIS = "(".charCodeAt(0);
45
+ const CC_RIGHT_PARENTHESIS = ")".charCodeAt(0);
46
+ const CC_LOWER_F = "f".charCodeAt(0);
47
+ const CC_UPPER_F = "F".charCodeAt(0);
45
48
 
46
49
  // https://www.w3.org/TR/css-syntax-3/#newline
47
50
  // We don't have `preprocessing` stage, so we need specify all of them
@@ -54,6 +57,7 @@ const OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE = /^@(-\w+-)?keyframes$/;
54
57
  const OPTIONALLY_VENDOR_PREFIXED_ANIMATION_PROPERTY =
55
58
  /^(-\w+-)?animation(-name)?$/i;
56
59
  const IS_MODULES = /\.module(s)?\.[^.]+$/i;
60
+ const CSS_COMMENT = /\/\*((?!\*\/).*?)\*\//g;
57
61
 
58
62
  /**
59
63
  * @param {string} str url string
@@ -95,6 +99,136 @@ const normalizeUrl = (str, isString) => {
95
99
  return str;
96
100
  };
97
101
 
102
+ // eslint-disable-next-line no-useless-escape
103
+ const regexSingleEscape = /[ -,.\/:-@[\]\^`{-~]/;
104
+ const regexExcessiveSpaces =
105
+ /(^|\\+)?(\\[A-F0-9]{1,6})\u0020(?![a-fA-F0-9\u0020])/g;
106
+
107
+ /**
108
+ * @param {string} str string
109
+ * @returns {string} escaped identifier
110
+ */
111
+ const escapeIdentifier = str => {
112
+ let output = "";
113
+ let counter = 0;
114
+
115
+ while (counter < str.length) {
116
+ const character = str.charAt(counter++);
117
+
118
+ let value;
119
+
120
+ if (/[\t\n\f\r\u000B]/.test(character)) {
121
+ const codePoint = character.charCodeAt(0);
122
+
123
+ value = `\\${codePoint.toString(16).toUpperCase()} `;
124
+ } else if (character === "\\" || regexSingleEscape.test(character)) {
125
+ value = `\\${character}`;
126
+ } else {
127
+ value = character;
128
+ }
129
+
130
+ output += value;
131
+ }
132
+
133
+ const firstChar = str.charAt(0);
134
+
135
+ if (/^-[-\d]/.test(output)) {
136
+ output = `\\-${output.slice(1)}`;
137
+ } else if (/\d/.test(firstChar)) {
138
+ output = `\\3${firstChar} ${output.slice(1)}`;
139
+ }
140
+
141
+ // Remove spaces after `\HEX` escapes that are not followed by a hex digit,
142
+ // since they’re redundant. Note that this is only possible if the escape
143
+ // sequence isn’t preceded by an odd number of backslashes.
144
+ output = output.replace(regexExcessiveSpaces, ($0, $1, $2) => {
145
+ if ($1 && $1.length % 2) {
146
+ // It’s not safe to remove the space, so don’t.
147
+ return $0;
148
+ }
149
+
150
+ // Strip the space.
151
+ return ($1 || "") + $2;
152
+ });
153
+
154
+ return output;
155
+ };
156
+
157
+ const CONTAINS_ESCAPE = /\\/;
158
+
159
+ /**
160
+ * @param {string} str string
161
+ * @returns {[string, number] | undefined} hex
162
+ */
163
+ const gobbleHex = str => {
164
+ const lower = str.toLowerCase();
165
+ let hex = "";
166
+ let spaceTerminated = false;
167
+
168
+ for (let i = 0; i < 6 && lower[i] !== undefined; i++) {
169
+ const code = lower.charCodeAt(i);
170
+ // check to see if we are dealing with a valid hex char [a-f|0-9]
171
+ const valid = (code >= 97 && code <= 102) || (code >= 48 && code <= 57);
172
+ // https://drafts.csswg.org/css-syntax/#consume-escaped-code-point
173
+ spaceTerminated = code === 32;
174
+ if (!valid) break;
175
+ hex += lower[i];
176
+ }
177
+
178
+ if (hex.length === 0) return undefined;
179
+
180
+ const codePoint = Number.parseInt(hex, 16);
181
+ const isSurrogate = codePoint >= 0xd800 && codePoint <= 0xdfff;
182
+
183
+ // Add special case for
184
+ // "If this number is zero, or is for a surrogate, or is greater than the maximum allowed code point"
185
+ // https://drafts.csswg.org/css-syntax/#maximum-allowed-code-point
186
+ if (isSurrogate || codePoint === 0x0000 || codePoint > 0x10ffff) {
187
+ return ["\uFFFD", hex.length + (spaceTerminated ? 1 : 0)];
188
+ }
189
+
190
+ return [
191
+ String.fromCodePoint(codePoint),
192
+ hex.length + (spaceTerminated ? 1 : 0)
193
+ ];
194
+ };
195
+
196
+ /**
197
+ * @param {string} str string
198
+ * @returns {string} unescaped string
199
+ */
200
+ const unescapeIdentifier = str => {
201
+ const needToProcess = CONTAINS_ESCAPE.test(str);
202
+ if (!needToProcess) return str;
203
+ let ret = "";
204
+ for (let i = 0; i < str.length; i++) {
205
+ if (str[i] === "\\") {
206
+ const gobbled = gobbleHex(str.slice(i + 1, i + 7));
207
+ if (gobbled !== undefined) {
208
+ ret += gobbled[0];
209
+ i += gobbled[1];
210
+ continue;
211
+ }
212
+ // Retain a pair of \\ if double escaped `\\\\`
213
+ // https://github.com/postcss/postcss-selector-parser/commit/268c9a7656fb53f543dc620aa5b73a30ec3ff20e
214
+ if (str[i + 1] === "\\") {
215
+ ret += "\\";
216
+ i += 1;
217
+ continue;
218
+ }
219
+ // if \\ is at the end of the string retain it
220
+ // https://github.com/postcss/postcss-selector-parser/commit/01a6b346e3612ce1ab20219acc26abdc259ccefb
221
+ if (str.length === i + 1) {
222
+ ret += str[i];
223
+ }
224
+ continue;
225
+ }
226
+ ret += str[i];
227
+ }
228
+
229
+ return ret;
230
+ };
231
+
98
232
  class LocConverter {
99
233
  /**
100
234
  * @param {string} input input
@@ -145,15 +279,28 @@ const EMPTY_COMMENT_OPTIONS = {
145
279
  const CSS_MODE_TOP_LEVEL = 0;
146
280
  const CSS_MODE_IN_BLOCK = 1;
147
281
 
282
+ const eatUntilSemi = walkCssTokens.eatUntil(";");
283
+ const eatUntilLeftCurly = walkCssTokens.eatUntil("{");
284
+ const eatSemi = walkCssTokens.eatUntil(";");
285
+
148
286
  class CssParser extends Parser {
149
287
  /**
150
288
  * @param {object} options options
289
+ * @param {boolean=} options.importOption need handle `@import`
290
+ * @param {boolean=} options.url need handle URLs
151
291
  * @param {("pure" | "global" | "local" | "auto")=} options.defaultMode default mode
152
292
  * @param {boolean=} options.namedExports is named exports
153
293
  */
154
- constructor({ defaultMode = "pure", namedExports = true } = {}) {
294
+ constructor({
295
+ defaultMode = "pure",
296
+ importOption = true,
297
+ url = true,
298
+ namedExports = true
299
+ } = {}) {
155
300
  super();
156
301
  this.defaultMode = defaultMode;
302
+ this.import = importOption;
303
+ this.url = url;
157
304
  this.namedExports = namedExports;
158
305
  /** @type {Comment[] | undefined} */
159
306
  this.comments = undefined;
@@ -228,10 +375,12 @@ class CssParser extends Parser {
228
375
  let modeData;
229
376
  /** @type {boolean} */
230
377
  let inAnimationProperty = false;
231
- /** @type {Set<string>} */
232
- const declaredCssVariables = new Set();
233
378
  /** @type {[number, number, boolean] | undefined} */
234
379
  let lastIdentifier;
380
+ /** @type {Set<string>} */
381
+ const declaredCssVariables = new Set();
382
+ /** @type {Map<string, { path?: string, value: string }>} */
383
+ const icssDefinitions = new Map();
235
384
 
236
385
  /**
237
386
  * @param {string} input input
@@ -289,78 +438,156 @@ class CssParser extends Parser {
289
438
  }
290
439
  return [pos, text.trimEnd()];
291
440
  };
292
- const eatExportName = walkCssTokens.eatUntil(":};/");
293
- const eatExportValue = walkCssTokens.eatUntil("};/");
441
+
294
442
  /**
443
+ * @param {0 | 1} type import or export
295
444
  * @param {string} input input
296
445
  * @param {number} pos start position
297
446
  * @returns {number} position after parse
298
447
  */
299
- const parseExports = (input, pos) => {
448
+ const parseImportOrExport = (type, input, pos) => {
300
449
  pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
301
- const cc = input.charCodeAt(pos);
302
- if (cc !== CC_LEFT_CURLY) {
303
- this._emitWarning(
304
- state,
305
- `Unexpected '${input[pos]}' at ${pos} during parsing of ':export' (expected '{')`,
306
- locConverter,
307
- pos,
308
- pos
309
- );
310
- return pos;
311
- }
312
- pos++;
313
- pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
314
- for (;;) {
315
- if (input.charCodeAt(pos) === CC_RIGHT_CURLY) break;
316
- pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
317
- if (pos === input.length) return pos;
318
- const start = pos;
319
- let name;
320
- [pos, name] = eatText(input, pos, eatExportName);
321
- if (pos === input.length) return pos;
322
- if (input.charCodeAt(pos) !== CC_COLON) {
450
+ let importPath;
451
+ if (type === 0) {
452
+ let cc = input.charCodeAt(pos);
453
+ if (cc !== CC_LEFT_PARENTHESIS) {
323
454
  this._emitWarning(
324
455
  state,
325
- `Unexpected '${input[pos]}' at ${pos} during parsing of export name in ':export' (expected ':')`,
456
+ `Unexpected '${input[pos]}' at ${pos} during parsing of ':import' (expected '(')`,
326
457
  locConverter,
327
- start,
458
+ pos,
328
459
  pos
329
460
  );
330
461
  return pos;
331
462
  }
332
463
  pos++;
333
- if (pos === input.length) return pos;
464
+ const stringStart = pos;
465
+ const str = walkCssTokens.eatString(input, pos);
466
+ if (!str) {
467
+ this._emitWarning(
468
+ state,
469
+ `Unexpected '${input[pos]}' at ${pos} during parsing of ':import' (expected string)`,
470
+ locConverter,
471
+ stringStart,
472
+ pos
473
+ );
474
+ return pos;
475
+ }
476
+ importPath = input.slice(str[0] + 1, str[1] - 1);
477
+ pos = str[1];
334
478
  pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
335
- if (pos === input.length) return pos;
336
- let value;
337
- [pos, value] = eatText(input, pos, eatExportValue);
338
- if (pos === input.length) return pos;
339
- const cc = input.charCodeAt(pos);
340
- if (cc === CC_SEMICOLON) {
341
- pos++;
342
- if (pos === input.length) return pos;
343
- pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
344
- if (pos === input.length) return pos;
345
- } else if (cc !== CC_RIGHT_CURLY) {
479
+ cc = input.charCodeAt(pos);
480
+ if (cc !== CC_RIGHT_PARENTHESIS) {
346
481
  this._emitWarning(
347
482
  state,
348
- `Unexpected '${input[pos]}' at ${pos} during parsing of export value in ':export' (expected ';' or '}')`,
483
+ `Unexpected '${input[pos]}' at ${pos} during parsing of ':import' (expected ')')`,
349
484
  locConverter,
350
- start,
485
+ pos,
351
486
  pos
352
487
  );
353
488
  return pos;
354
489
  }
355
- const dep = new CssExportDependency(name, value);
356
- const { line: sl, column: sc } = locConverter.get(start);
357
- const { line: el, column: ec } = locConverter.get(pos);
358
- dep.setLoc(sl, sc, el, ec);
359
- module.addDependency(dep);
490
+ pos++;
491
+ pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
360
492
  }
361
- pos++;
362
- if (pos === input.length) return pos;
493
+
494
+ /**
495
+ * @param {string} name name
496
+ * @param {string} value value
497
+ * @param {number} start start of position
498
+ * @param {number} end end of position
499
+ */
500
+ const createDep = (name, value, start, end) => {
501
+ if (type === 0) {
502
+ icssDefinitions.set(name, {
503
+ path: /** @type {string} */ (importPath),
504
+ value
505
+ });
506
+ } else if (type === 1) {
507
+ const dep = new CssIcssExportDependency(name, value);
508
+ const { line: sl, column: sc } = locConverter.get(start);
509
+ const { line: el, column: ec } = locConverter.get(end);
510
+ dep.setLoc(sl, sc, el, ec);
511
+ module.addDependency(dep);
512
+ }
513
+ };
514
+
515
+ let needTerminate = false;
516
+ let balanced = 0;
517
+ /** @type {undefined | 0 | 1 | 2} */
518
+ let scope;
519
+
520
+ /** @type {[number, number] | undefined} */
521
+ let name;
522
+ /** @type {number | undefined} */
523
+ let value;
524
+
525
+ /** @type {CssTokenCallbacks} */
526
+ const callbacks = {
527
+ leftCurlyBracket: (_input, _start, end) => {
528
+ balanced++;
529
+
530
+ if (scope === undefined) {
531
+ scope = 0;
532
+ }
533
+
534
+ return end;
535
+ },
536
+ rightCurlyBracket: (_input, _start, end) => {
537
+ balanced--;
538
+
539
+ if (scope === 2) {
540
+ createDep(
541
+ input.slice(name[0], name[1]),
542
+ input.slice(value, end - 1).trim(),
543
+ name[1],
544
+ end - 1
545
+ );
546
+ scope = 0;
547
+ }
548
+
549
+ if (balanced === 0 && scope === 0) {
550
+ needTerminate = true;
551
+ }
552
+
553
+ return end;
554
+ },
555
+ identifier: (_input, start, end) => {
556
+ if (scope === 0) {
557
+ name = [start, end];
558
+ scope = 1;
559
+ }
560
+
561
+ return end;
562
+ },
563
+ colon: (_input, _start, end) => {
564
+ if (scope === 1) {
565
+ scope = 2;
566
+ value = walkCssTokens.eatWhitespace(input, end);
567
+ return value;
568
+ }
569
+
570
+ return end;
571
+ },
572
+ semicolon: (input, _start, end) => {
573
+ if (scope === 2) {
574
+ createDep(
575
+ input.slice(name[0], name[1]),
576
+ input.slice(value, end - 1),
577
+ name[1],
578
+ end - 1
579
+ );
580
+ scope = 0;
581
+ }
582
+
583
+ return end;
584
+ },
585
+ needTerminate: () => needTerminate
586
+ };
587
+
588
+ pos = walkCssTokens(input, pos, callbacks);
363
589
  pos = walkCssTokens.eatWhiteLine(input, pos);
590
+
364
591
  return pos;
365
592
  };
366
593
  const eatPropertyName = walkCssTokens.eatUntil(":{};");
@@ -381,11 +608,11 @@ class CssParser extends Parser {
381
608
  );
382
609
  if (input.charCodeAt(propertyNameEnd) !== CC_COLON) return end;
383
610
  pos = propertyNameEnd + 1;
384
- if (propertyName.startsWith("--")) {
611
+ if (propertyName.startsWith("--") && propertyName.length >= 3) {
385
612
  // CSS Variable
386
613
  const { line: sl, column: sc } = locConverter.get(propertyNameStart);
387
614
  const { line: el, column: ec } = locConverter.get(propertyNameEnd);
388
- const name = propertyName.slice(2);
615
+ const name = unescapeIdentifier(propertyName.slice(2));
389
616
  const dep = new CssLocalIdentifierDependency(
390
617
  name,
391
618
  [propertyNameStart, propertyNameEnd],
@@ -408,9 +635,11 @@ class CssParser extends Parser {
408
635
  if (inAnimationProperty && lastIdentifier) {
409
636
  const { line: sl, column: sc } = locConverter.get(lastIdentifier[0]);
410
637
  const { line: el, column: ec } = locConverter.get(lastIdentifier[1]);
411
- const name = lastIdentifier[2]
412
- ? input.slice(lastIdentifier[0], lastIdentifier[1])
413
- : input.slice(lastIdentifier[0] + 1, lastIdentifier[1] - 1);
638
+ const name = unescapeIdentifier(
639
+ lastIdentifier[2]
640
+ ? input.slice(lastIdentifier[0], lastIdentifier[1])
641
+ : input.slice(lastIdentifier[0] + 1, lastIdentifier[1] - 1)
642
+ );
414
643
  const dep = new CssSelfLocalIdentifierDependency(name, [
415
644
  lastIdentifier[0],
416
645
  lastIdentifier[1]
@@ -421,9 +650,6 @@ class CssParser extends Parser {
421
650
  }
422
651
  };
423
652
 
424
- const eatUntilSemi = walkCssTokens.eatUntil(";");
425
- const eatUntilLeftCurly = walkCssTokens.eatUntil("{");
426
-
427
653
  /**
428
654
  * @param {string} input input
429
655
  * @param {number} start start
@@ -448,7 +674,7 @@ class CssParser extends Parser {
448
674
  return end;
449
675
  };
450
676
 
451
- walkCssTokens(source, {
677
+ walkCssTokens(source, 0, {
452
678
  comment,
453
679
  leftCurlyBracket: (input, start, end) => {
454
680
  switch (scope) {
@@ -497,6 +723,10 @@ class CssParser extends Parser {
497
723
  return end;
498
724
  },
499
725
  url: (input, start, end, contentStart, contentEnd) => {
726
+ if (!this.url) {
727
+ return end;
728
+ }
729
+
500
730
  const { options, errors: commentErrors } = this.parseCommentOptions([
501
731
  lastTokenEndForComments,
502
732
  end
@@ -572,6 +802,10 @@ class CssParser extends Parser {
572
802
  return eatUntilSemi(input, start);
573
803
  }
574
804
  case "@import": {
805
+ if (!this.import) {
806
+ return eatSemi(input, end);
807
+ }
808
+
575
809
  if (!allowImportAtRule) {
576
810
  this._emitWarning(
577
811
  state,
@@ -687,48 +921,129 @@ class CssParser extends Parser {
687
921
  }
688
922
  default: {
689
923
  if (isModules) {
690
- if (OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE.test(name)) {
924
+ if (name === "@value") {
925
+ const semi = eatUntilSemi(input, end);
926
+ const atRuleEnd = semi + 1;
927
+ const params = input.slice(end, semi);
928
+ let [alias, from] = params.split(/\s*from\s*/);
929
+
930
+ if (from) {
931
+ const aliases = alias
932
+ .replace(CSS_COMMENT, " ")
933
+ .trim()
934
+ .replace(/^\(|\)$/g, "")
935
+ .split(/\s*,\s*/);
936
+
937
+ from = from.replace(CSS_COMMENT, "").trim();
938
+
939
+ const isExplicitImport = from[0] === "'" || from[0] === '"';
940
+
941
+ if (isExplicitImport) {
942
+ from = from.slice(1, -1);
943
+ }
944
+
945
+ for (const alias of aliases) {
946
+ const [name, aliasName] = alias.split(/\s*as\s*/);
947
+
948
+ icssDefinitions.set(aliasName || name, {
949
+ value: name,
950
+ path: from
951
+ });
952
+ }
953
+ } else {
954
+ const ident = walkCssTokens.eatIdentSequence(alias, 0);
955
+
956
+ if (!ident) {
957
+ this._emitWarning(
958
+ state,
959
+ `Broken '@value' at-rule: ${input.slice(
960
+ start,
961
+ atRuleEnd
962
+ )}'`,
963
+ locConverter,
964
+ start,
965
+ atRuleEnd
966
+ );
967
+
968
+ const dep = new ConstDependency("", [start, atRuleEnd]);
969
+ module.addPresentationalDependency(dep);
970
+ return atRuleEnd;
971
+ }
972
+
973
+ const pos = walkCssTokens.eatWhitespaceAndComments(
974
+ alias,
975
+ ident[1]
976
+ );
977
+
978
+ const name = alias.slice(ident[0], ident[1]);
979
+ let value =
980
+ alias.charCodeAt(pos) === CC_COLON
981
+ ? alias.slice(pos + 1)
982
+ : alias.slice(ident[1]);
983
+
984
+ if (value && !/^\s+$/.test(value)) {
985
+ value = value.trim();
986
+ }
987
+
988
+ if (icssDefinitions.has(value)) {
989
+ const def = icssDefinitions.get(value);
990
+
991
+ value = def.value;
992
+ }
993
+
994
+ icssDefinitions.set(name, { value });
995
+
996
+ const dep = new CssIcssExportDependency(name, value);
997
+ const { line: sl, column: sc } = locConverter.get(start);
998
+ const { line: el, column: ec } = locConverter.get(end);
999
+ dep.setLoc(sl, sc, el, ec);
1000
+ module.addDependency(dep);
1001
+ }
1002
+
1003
+ const dep = new ConstDependency("", [start, atRuleEnd]);
1004
+ module.addPresentationalDependency(dep);
1005
+ return atRuleEnd;
1006
+ } else if (
1007
+ OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE.test(name) &&
1008
+ isLocalMode()
1009
+ ) {
691
1010
  const ident = walkCssTokens.eatIdentSequenceOrString(
692
1011
  input,
693
1012
  end
694
1013
  );
695
1014
  if (!ident) return end;
696
- const name =
1015
+ const name = unescapeIdentifier(
697
1016
  ident[2] === true
698
1017
  ? input.slice(ident[0], ident[1])
699
- : input.slice(ident[0] + 1, ident[1] - 1);
700
- if (isLocalMode()) {
701
- const { line: sl, column: sc } = locConverter.get(ident[0]);
702
- const { line: el, column: ec } = locConverter.get(ident[1]);
703
- const dep = new CssLocalIdentifierDependency(name, [
704
- ident[0],
705
- ident[1]
706
- ]);
707
- dep.setLoc(sl, sc, el, ec);
708
- module.addDependency(dep);
709
- }
1018
+ : input.slice(ident[0] + 1, ident[1] - 1)
1019
+ );
1020
+ const { line: sl, column: sc } = locConverter.get(ident[0]);
1021
+ const { line: el, column: ec } = locConverter.get(ident[1]);
1022
+ const dep = new CssLocalIdentifierDependency(name, [
1023
+ ident[0],
1024
+ ident[1]
1025
+ ]);
1026
+ dep.setLoc(sl, sc, el, ec);
1027
+ module.addDependency(dep);
710
1028
  return ident[1];
711
- } else if (name === "@property") {
1029
+ } else if (name === "@property" && isLocalMode()) {
712
1030
  const ident = walkCssTokens.eatIdentSequence(input, end);
713
1031
  if (!ident) return end;
714
1032
  let name = input.slice(ident[0], ident[1]);
715
- if (!name.startsWith("--")) return end;
716
- name = name.slice(2);
1033
+ if (!name.startsWith("--") || name.length < 3) return end;
1034
+ name = unescapeIdentifier(name.slice(2));
717
1035
  declaredCssVariables.add(name);
718
- if (isLocalMode()) {
719
- const { line: sl, column: sc } = locConverter.get(ident[0]);
720
- const { line: el, column: ec } = locConverter.get(ident[1]);
721
- const dep = new CssLocalIdentifierDependency(
722
- name,
723
- [ident[0], ident[1]],
724
- "--"
725
- );
726
- dep.setLoc(sl, sc, el, ec);
727
- module.addDependency(dep);
728
- }
1036
+ const { line: sl, column: sc } = locConverter.get(ident[0]);
1037
+ const { line: el, column: ec } = locConverter.get(ident[1]);
1038
+ const dep = new CssLocalIdentifierDependency(
1039
+ name,
1040
+ [ident[0], ident[1]],
1041
+ "--"
1042
+ );
1043
+ dep.setLoc(sl, sc, el, ec);
1044
+ module.addDependency(dep);
729
1045
  return ident[1];
730
- } else if (isModules && name === "@scope") {
731
- modeData = isLocalMode() ? "local" : "global";
1046
+ } else if (name === "@scope") {
732
1047
  isNextRulePrelude = true;
733
1048
  return end;
734
1049
  }
@@ -752,19 +1067,55 @@ class CssParser extends Parser {
752
1067
  return end;
753
1068
  },
754
1069
  identifier: (input, start, end) => {
755
- switch (scope) {
756
- case CSS_MODE_IN_BLOCK: {
757
- if (isLocalMode()) {
758
- // Handle only top level values and not inside functions
759
- if (inAnimationProperty && balanced.length === 0) {
760
- lastIdentifier = [start, end, true];
761
- } else {
762
- return processLocalDeclaration(input, start, end);
1070
+ if (isModules) {
1071
+ if (icssDefinitions.has(input.slice(start, end))) {
1072
+ const name = input.slice(start, end);
1073
+ let { path, value } = icssDefinitions.get(name);
1074
+
1075
+ if (path) {
1076
+ if (icssDefinitions.has(path)) {
1077
+ const definition = icssDefinitions.get(path);
1078
+
1079
+ path = definition.value.slice(1, -1);
763
1080
  }
1081
+
1082
+ const dep = new CssIcssImportDependency(path, value, [
1083
+ start,
1084
+ end - 1
1085
+ ]);
1086
+ const { line: sl, column: sc } = locConverter.get(start);
1087
+ const { line: el, column: ec } = locConverter.get(end - 1);
1088
+ dep.setLoc(sl, sc, el, ec);
1089
+ module.addDependency(dep);
1090
+ } else {
1091
+ const { line: sl, column: sc } = locConverter.get(start);
1092
+ const { line: el, column: ec } = locConverter.get(end);
1093
+ const dep = new CssIcssSymbolDependency(name, value, [
1094
+ start,
1095
+ end
1096
+ ]);
1097
+ dep.setLoc(sl, sc, el, ec);
1098
+ module.addDependency(dep);
1099
+ }
1100
+
1101
+ return end;
1102
+ }
1103
+
1104
+ switch (scope) {
1105
+ case CSS_MODE_IN_BLOCK: {
1106
+ if (isLocalMode()) {
1107
+ // Handle only top level values and not inside functions
1108
+ if (inAnimationProperty && balanced.length === 0) {
1109
+ lastIdentifier = [start, end, true];
1110
+ } else {
1111
+ return processLocalDeclaration(input, start, end);
1112
+ }
1113
+ }
1114
+ break;
764
1115
  }
765
- break;
766
1116
  }
767
1117
  }
1118
+
768
1119
  return end;
769
1120
  },
770
1121
  delim: (input, start, end) => {
@@ -774,7 +1125,7 @@ class CssParser extends Parser {
774
1125
  end
775
1126
  );
776
1127
  if (!ident) return end;
777
- const name = input.slice(ident[0], ident[1]);
1128
+ const name = unescapeIdentifier(input.slice(ident[0], ident[1]));
778
1129
  const dep = new CssLocalIdentifierDependency(name, [
779
1130
  ident[0],
780
1131
  ident[1]
@@ -791,7 +1142,7 @@ class CssParser extends Parser {
791
1142
  hash: (input, start, end, isID) => {
792
1143
  if (isNextRulePrelude && isLocalMode() && isID) {
793
1144
  const valueStart = start + 1;
794
- const name = input.slice(valueStart, end);
1145
+ const name = unescapeIdentifier(input.slice(valueStart, end));
795
1146
  const dep = new CssLocalIdentifierDependency(name, [valueStart, end]);
796
1147
  const { line: sl, column: sc } = locConverter.get(start);
797
1148
  const { line: el, column: ec } = locConverter.get(end);
@@ -812,8 +1163,13 @@ class CssParser extends Parser {
812
1163
 
813
1164
  switch (scope) {
814
1165
  case CSS_MODE_TOP_LEVEL: {
815
- if (name === "export") {
816
- const pos = parseExports(input, ident[1]);
1166
+ if (name === "import") {
1167
+ const pos = parseImportOrExport(0, input, ident[1]);
1168
+ const dep = new ConstDependency("", [start, pos]);
1169
+ module.addPresentationalDependency(dep);
1170
+ return pos;
1171
+ } else if (name === "export") {
1172
+ const pos = parseImportOrExport(1, input, ident[1]);
817
1173
  const dep = new ConstDependency("", [start, pos]);
818
1174
  module.addPresentationalDependency(dep);
819
1175
  return pos;
@@ -901,6 +1257,10 @@ class CssParser extends Parser {
901
1257
  switch (name) {
902
1258
  case "src":
903
1259
  case "url": {
1260
+ if (!this.url) {
1261
+ return end;
1262
+ }
1263
+
904
1264
  const string = walkCssTokens.eatString(input, end);
905
1265
  if (!string) return end;
906
1266
  const { options, errors: commentErrors } = this.parseCommentOptions(
@@ -955,7 +1315,7 @@ class CssParser extends Parser {
955
1315
  return string[1];
956
1316
  }
957
1317
  default: {
958
- if (IMAGE_SET_FUNCTION.test(name)) {
1318
+ if (this.url && IMAGE_SET_FUNCTION.test(name)) {
959
1319
  lastTokenEndForComments = end;
960
1320
  const values = walkCssTokens.eatImageSetStrings(input, end, {
961
1321
  comment
@@ -1025,21 +1385,83 @@ class CssParser extends Parser {
1025
1385
  }
1026
1386
 
1027
1387
  if (name === "var") {
1028
- const ident = walkCssTokens.eatIdentSequence(input, end);
1029
- if (!ident) return end;
1030
- const name = input.slice(ident[0], ident[1]);
1031
- if (!name.startsWith("--")) return end;
1032
- const { line: sl, column: sc } = locConverter.get(ident[0]);
1033
- const { line: el, column: ec } = locConverter.get(ident[1]);
1034
- const dep = new CssSelfLocalIdentifierDependency(
1035
- name.slice(2),
1036
- [ident[0], ident[1]],
1037
- "--",
1038
- declaredCssVariables
1388
+ const customIdent = walkCssTokens.eatIdentSequence(input, end);
1389
+ if (!customIdent) return end;
1390
+ let name = input.slice(customIdent[0], customIdent[1]);
1391
+ // A custom property is any property whose name starts with two dashes (U+002D HYPHEN-MINUS), like --foo.
1392
+ // The <custom-property-name> production corresponds to this:
1393
+ // it’s defined as any <dashed-ident> (a valid identifier that starts with two dashes),
1394
+ // except -- itself, which is reserved for future use by CSS.
1395
+ if (!name.startsWith("--") || name.length < 3) return end;
1396
+ name = unescapeIdentifier(
1397
+ input.slice(customIdent[0] + 2, customIdent[1])
1039
1398
  );
1040
- dep.setLoc(sl, sc, el, ec);
1041
- module.addDependency(dep);
1042
- return ident[1];
1399
+ const afterCustomIdent = walkCssTokens.eatWhitespaceAndComments(
1400
+ input,
1401
+ customIdent[1]
1402
+ );
1403
+ if (
1404
+ input.charCodeAt(afterCustomIdent) === CC_LOWER_F ||
1405
+ input.charCodeAt(afterCustomIdent) === CC_UPPER_F
1406
+ ) {
1407
+ const fromWord = walkCssTokens.eatIdentSequence(
1408
+ input,
1409
+ afterCustomIdent
1410
+ );
1411
+ if (
1412
+ !fromWord ||
1413
+ input.slice(fromWord[0], fromWord[1]).toLowerCase() !==
1414
+ "from"
1415
+ ) {
1416
+ return end;
1417
+ }
1418
+ const from = walkCssTokens.eatIdentSequenceOrString(
1419
+ input,
1420
+ walkCssTokens.eatWhitespaceAndComments(input, fromWord[1])
1421
+ );
1422
+ if (!from) {
1423
+ return end;
1424
+ }
1425
+ const path = input.slice(from[0], from[1]);
1426
+ if (from[2] === true && path === "global") {
1427
+ const dep = new ConstDependency("", [
1428
+ customIdent[1],
1429
+ from[1]
1430
+ ]);
1431
+ module.addPresentationalDependency(dep);
1432
+ return end;
1433
+ } else if (from[2] === false) {
1434
+ const dep = new CssIcssImportDependency(
1435
+ path.slice(1, -1),
1436
+ name,
1437
+ [customIdent[0], from[1] - 1]
1438
+ );
1439
+ const { line: sl, column: sc } = locConverter.get(
1440
+ customIdent[0]
1441
+ );
1442
+ const { line: el, column: ec } = locConverter.get(
1443
+ from[1] - 1
1444
+ );
1445
+ dep.setLoc(sl, sc, el, ec);
1446
+ module.addDependency(dep);
1447
+ }
1448
+ } else {
1449
+ const { line: sl, column: sc } = locConverter.get(
1450
+ customIdent[0]
1451
+ );
1452
+ const { line: el, column: ec } = locConverter.get(
1453
+ customIdent[1]
1454
+ );
1455
+ const dep = new CssSelfLocalIdentifierDependency(
1456
+ name,
1457
+ [customIdent[0], customIdent[1]],
1458
+ "--",
1459
+ declaredCssVariables
1460
+ );
1461
+ dep.setLoc(sl, sc, el, ec);
1462
+ module.addDependency(dep);
1463
+ return end;
1464
+ }
1043
1465
  }
1044
1466
  }
1045
1467
  }
@@ -1176,3 +1598,5 @@ class CssParser extends Parser {
1176
1598
  }
1177
1599
 
1178
1600
  module.exports = CssParser;
1601
+ module.exports.escapeIdentifier = escapeIdentifier;
1602
+ module.exports.unescapeIdentifier = unescapeIdentifier;