webpack 5.81.0 → 5.82.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of webpack might be problematic. Click here for more details.

Files changed (62) hide show
  1. package/bin/webpack.js +13 -2
  2. package/lib/Compilation.js +4 -1
  3. package/lib/CssModule.js +39 -7
  4. package/lib/DependenciesBlock.js +8 -0
  5. package/lib/FileSystemInfo.js +1 -1
  6. package/lib/HotModuleReplacementPlugin.js +3 -2
  7. package/lib/Module.js +3 -2
  8. package/lib/ModuleTypeConstants.js +90 -0
  9. package/lib/NormalModule.js +2 -1
  10. package/lib/RuntimeModule.js +4 -3
  11. package/lib/Template.js +2 -1
  12. package/lib/WebpackOptionsApply.js +33 -40
  13. package/lib/asset/AssetGenerator.js +4 -3
  14. package/lib/asset/AssetModulesPlugin.js +21 -11
  15. package/lib/asset/RawDataUrlModule.js +2 -1
  16. package/lib/cache/MemoryWithGcCachePlugin.js +2 -0
  17. package/lib/config/defaults.js +4 -2
  18. package/lib/container/FallbackModule.js +2 -1
  19. package/lib/container/RemoteModule.js +2 -1
  20. package/lib/css/CssGenerator.js +4 -0
  21. package/lib/css/CssLoadingRuntimeModule.js +9 -2
  22. package/lib/css/CssModulesPlugin.js +149 -39
  23. package/lib/css/CssParser.js +443 -319
  24. package/lib/css/walkCssTokens.js +118 -27
  25. package/lib/debug/ProfilingPlugin.js +2 -0
  26. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +1 -0
  27. package/lib/esm/ModuleChunkLoadingRuntimeModule.js +4 -2
  28. package/lib/hmr/LazyCompilationPlugin.js +13 -4
  29. package/lib/javascript/BasicEvaluatedExpression.js +108 -1
  30. package/lib/javascript/JavascriptModulesPlugin.js +3 -2
  31. package/lib/javascript/JavascriptParser.js +132 -11
  32. package/lib/json/JsonData.js +25 -0
  33. package/lib/json/JsonGenerator.js +15 -3
  34. package/lib/json/JsonModulesPlugin.js +1 -0
  35. package/lib/json/JsonParser.js +2 -1
  36. package/lib/library/ModuleLibraryPlugin.js +2 -1
  37. package/lib/node/ReadFileChunkLoadingRuntimeModule.js +3 -1
  38. package/lib/runtime/GetChunkFilenameRuntimeModule.js +4 -0
  39. package/lib/runtime/GetTrustedTypesPolicyRuntimeModule.js +22 -3
  40. package/lib/schemes/DataUriPlugin.js +4 -0
  41. package/lib/schemes/HttpUriPlugin.js +38 -0
  42. package/lib/sharing/ConsumeSharedModule.js +5 -2
  43. package/lib/sharing/ProvideSharedModule.js +2 -1
  44. package/lib/sharing/utils.js +293 -7
  45. package/lib/stats/DefaultStatsFactoryPlugin.js +7 -4
  46. package/lib/stats/DefaultStatsPrinterPlugin.js +25 -0
  47. package/lib/util/StackedCacheMap.js +6 -0
  48. package/lib/util/StringXor.js +51 -0
  49. package/lib/util/compileBooleanMatcher.js +31 -0
  50. package/lib/util/createHash.js +4 -3
  51. package/lib/util/deprecation.js +8 -0
  52. package/lib/util/identifier.js +4 -0
  53. package/lib/util/numberHash.js +75 -21
  54. package/lib/util/propertyAccess.js +5 -0
  55. package/lib/wasm/EnableWasmLoadingPlugin.js +4 -0
  56. package/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js +1 -0
  57. package/lib/wasm-async/AsyncWebAssemblyParser.js +1 -1
  58. package/lib/web/JsonpChunkLoadingRuntimeModule.js +8 -4
  59. package/package.json +3 -3
  60. package/schemas/WebpackOptions.check.js +1 -1
  61. package/schemas/WebpackOptions.json +25 -0
  62. package/types.d.ts +181 -39
@@ -5,7 +5,9 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ const ModuleDependencyWarning = require("../ModuleDependencyWarning");
8
9
  const Parser = require("../Parser");
10
+ const WebpackError = require("../WebpackError");
9
11
  const ConstDependency = require("../dependencies/ConstDependency");
10
12
  const CssExportDependency = require("../dependencies/CssExportDependency");
11
13
  const CssImportDependency = require("../dependencies/CssImportDependency");
@@ -34,6 +36,11 @@ const OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE = /^@(-\w+-)?keyframes$/;
34
36
  const OPTIONALLY_VENDOR_PREFIXED_ANIMATION_PROPERTY =
35
37
  /^(-\w+-)?animation(-name)?$/i;
36
38
 
39
+ /**
40
+ * @param {string} str url string
41
+ * @param {boolean} isString is url wrapped in quotes
42
+ * @returns {string} normalized url
43
+ */
37
44
  const normalizeUrl = (str, isString) => {
38
45
  // Remove extra spaces and newlines:
39
46
  // `url("im\
@@ -71,6 +78,9 @@ const normalizeUrl = (str, isString) => {
71
78
  };
72
79
 
73
80
  class LocConverter {
81
+ /**
82
+ * @param {string} input input
83
+ */
74
84
  constructor(input) {
75
85
  this._input = input;
76
86
  this.line = 1;
@@ -78,6 +88,10 @@ class LocConverter {
78
88
  this.pos = 0;
79
89
  }
80
90
 
91
+ /**
92
+ * @param {number} pos position
93
+ * @returns {LocConverter} location converter
94
+ */
81
95
  get(pos) {
82
96
  if (this.pos !== pos) {
83
97
  if (this.pos < pos) {
@@ -106,43 +120,38 @@ class LocConverter {
106
120
  }
107
121
 
108
122
  const CSS_MODE_TOP_LEVEL = 0;
109
- const CSS_MODE_IN_RULE = 1;
110
- const CSS_MODE_IN_LOCAL_RULE = 2;
111
- const CSS_MODE_AT_IMPORT_EXPECT_URL = 3;
112
- const CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA = 4;
113
- const CSS_MODE_AT_OTHER = 5;
114
-
115
- const explainMode = mode => {
116
- switch (mode) {
117
- case CSS_MODE_TOP_LEVEL:
118
- return "parsing top level css";
119
- case CSS_MODE_IN_RULE:
120
- return "parsing css rule content (global)";
121
- case CSS_MODE_IN_LOCAL_RULE:
122
- return "parsing css rule content (local)";
123
- case CSS_MODE_AT_IMPORT_EXPECT_URL:
124
- return "parsing @import (expecting url)";
125
- case CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA:
126
- return "parsing @import (expecting optionally layer, supports or media query)";
127
- case CSS_MODE_AT_OTHER:
128
- return "parsing at-rule";
129
- default:
130
- return mode;
131
- }
132
- };
123
+ const CSS_MODE_IN_BLOCK = 1;
124
+ const CSS_MODE_AT_IMPORT_EXPECT_URL = 2;
125
+ const CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA = 3;
126
+ const CSS_MODE_AT_IMPORT_INVALID = 4;
127
+ const CSS_MODE_AT_NAMESPACE_INVALID = 5;
133
128
 
134
129
  class CssParser extends Parser {
135
- constructor({
136
- allowPseudoBlocks = true,
137
- allowModeSwitch = true,
138
- defaultMode = "global"
139
- } = {}) {
130
+ constructor({ allowModeSwitch = true, defaultMode = "global" } = {}) {
140
131
  super();
141
- this.allowPseudoBlocks = allowPseudoBlocks;
142
132
  this.allowModeSwitch = allowModeSwitch;
143
133
  this.defaultMode = defaultMode;
144
134
  }
145
135
 
136
+ /**
137
+ * @param {ParserState} state parser state
138
+ * @param {string} message warning message
139
+ * @param {LocConverter} locConverter location converter
140
+ * @param {number} start start offset
141
+ * @param {number} end end offset
142
+ */
143
+ _emitWarning(state, message, locConverter, start, end) {
144
+ const { line: sl, column: sc } = locConverter.get(start);
145
+ const { line: el, column: ec } = locConverter.get(end);
146
+
147
+ state.current.addWarning(
148
+ new ModuleDependencyWarning(state.module, new WebpackError(message), {
149
+ start: { line: sl, column: sc },
150
+ end: { line: el, column: ec }
151
+ })
152
+ );
153
+ }
154
+
146
155
  /**
147
156
  * @param {string | Buffer | PreparsedAst} source the source to parse
148
157
  * @param {ParserState} state the parser state
@@ -159,35 +168,57 @@ class CssParser extends Parser {
159
168
  }
160
169
 
161
170
  const module = state.module;
162
-
163
- const declaredCssVariables = new Set();
164
-
165
171
  const locConverter = new LocConverter(source);
166
- let mode = CSS_MODE_TOP_LEVEL;
167
- let modeNestingLevel = 0;
172
+ /** @type {Set<string>}*/
173
+ const declaredCssVariables = new Set();
174
+ /** @type {number} */
175
+ let scope = CSS_MODE_TOP_LEVEL;
176
+ /** @type {number} */
177
+ let blockNestingLevel = 0;
178
+ /** @type {boolean} */
179
+ let allowImportAtRule = true;
180
+ /** @type {"local" | "global" | undefined} */
168
181
  let modeData = undefined;
169
- let singleClassSelector = undefined;
182
+ /** @type {[number, number] | undefined} */
170
183
  let lastIdentifier = undefined;
171
- let awaitRightParenthesis = false;
172
184
  /** @type [string, number, number][] */
173
185
  let balanced = [];
174
- const modeStack = [];
186
+ /** @type {undefined | { start: number, end: number, url?: string, media?: string, supports?: string, layer?: string }} */
187
+ let importData = undefined;
188
+ /** @type {boolean} */
189
+ let inAnimationProperty = false;
190
+ /** @type {boolean} */
191
+ let isNextRulePrelude = true;
192
+
193
+ /**
194
+ * @param {string} input input
195
+ * @param {number} pos position
196
+ * @returns {boolean} true, when next is nested syntax
197
+ */
198
+ const isNextNestedSyntax = (input, pos) => {
199
+ pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
175
200
 
176
- const isTopLevelLocal = () =>
177
- modeData === "local" ||
178
- (this.defaultMode === "local" && modeData === undefined);
179
- const eatWhiteLine = (input, pos) => {
180
- for (;;) {
181
- const cc = input.charCodeAt(pos);
182
- if (cc === 32 || cc === 9) {
183
- pos++;
184
- continue;
185
- }
186
- if (cc === 10) pos++;
187
- break;
201
+ if (input[pos] === "}") {
202
+ return false;
188
203
  }
189
- return pos;
204
+
205
+ // According spec only identifier can be used as a property name
206
+ const isIdentifier = walkCssTokens.isIdentStartCodePoint(
207
+ input.charCodeAt(pos)
208
+ );
209
+
210
+ return !isIdentifier;
190
211
  };
212
+ /**
213
+ * @returns {boolean} true, when in local scope
214
+ */
215
+ const isLocalMode = () =>
216
+ modeData === "local" ||
217
+ (this.defaultMode === "local" && modeData === undefined);
218
+ /**
219
+ * @param {string} chars characters
220
+ * @returns {(input: string, pos: number) => number} function to eat characters
221
+ */
191
222
  const eatUntil = chars => {
192
223
  const charCodes = Array.from({ length: chars.length }, (_, i) =>
193
224
  chars.charCodeAt(i)
@@ -208,6 +239,12 @@ class CssParser extends Parser {
208
239
  }
209
240
  };
210
241
  };
242
+ /**
243
+ * @param {string} input input
244
+ * @param {number} pos start position
245
+ * @param {(input: string, pos: number) => number} eater eater
246
+ * @returns {[number,string]} new position and text
247
+ */
211
248
  const eatText = (input, pos, eater) => {
212
249
  let text = "";
213
250
  for (;;) {
@@ -235,13 +272,24 @@ class CssParser extends Parser {
235
272
  };
236
273
  const eatExportName = eatUntil(":};/");
237
274
  const eatExportValue = eatUntil("};/");
275
+ /**
276
+ * @param {string} input input
277
+ * @param {number} pos start position
278
+ * @returns {number} position after parse
279
+ */
238
280
  const parseExports = (input, pos) => {
239
281
  pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
240
282
  const cc = input.charCodeAt(pos);
241
- if (cc !== CC_LEFT_CURLY)
242
- throw new Error(
243
- `Unexpected ${input[pos]} at ${pos} during parsing of ':export' (expected '{')`
283
+ if (cc !== CC_LEFT_CURLY) {
284
+ this._emitWarning(
285
+ state,
286
+ `Unexpected '${input[pos]}' at ${pos} during parsing of ':export' (expected '{')`,
287
+ locConverter,
288
+ pos,
289
+ pos
244
290
  );
291
+ return pos;
292
+ }
245
293
  pos++;
246
294
  pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
247
295
  for (;;) {
@@ -253,9 +301,14 @@ class CssParser extends Parser {
253
301
  [pos, name] = eatText(input, pos, eatExportName);
254
302
  if (pos === input.length) return pos;
255
303
  if (input.charCodeAt(pos) !== CC_COLON) {
256
- throw new Error(
257
- `Unexpected ${input[pos]} at ${pos} during parsing of export name in ':export' (expected ':')`
304
+ this._emitWarning(
305
+ state,
306
+ `Unexpected '${input[pos]}' at ${pos} during parsing of export name in ':export' (expected ':')`,
307
+ locConverter,
308
+ start,
309
+ pos
258
310
  );
311
+ return pos;
259
312
  }
260
313
  pos++;
261
314
  if (pos === input.length) return pos;
@@ -271,9 +324,14 @@ class CssParser extends Parser {
271
324
  pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
272
325
  if (pos === input.length) return pos;
273
326
  } else if (cc !== CC_RIGHT_CURLY) {
274
- throw new Error(
275
- `Unexpected ${input[pos]} at ${pos} during parsing of export value in ':export' (expected ';' or '}')`
327
+ this._emitWarning(
328
+ state,
329
+ `Unexpected '${input[pos]}' at ${pos} during parsing of export value in ':export' (expected ';' or '}')`,
330
+ locConverter,
331
+ start,
332
+ pos
276
333
  );
334
+ return pos;
277
335
  }
278
336
  const dep = new CssExportDependency(name, value);
279
337
  const { line: sl, column: sc } = locConverter.get(start);
@@ -283,13 +341,18 @@ class CssParser extends Parser {
283
341
  }
284
342
  pos++;
285
343
  if (pos === input.length) return pos;
286
- pos = eatWhiteLine(input, pos);
344
+ pos = walkCssTokens.eatWhiteLine(input, pos);
287
345
  return pos;
288
346
  };
289
347
  const eatPropertyName = eatUntil(":{};");
290
- const processLocalDeclaration = (input, pos) => {
348
+ /**
349
+ * @param {string} input input
350
+ * @param {number} pos name start position
351
+ * @param {number} end name end position
352
+ * @returns {number} position after handling
353
+ */
354
+ const processLocalDeclaration = (input, pos, end) => {
291
355
  modeData = undefined;
292
- const start = pos;
293
356
  pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
294
357
  const propertyNameStart = pos;
295
358
  const [propertyNameEnd, propertyName] = eatText(
@@ -297,7 +360,7 @@ class CssParser extends Parser {
297
360
  pos,
298
361
  eatPropertyName
299
362
  );
300
- if (input.charCodeAt(propertyNameEnd) !== CC_COLON) return start;
363
+ if (input.charCodeAt(propertyNameEnd) !== CC_COLON) return end;
301
364
  pos = propertyNameEnd + 1;
302
365
  if (propertyName.startsWith("--")) {
303
366
  // CSS Variable
@@ -313,58 +376,54 @@ class CssParser extends Parser {
313
376
  module.addDependency(dep);
314
377
  declaredCssVariables.add(name);
315
378
  } else if (
379
+ !propertyName.startsWith("--") &&
316
380
  OPTIONALLY_VENDOR_PREFIXED_ANIMATION_PROPERTY.test(propertyName)
317
381
  ) {
318
- modeData = "animation";
319
- lastIdentifier = undefined;
382
+ inAnimationProperty = true;
320
383
  }
321
384
  return pos;
322
385
  };
323
- const processDeclarationValueDone = (input, pos) => {
324
- if (modeData === "animation" && lastIdentifier) {
386
+ /**
387
+ * @param {string} input input
388
+ */
389
+ const processDeclarationValueDone = input => {
390
+ if (inAnimationProperty && lastIdentifier) {
325
391
  const { line: sl, column: sc } = locConverter.get(lastIdentifier[0]);
326
392
  const { line: el, column: ec } = locConverter.get(lastIdentifier[1]);
327
393
  const name = input.slice(lastIdentifier[0], lastIdentifier[1]);
328
394
  const dep = new CssSelfLocalIdentifierDependency(name, lastIdentifier);
329
395
  dep.setLoc(sl, sc, el, ec);
330
396
  module.addDependency(dep);
397
+ lastIdentifier = undefined;
331
398
  }
332
399
  };
333
- const eatAtRuleNested = eatUntil("{};/");
334
400
  const eatKeyframes = eatUntil("{};/");
335
401
  const eatNameInVar = eatUntil(",)};/");
336
402
  walkCssTokens(source, {
337
403
  isSelector: () => {
338
- return (
339
- mode !== CSS_MODE_IN_RULE &&
340
- mode !== CSS_MODE_IN_LOCAL_RULE &&
341
- mode !== CSS_MODE_AT_IMPORT_EXPECT_URL &&
342
- mode !== CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA
343
- );
404
+ return isNextRulePrelude;
344
405
  },
345
- url: (input, start, end, contentStart, contentEnd, isString) => {
346
- let value = normalizeUrl(
347
- input.slice(contentStart, contentEnd),
348
- isString
349
- );
350
- switch (mode) {
406
+ url: (input, start, end, contentStart, contentEnd) => {
407
+ let value = normalizeUrl(input.slice(contentStart, contentEnd), false);
408
+ switch (scope) {
351
409
  case CSS_MODE_AT_IMPORT_EXPECT_URL: {
352
- modeData.url = value;
353
- modeData.lastPos = end;
354
- mode = CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA;
410
+ importData.url = value;
411
+ importData.end = end;
412
+ scope = CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA;
355
413
  break;
356
414
  }
357
415
  // Do not parse URLs in `supports(...)`
358
416
  case CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA: {
359
417
  break;
360
418
  }
361
- default: {
362
- if (
363
- // Ignore `url(#highlight)` URLs
364
- /^#/.test(value) ||
365
- // Ignore `url()`, `url('')` and `url("")`, they are valid by spec
366
- value.length === 0
367
- ) {
419
+ // Do not parse URLs in import between rules
420
+ case CSS_MODE_AT_NAMESPACE_INVALID:
421
+ case CSS_MODE_AT_IMPORT_INVALID: {
422
+ break;
423
+ }
424
+ case CSS_MODE_IN_BLOCK: {
425
+ // Ignore `url()`, `url('')` and `url("")`, they are valid by spec
426
+ if (value.length === 0) {
368
427
  break;
369
428
  }
370
429
 
@@ -380,16 +439,19 @@ class CssParser extends Parser {
380
439
  return end;
381
440
  },
382
441
  string: (input, start, end) => {
383
- switch (mode) {
442
+ switch (scope) {
384
443
  case CSS_MODE_AT_IMPORT_EXPECT_URL: {
385
- modeData.url = normalizeUrl(input.slice(start + 1, end - 1), true);
386
- modeData.lastPos = end;
444
+ importData.url = normalizeUrl(
445
+ input.slice(start + 1, end - 1),
446
+ true
447
+ );
448
+ importData.end = end;
387
449
  const insideURLFunction =
388
450
  balanced[balanced.length - 1] &&
389
451
  balanced[balanced.length - 1][0] === "url";
390
452
 
391
453
  if (!insideURLFunction) {
392
- mode = CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA;
454
+ scope = CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA;
393
455
  }
394
456
  break;
395
457
  }
@@ -397,7 +459,7 @@ class CssParser extends Parser {
397
459
  case CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA: {
398
460
  break;
399
461
  }
400
- default: {
462
+ case CSS_MODE_IN_BLOCK: {
401
463
  // TODO move escaped parsing to tokenizer
402
464
  const last = balanced[balanced.length - 1];
403
465
 
@@ -408,12 +470,8 @@ class CssParser extends Parser {
408
470
  ) {
409
471
  let value = normalizeUrl(input.slice(start + 1, end - 1), true);
410
472
 
411
- if (
412
- // Ignore `url(#highlight)` URLs
413
- /^#/.test(value) ||
414
- // Ignore `url()`, `url('')` and `url("")`, they are valid by spec
415
- value.length === 0
416
- ) {
473
+ // Ignore `url()`, `url('')` and `url("")`, they are valid by spec
474
+ if (value.length === 0) {
417
475
  break;
418
476
  }
419
477
 
@@ -436,175 +494,234 @@ class CssParser extends Parser {
436
494
  atKeyword: (input, start, end) => {
437
495
  const name = input.slice(start, end).toLowerCase();
438
496
  if (name === "@namespace") {
439
- throw new Error("@namespace is not supported in bundled CSS");
440
- }
441
- if (name === "@import") {
442
- if (mode !== CSS_MODE_TOP_LEVEL) {
443
- throw new Error(
444
- `Unexpected @import at ${start} during ${explainMode(mode)}`
497
+ scope = CSS_MODE_AT_NAMESPACE_INVALID;
498
+ this._emitWarning(
499
+ state,
500
+ "@namespace is not supported in bundled CSS",
501
+ locConverter,
502
+ start,
503
+ end
504
+ );
505
+ return end;
506
+ } else if (name === "@import") {
507
+ if (!allowImportAtRule) {
508
+ scope = CSS_MODE_AT_IMPORT_INVALID;
509
+ this._emitWarning(
510
+ state,
511
+ "Any @import rules must precede all other rules",
512
+ locConverter,
513
+ start,
514
+ end
445
515
  );
516
+ return end;
446
517
  }
447
- mode = CSS_MODE_AT_IMPORT_EXPECT_URL;
448
- modeData = {
449
- atRuleStart: start,
450
- lastPos: end,
451
- url: undefined,
452
- layer: undefined,
453
- supports: undefined,
454
- media: undefined
455
- };
456
- }
457
- if (OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE.test(name)) {
518
+
519
+ scope = CSS_MODE_AT_IMPORT_EXPECT_URL;
520
+ importData = { start, end };
521
+ } else if (
522
+ this.allowModeSwitch &&
523
+ OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE.test(name)
524
+ ) {
458
525
  let pos = end;
459
526
  pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
460
527
  if (pos === input.length) return pos;
461
528
  const [newPos, name] = eatText(input, pos, eatKeyframes);
529
+ if (newPos === input.length) return newPos;
530
+ if (input.charCodeAt(newPos) !== CC_LEFT_CURLY) {
531
+ this._emitWarning(
532
+ state,
533
+ `Unexpected '${input[newPos]}' at ${newPos} during parsing of @keyframes (expected '{')`,
534
+ locConverter,
535
+ start,
536
+ end
537
+ );
538
+
539
+ return newPos;
540
+ }
462
541
  const { line: sl, column: sc } = locConverter.get(pos);
463
542
  const { line: el, column: ec } = locConverter.get(newPos);
464
543
  const dep = new CssLocalIdentifierDependency(name, [pos, newPos]);
465
544
  dep.setLoc(sl, sc, el, ec);
466
545
  module.addDependency(dep);
467
546
  pos = newPos;
468
- if (pos === input.length) return pos;
469
- if (input.charCodeAt(pos) !== CC_LEFT_CURLY) {
470
- throw new Error(
471
- `Unexpected ${input[pos]} at ${pos} during parsing of @keyframes (expected '{')`
472
- );
473
- }
474
- mode = CSS_MODE_IN_LOCAL_RULE;
475
- modeNestingLevel = 1;
476
547
  return pos + 1;
477
- }
478
- if (name === "@media" || name === "@supports") {
548
+ } else if (this.allowModeSwitch && name === "@property") {
479
549
  let pos = end;
480
- const [newPos] = eatText(input, pos, eatAtRuleNested);
481
- pos = newPos;
550
+ pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
482
551
  if (pos === input.length) return pos;
483
- if (input.charCodeAt(pos) !== CC_LEFT_CURLY) {
484
- throw new Error(
485
- `Unexpected ${input[pos]} at ${pos} during parsing of @media or @supports (expected '{')`
552
+ const propertyNameStart = pos;
553
+ const [propertyNameEnd, propertyName] = eatText(
554
+ input,
555
+ pos,
556
+ eatKeyframes
557
+ );
558
+ if (propertyNameEnd === input.length) return propertyNameEnd;
559
+ if (!propertyName.startsWith("--")) return propertyNameEnd;
560
+ if (input.charCodeAt(propertyNameEnd) !== CC_LEFT_CURLY) {
561
+ this._emitWarning(
562
+ state,
563
+ `Unexpected '${input[propertyNameEnd]}' at ${propertyNameEnd} during parsing of @property (expected '{')`,
564
+ locConverter,
565
+ start,
566
+ end
486
567
  );
568
+
569
+ return propertyNameEnd;
487
570
  }
571
+ const { line: sl, column: sc } = locConverter.get(pos);
572
+ const { line: el, column: ec } = locConverter.get(propertyNameEnd);
573
+ const name = propertyName.slice(2);
574
+ const dep = new CssLocalIdentifierDependency(
575
+ name,
576
+ [propertyNameStart, propertyNameEnd],
577
+ "--"
578
+ );
579
+ dep.setLoc(sl, sc, el, ec);
580
+ module.addDependency(dep);
581
+ declaredCssVariables.add(name);
582
+ pos = propertyNameEnd;
488
583
  return pos + 1;
584
+ } else if (
585
+ name === "@media" ||
586
+ name === "@supports" ||
587
+ name === "@layer" ||
588
+ name === "@container"
589
+ ) {
590
+ modeData = isLocalMode() ? "local" : "global";
591
+ isNextRulePrelude = true;
592
+ return end;
593
+ } else if (this.allowModeSwitch) {
594
+ modeData = "global";
595
+ isNextRulePrelude = false;
489
596
  }
490
597
  return end;
491
598
  },
492
599
  semicolon: (input, start, end) => {
493
- switch (mode) {
494
- case CSS_MODE_AT_IMPORT_EXPECT_URL:
495
- throw new Error(`Expected URL for @import at ${start}`);
600
+ switch (scope) {
601
+ case CSS_MODE_AT_IMPORT_EXPECT_URL: {
602
+ this._emitWarning(
603
+ state,
604
+ `Expected URL for @import at ${start}`,
605
+ locConverter,
606
+ start,
607
+ end
608
+ );
609
+ return end;
610
+ }
496
611
  case CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA: {
497
- if (modeData.url === undefined) {
498
- throw new Error(
499
- `Expected URL for @import at ${modeData.atRuleStart}`
612
+ if (!importData.url === undefined) {
613
+ this._emitWarning(
614
+ state,
615
+ `Expected URL for @import at ${importData.start}`,
616
+ locConverter,
617
+ importData.start,
618
+ importData.end
500
619
  );
620
+ return end;
501
621
  }
502
622
  const semicolonPos = end;
503
- const { line: sl, column: sc } = locConverter.get(
504
- modeData.atRuleStart
505
- );
623
+ end = walkCssTokens.eatWhiteLine(input, end + 1);
624
+ const { line: sl, column: sc } = locConverter.get(importData.start);
506
625
  const { line: el, column: ec } = locConverter.get(end);
507
626
  const pos = walkCssTokens.eatWhitespaceAndComments(
508
627
  input,
509
- modeData.lastPos
628
+ importData.end
510
629
  );
511
630
  // Prevent to consider comments as a part of media query
512
631
  if (pos !== semicolonPos - 1) {
513
- modeData.media = input
514
- .slice(modeData.lastPos, semicolonPos - 1)
632
+ importData.media = input
633
+ .slice(importData.end, semicolonPos - 1)
515
634
  .trim();
516
635
  }
517
636
  const dep = new CssImportDependency(
518
- modeData.url.trim(),
519
- [modeData.start, end],
520
- modeData.layer,
521
- modeData.supports,
522
- modeData.media && modeData.media.length > 0
523
- ? modeData.media
637
+ importData.url.trim(),
638
+ [importData.start, end],
639
+ importData.layer,
640
+ importData.supports,
641
+ importData.media && importData.media.length > 0
642
+ ? importData.media
524
643
  : undefined
525
644
  );
526
645
  dep.setLoc(sl, sc, el, ec);
527
646
  module.addDependency(dep);
528
- modeData = undefined;
529
- mode = CSS_MODE_TOP_LEVEL;
647
+ importData = undefined;
648
+ scope = CSS_MODE_TOP_LEVEL;
530
649
  break;
531
650
  }
532
- case CSS_MODE_IN_LOCAL_RULE: {
533
- processDeclarationValueDone(input, start);
534
- return processLocalDeclaration(input, end);
535
- }
536
- case CSS_MODE_IN_RULE: {
537
- return end;
651
+ case CSS_MODE_IN_BLOCK: {
652
+ if (this.allowModeSwitch) {
653
+ processDeclarationValueDone(input);
654
+ inAnimationProperty = false;
655
+ isNextRulePrelude = isNextNestedSyntax(input, end);
656
+ }
657
+ break;
538
658
  }
539
659
  }
540
- mode = CSS_MODE_TOP_LEVEL;
541
- modeData = undefined;
542
- singleClassSelector = undefined;
543
660
  return end;
544
661
  },
545
662
  leftCurlyBracket: (input, start, end) => {
546
- switch (mode) {
547
- case CSS_MODE_TOP_LEVEL:
548
- mode = isTopLevelLocal()
549
- ? CSS_MODE_IN_LOCAL_RULE
550
- : CSS_MODE_IN_RULE;
551
- modeNestingLevel = 1;
552
- if (mode === CSS_MODE_IN_LOCAL_RULE)
553
- return processLocalDeclaration(input, end);
663
+ switch (scope) {
664
+ case CSS_MODE_TOP_LEVEL: {
665
+ allowImportAtRule = false;
666
+ scope = CSS_MODE_IN_BLOCK;
667
+ blockNestingLevel = 1;
668
+
669
+ if (this.allowModeSwitch) {
670
+ isNextRulePrelude = isNextNestedSyntax(input, end);
671
+ }
672
+
554
673
  break;
555
- case CSS_MODE_IN_RULE:
556
- case CSS_MODE_IN_LOCAL_RULE:
557
- modeNestingLevel++;
674
+ }
675
+ case CSS_MODE_IN_BLOCK: {
676
+ blockNestingLevel++;
677
+
678
+ if (this.allowModeSwitch) {
679
+ isNextRulePrelude = isNextNestedSyntax(input, end);
680
+ }
558
681
  break;
682
+ }
559
683
  }
560
684
  return end;
561
685
  },
562
686
  rightCurlyBracket: (input, start, end) => {
563
- switch (mode) {
564
- case CSS_MODE_IN_LOCAL_RULE:
565
- processDeclarationValueDone(input, start);
566
- /* falls through */
567
- case CSS_MODE_IN_RULE:
568
- if (--modeNestingLevel === 0) {
569
- mode = CSS_MODE_TOP_LEVEL;
570
- modeData = undefined;
571
- singleClassSelector = undefined;
687
+ switch (scope) {
688
+ case CSS_MODE_IN_BLOCK: {
689
+ if (isLocalMode()) {
690
+ processDeclarationValueDone(input);
691
+ inAnimationProperty = false;
572
692
  }
573
- break;
574
- }
575
- return end;
576
- },
577
- id: (input, start, end) => {
578
- singleClassSelector = false;
579
- switch (mode) {
580
- case CSS_MODE_TOP_LEVEL:
581
- if (isTopLevelLocal()) {
582
- const name = input.slice(start + 1, end);
583
- const dep = new CssLocalIdentifierDependency(name, [
584
- start + 1,
585
- end
586
- ]);
587
- const { line: sl, column: sc } = locConverter.get(start);
588
- const { line: el, column: ec } = locConverter.get(end);
589
- dep.setLoc(sl, sc, el, ec);
590
- module.addDependency(dep);
693
+ if (--blockNestingLevel === 0) {
694
+ scope = CSS_MODE_TOP_LEVEL;
695
+
696
+ if (this.allowModeSwitch) {
697
+ isNextRulePrelude = true;
698
+ modeData = undefined;
699
+ }
700
+ } else if (this.allowModeSwitch) {
701
+ isNextRulePrelude = isNextNestedSyntax(input, end);
591
702
  }
592
703
  break;
704
+ }
593
705
  }
594
706
  return end;
595
707
  },
596
708
  identifier: (input, start, end) => {
597
- singleClassSelector = false;
598
- switch (mode) {
599
- case CSS_MODE_IN_LOCAL_RULE:
600
- if (modeData === "animation") {
601
- lastIdentifier = [start, end];
709
+ switch (scope) {
710
+ case CSS_MODE_IN_BLOCK: {
711
+ if (isLocalMode()) {
712
+ // Handle only top level values and not inside functions
713
+ if (inAnimationProperty && balanced.length === 0) {
714
+ lastIdentifier = [start, end];
715
+ } else {
716
+ return processLocalDeclaration(input, start, end);
717
+ }
602
718
  }
603
719
  break;
720
+ }
604
721
  case CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA: {
605
722
  if (input.slice(start, end).toLowerCase() === "layer") {
606
- modeData.layer = "";
607
- modeData.lastPos = end;
723
+ importData.layer = "";
724
+ importData.end = end;
608
725
  }
609
726
  break;
610
727
  }
@@ -612,24 +729,25 @@ class CssParser extends Parser {
612
729
  return end;
613
730
  },
614
731
  class: (input, start, end) => {
615
- switch (mode) {
616
- case CSS_MODE_TOP_LEVEL: {
617
- if (isTopLevelLocal()) {
618
- const name = input.slice(start + 1, end);
619
- const dep = new CssLocalIdentifierDependency(name, [
620
- start + 1,
621
- end
622
- ]);
623
- const { line: sl, column: sc } = locConverter.get(start);
624
- const { line: el, column: ec } = locConverter.get(end);
625
- dep.setLoc(sl, sc, el, ec);
626
- module.addDependency(dep);
627
- if (singleClassSelector === undefined) singleClassSelector = name;
628
- } else {
629
- singleClassSelector = false;
630
- }
631
- break;
632
- }
732
+ if (isLocalMode()) {
733
+ const name = input.slice(start + 1, end);
734
+ const dep = new CssLocalIdentifierDependency(name, [start + 1, end]);
735
+ const { line: sl, column: sc } = locConverter.get(start);
736
+ const { line: el, column: ec } = locConverter.get(end);
737
+ dep.setLoc(sl, sc, el, ec);
738
+ module.addDependency(dep);
739
+ }
740
+
741
+ return end;
742
+ },
743
+ id: (input, start, end) => {
744
+ if (isLocalMode()) {
745
+ const name = input.slice(start + 1, end);
746
+ const dep = new CssLocalIdentifierDependency(name, [start + 1, end]);
747
+ const { line: sl, column: sc } = locConverter.get(start);
748
+ const { line: el, column: ec } = locConverter.get(end);
749
+ dep.setLoc(sl, sc, el, ec);
750
+ module.addDependency(dep);
633
751
  }
634
752
  return end;
635
753
  },
@@ -638,75 +756,74 @@ class CssParser extends Parser {
638
756
 
639
757
  balanced.push([name, start, end]);
640
758
 
641
- switch (mode) {
642
- case CSS_MODE_IN_LOCAL_RULE: {
643
- name = name.toLowerCase();
644
-
645
- if (name === "var") {
646
- let pos = walkCssTokens.eatWhitespaceAndComments(input, end);
647
- if (pos === input.length) return pos;
648
- const [newPos, name] = eatText(input, pos, eatNameInVar);
649
- if (!name.startsWith("--")) return end;
650
- const { line: sl, column: sc } = locConverter.get(pos);
651
- const { line: el, column: ec } = locConverter.get(newPos);
652
- const dep = new CssSelfLocalIdentifierDependency(
653
- name.slice(2),
654
- [pos, newPos],
655
- "--",
656
- declaredCssVariables
657
- );
658
- dep.setLoc(sl, sc, el, ec);
659
- module.addDependency(dep);
660
- return newPos;
661
- }
662
- break;
759
+ if (isLocalMode()) {
760
+ name = name.toLowerCase();
761
+
762
+ // Don't rename animation name when we have `var()` function
763
+ if (inAnimationProperty && balanced.length === 1) {
764
+ lastIdentifier = undefined;
765
+ }
766
+
767
+ if (name === "var") {
768
+ let pos = walkCssTokens.eatWhitespaceAndComments(input, end);
769
+ if (pos === input.length) return pos;
770
+ const [newPos, name] = eatText(input, pos, eatNameInVar);
771
+ if (!name.startsWith("--")) return end;
772
+ const { line: sl, column: sc } = locConverter.get(pos);
773
+ const { line: el, column: ec } = locConverter.get(newPos);
774
+ const dep = new CssSelfLocalIdentifierDependency(
775
+ name.slice(2),
776
+ [pos, newPos],
777
+ "--",
778
+ declaredCssVariables
779
+ );
780
+ dep.setLoc(sl, sc, el, ec);
781
+ module.addDependency(dep);
782
+ return newPos;
663
783
  }
664
784
  }
785
+
665
786
  return end;
666
787
  },
667
788
  leftParenthesis: (input, start, end) => {
668
789
  balanced.push(["(", start, end]);
669
790
 
670
- switch (mode) {
671
- case CSS_MODE_TOP_LEVEL: {
672
- modeStack.push(false);
673
- break;
674
- }
675
- }
676
791
  return end;
677
792
  },
678
793
  rightParenthesis: (input, start, end) => {
679
794
  const last = balanced[balanced.length - 1];
795
+ const popped = balanced.pop();
796
+
797
+ if (
798
+ this.allowModeSwitch &&
799
+ popped &&
800
+ (popped[0] === ":local" || popped[0] === ":global")
801
+ ) {
802
+ modeData = balanced[balanced.length - 1]
803
+ ? /** @type {"local" | "global"} */
804
+ (balanced[balanced.length - 1][0])
805
+ : undefined;
806
+ const dep = new ConstDependency("", [start, end]);
807
+ module.addPresentationalDependency(dep);
808
+
809
+ return end;
810
+ }
680
811
 
681
- balanced.pop();
682
-
683
- switch (mode) {
684
- case CSS_MODE_TOP_LEVEL: {
685
- if (awaitRightParenthesis) {
686
- awaitRightParenthesis = false;
687
- }
688
- const newModeData = modeStack.pop();
689
- if (newModeData !== false) {
690
- modeData = newModeData;
691
- const dep = new ConstDependency("", [start, end]);
692
- module.addPresentationalDependency(dep);
693
- }
694
- break;
695
- }
812
+ switch (scope) {
696
813
  case CSS_MODE_AT_IMPORT_EXPECT_URL: {
697
814
  if (last && last[0] === "url") {
698
- modeData.lastPos = end;
699
- mode = CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA;
815
+ importData.end = end;
816
+ scope = CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA;
700
817
  }
701
818
  break;
702
819
  }
703
820
  case CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA: {
704
821
  if (last && last[0].toLowerCase() === "layer") {
705
- modeData.layer = input.slice(last[2], end - 1).trim();
706
- modeData.lastPos = end;
822
+ importData.layer = input.slice(last[2], end - 1).trim();
823
+ importData.end = end;
707
824
  } else if (last && last[0].toLowerCase() === "supports") {
708
- modeData.supports = input.slice(last[2], end - 1).trim();
709
- modeData.lastPos = end;
825
+ importData.supports = input.slice(last[2], end - 1).trim();
826
+ importData.end = end;
710
827
  }
711
828
  break;
712
829
  }
@@ -715,27 +832,38 @@ class CssParser extends Parser {
715
832
  return end;
716
833
  },
717
834
  pseudoClass: (input, start, end) => {
718
- singleClassSelector = false;
719
- switch (mode) {
720
- case CSS_MODE_TOP_LEVEL: {
721
- const name = input.slice(start, end).toLowerCase();
722
- if (this.allowModeSwitch && name === ":global") {
723
- modeData = "global";
724
- const dep = new ConstDependency("", [start, end]);
725
- module.addPresentationalDependency(dep);
726
- } else if (this.allowModeSwitch && name === ":local") {
727
- modeData = "local";
728
- const dep = new ConstDependency("", [start, end]);
729
- module.addPresentationalDependency(dep);
730
- } else if (this.allowPseudoBlocks && name === ":export") {
731
- const pos = parseExports(input, end);
732
- const dep = new ConstDependency("", [start, pos]);
733
- module.addPresentationalDependency(dep);
734
- return pos;
835
+ if (this.allowModeSwitch) {
836
+ const name = input.slice(start, end).toLowerCase();
837
+
838
+ if (name === ":global") {
839
+ modeData = "global";
840
+ // Eat extra whitespace and comments
841
+ end = walkCssTokens.eatWhitespace(input, end);
842
+ const dep = new ConstDependency("", [start, end]);
843
+ module.addPresentationalDependency(dep);
844
+ return end;
845
+ } else if (name === ":local") {
846
+ modeData = "local";
847
+ // Eat extra whitespace and comments
848
+ end = walkCssTokens.eatWhitespace(input, end);
849
+ const dep = new ConstDependency("", [start, end]);
850
+ module.addPresentationalDependency(dep);
851
+ return end;
852
+ }
853
+
854
+ switch (scope) {
855
+ case CSS_MODE_TOP_LEVEL: {
856
+ if (name === ":export") {
857
+ const pos = parseExports(input, end);
858
+ const dep = new ConstDependency("", [start, pos]);
859
+ module.addPresentationalDependency(dep);
860
+ return pos;
861
+ }
862
+ break;
735
863
  }
736
- break;
737
864
  }
738
865
  }
866
+
739
867
  return end;
740
868
  },
741
869
  pseudoFunction: (input, start, end) => {
@@ -743,40 +871,36 @@ class CssParser extends Parser {
743
871
 
744
872
  balanced.push([name, start, end]);
745
873
 
746
- switch (mode) {
747
- case CSS_MODE_TOP_LEVEL: {
748
- name = name.toLowerCase();
749
-
750
- if (this.allowModeSwitch && name === ":global") {
751
- modeStack.push(modeData);
752
- modeData = "global";
753
- const dep = new ConstDependency("", [start, end]);
754
- module.addPresentationalDependency(dep);
755
- } else if (this.allowModeSwitch && name === ":local") {
756
- modeStack.push(modeData);
757
- modeData = "local";
758
- const dep = new ConstDependency("", [start, end]);
759
- module.addPresentationalDependency(dep);
760
- } else {
761
- awaitRightParenthesis = true;
762
- modeStack.push(false);
763
- }
764
- break;
874
+ if (this.allowModeSwitch) {
875
+ name = name.toLowerCase();
876
+
877
+ if (name === ":global") {
878
+ modeData = "global";
879
+ const dep = new ConstDependency("", [start, end]);
880
+ module.addPresentationalDependency(dep);
881
+ } else if (name === ":local") {
882
+ modeData = "local";
883
+ const dep = new ConstDependency("", [start, end]);
884
+ module.addPresentationalDependency(dep);
765
885
  }
766
886
  }
887
+
767
888
  return end;
768
889
  },
769
890
  comma: (input, start, end) => {
770
- switch (mode) {
771
- case CSS_MODE_TOP_LEVEL:
772
- if (!awaitRightParenthesis) {
773
- modeData = undefined;
774
- modeStack.length = 0;
891
+ if (this.allowModeSwitch) {
892
+ // Reset stack for `:global .class :local .class-other` selector after
893
+ modeData = undefined;
894
+
895
+ switch (scope) {
896
+ case CSS_MODE_IN_BLOCK: {
897
+ if (isLocalMode()) {
898
+ processDeclarationValueDone(input);
899
+ }
900
+
901
+ break;
775
902
  }
776
- break;
777
- case CSS_MODE_IN_LOCAL_RULE:
778
- processDeclarationValueDone(input, start);
779
- break;
903
+ }
780
904
  }
781
905
  return end;
782
906
  }