webpack 5.80.0 → 5.82.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.

Potentially problematic release.


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

Files changed (135) hide show
  1. package/bin/webpack.js +13 -2
  2. package/lib/AsyncDependenciesBlock.js +8 -0
  3. package/lib/CodeGenerationResults.js +2 -2
  4. package/lib/Compilation.js +4 -2
  5. package/lib/ContextModule.js +8 -0
  6. package/lib/CssModule.js +169 -0
  7. package/lib/DefinePlugin.js +81 -44
  8. package/lib/DelegatedModule.js +5 -0
  9. package/lib/DependenciesBlock.js +8 -0
  10. package/lib/Dependency.js +8 -0
  11. package/lib/DllModule.js +8 -0
  12. package/lib/ExportsInfo.js +3 -0
  13. package/lib/ExternalModule.js +8 -0
  14. package/lib/FileSystemInfo.js +8 -0
  15. package/lib/LoaderOptionsPlugin.js +12 -2
  16. package/lib/Module.js +8 -0
  17. package/lib/ModuleBuildError.js +9 -0
  18. package/lib/ModuleError.js +9 -0
  19. package/lib/ModuleFilenameHelpers.js +113 -4
  20. package/lib/ModuleParseError.js +9 -0
  21. package/lib/ModuleTypeConstants.js +21 -0
  22. package/lib/ModuleWarning.js +9 -0
  23. package/lib/NormalModule.js +8 -0
  24. package/lib/NormalModuleFactory.js +15 -3
  25. package/lib/RawModule.js +8 -0
  26. package/lib/WebpackError.js +8 -0
  27. package/lib/WebpackOptionsApply.js +33 -40
  28. package/lib/asset/RawDataUrlModule.js +8 -0
  29. package/lib/cache/MemoryWithGcCachePlugin.js +2 -0
  30. package/lib/cache/ResolverCachePlugin.js +3 -0
  31. package/lib/config/defaults.js +1 -0
  32. package/lib/config/normalization.js +1 -0
  33. package/lib/container/ContainerEntryModule.js +5 -0
  34. package/lib/container/ContainerExposedDependency.js +9 -0
  35. package/lib/container/FallbackDependency.js +6 -0
  36. package/lib/container/FallbackModule.js +5 -0
  37. package/lib/container/RemoteModule.js +5 -0
  38. package/lib/css/CssGenerator.js +4 -0
  39. package/lib/css/CssLoadingRuntimeModule.js +9 -2
  40. package/lib/css/CssModulesPlugin.js +201 -57
  41. package/lib/css/CssParser.js +270 -147
  42. package/lib/css/walkCssTokens.js +121 -65
  43. package/lib/debug/ProfilingPlugin.js +2 -0
  44. package/lib/dependencies/AMDDefineDependency.js +8 -0
  45. package/lib/dependencies/AMDRequireArrayDependency.js +8 -0
  46. package/lib/dependencies/AMDRequireContextDependency.js +9 -0
  47. package/lib/dependencies/AMDRequireDependency.js +8 -0
  48. package/lib/dependencies/CachedConstDependency.js +8 -0
  49. package/lib/dependencies/CommonJsDependencyHelpers.js +9 -0
  50. package/lib/dependencies/CommonJsExportRequireDependency.js +8 -0
  51. package/lib/dependencies/CommonJsExportsDependency.js +8 -0
  52. package/lib/dependencies/CommonJsExportsParserPlugin.js +65 -3
  53. package/lib/dependencies/CommonJsFullRequireDependency.js +8 -0
  54. package/lib/dependencies/CommonJsRequireContextDependency.js +9 -0
  55. package/lib/dependencies/CommonJsSelfReferenceDependency.js +8 -0
  56. package/lib/dependencies/ConstDependency.js +8 -0
  57. package/lib/dependencies/ContextDependency.js +8 -0
  58. package/lib/dependencies/ContextElementDependency.js +8 -0
  59. package/lib/dependencies/CreateScriptUrlDependency.js +8 -0
  60. package/lib/dependencies/CssExportDependency.js +8 -0
  61. package/lib/dependencies/CssImportDependency.js +52 -1
  62. package/lib/dependencies/CssLocalIdentifierDependency.js +8 -0
  63. package/lib/dependencies/CssSelfLocalIdentifierDependency.js +8 -0
  64. package/lib/dependencies/CssUrlDependency.js +8 -0
  65. package/lib/dependencies/DllEntryDependency.js +9 -0
  66. package/lib/dependencies/ExportsInfoDependency.js +5 -0
  67. package/lib/dependencies/HarmonyAcceptDependency.js +8 -0
  68. package/lib/dependencies/HarmonyEvaluatedImportSpecifierDependency.js +8 -0
  69. package/lib/dependencies/HarmonyExportExpressionDependency.js +8 -0
  70. package/lib/dependencies/HarmonyExportHeaderDependency.js +8 -0
  71. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +14 -0
  72. package/lib/dependencies/HarmonyExportSpecifierDependency.js +8 -0
  73. package/lib/dependencies/HarmonyImportDependency.js +8 -0
  74. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +1 -0
  75. package/lib/dependencies/HarmonyImportSpecifierDependency.js +8 -0
  76. package/lib/dependencies/ImportContextDependency.js +9 -0
  77. package/lib/dependencies/ImportDependency.js +8 -0
  78. package/lib/dependencies/JsonExportsDependency.js +8 -0
  79. package/lib/dependencies/LocalModuleDependency.js +8 -0
  80. package/lib/dependencies/ModuleDecoratorDependency.js +8 -0
  81. package/lib/dependencies/ModuleDependency.js +8 -0
  82. package/lib/dependencies/ProvidedDependency.js +8 -0
  83. package/lib/dependencies/PureExpressionDependency.js +8 -0
  84. package/lib/dependencies/RequireEnsureDependency.js +8 -0
  85. package/lib/dependencies/RequireHeaderDependency.js +5 -0
  86. package/lib/dependencies/RequireResolveContextDependency.js +9 -0
  87. package/lib/dependencies/RequireResolveHeaderDependency.js +5 -0
  88. package/lib/dependencies/RuntimeRequirementsDependency.js +8 -0
  89. package/lib/dependencies/StaticExportsDependency.js +8 -0
  90. package/lib/dependencies/URLDependency.js +8 -0
  91. package/lib/dependencies/UnsupportedDependency.js +8 -0
  92. package/lib/dependencies/WebAssemblyExportImportedDependency.js +8 -0
  93. package/lib/dependencies/WebAssemblyImportDependency.js +8 -0
  94. package/lib/dependencies/WorkerDependency.js +8 -0
  95. package/lib/index.js +1 -0
  96. package/lib/javascript/BasicEvaluatedExpression.js +108 -1
  97. package/lib/javascript/JavascriptParser.js +133 -12
  98. package/lib/json/JsonData.js +25 -0
  99. package/lib/json/JsonGenerator.js +15 -3
  100. package/lib/json/JsonModulesPlugin.js +1 -0
  101. package/lib/json/JsonParser.js +2 -1
  102. package/lib/library/ModuleLibraryPlugin.js +2 -1
  103. package/lib/optimize/RealContentHashPlugin.js +6 -0
  104. package/lib/runtime/AutoPublicPathRuntimeModule.js +6 -1
  105. package/lib/runtime/GetChunkFilenameRuntimeModule.js +4 -0
  106. package/lib/runtime/GetTrustedTypesPolicyRuntimeModule.js +22 -3
  107. package/lib/schemes/DataUriPlugin.js +4 -0
  108. package/lib/schemes/HttpUriPlugin.js +38 -0
  109. package/lib/serialization/ObjectMiddleware.js +2 -0
  110. package/lib/sharing/ConsumeSharedModule.js +8 -0
  111. package/lib/sharing/ConsumeSharedRuntimeModule.js +9 -3
  112. package/lib/sharing/ProvideSharedDependency.js +6 -0
  113. package/lib/sharing/ProvideSharedModule.js +5 -0
  114. package/lib/sharing/ShareRuntimeModule.js +7 -4
  115. package/lib/sharing/utils.js +293 -7
  116. package/lib/stats/DefaultStatsPrinterPlugin.js +25 -0
  117. package/lib/util/LazySet.js +10 -2
  118. package/lib/util/MapHelpers.js +19 -5
  119. package/lib/util/StackedCacheMap.js +6 -0
  120. package/lib/util/StringXor.js +51 -0
  121. package/lib/util/binarySearchBounds.js +49 -0
  122. package/lib/util/compileBooleanMatcher.js +31 -0
  123. package/lib/util/deprecation.js +8 -0
  124. package/lib/util/identifier.js +4 -0
  125. package/lib/util/internalSerializables.js +1 -0
  126. package/lib/util/numberHash.js +75 -21
  127. package/lib/util/propertyAccess.js +5 -0
  128. package/lib/util/semver.js +1 -1
  129. package/lib/wasm/EnableWasmLoadingPlugin.js +4 -0
  130. package/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js +1 -0
  131. package/lib/wasm-async/AsyncWebAssemblyParser.js +1 -1
  132. package/package.json +4 -5
  133. package/schemas/WebpackOptions.check.js +1 -1
  134. package/schemas/WebpackOptions.json +33 -0
  135. package/types.d.ts +176 -48
@@ -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");
@@ -30,7 +32,15 @@ const STRING_MULTILINE = /\\[\n\r\f]/g;
30
32
  const TRIM_WHITE_SPACES = /(^[ \t\n\r\f]*|[ \t\n\r\f]*$)/g;
31
33
  const UNESCAPE = /\\([0-9a-fA-F]{1,6}[ \t\n\r\f]?|[\s\S])/g;
32
34
  const IMAGE_SET_FUNCTION = /^(-\w+-)?image-set$/i;
33
-
35
+ const OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE = /^@(-\w+-)?keyframes$/;
36
+ const OPTIONALLY_VENDOR_PREFIXED_ANIMATION_PROPERTY =
37
+ /^(-\w+-)?animation(-name)?$/i;
38
+
39
+ /**
40
+ * @param {string} str url string
41
+ * @param {boolean} isString is url wrapped in quotes
42
+ * @returns {string} normalized url
43
+ */
34
44
  const normalizeUrl = (str, isString) => {
35
45
  // Remove extra spaces and newlines:
36
46
  // `url("im\
@@ -68,6 +78,9 @@ const normalizeUrl = (str, isString) => {
68
78
  };
69
79
 
70
80
  class LocConverter {
81
+ /**
82
+ * @param {string} input input
83
+ */
71
84
  constructor(input) {
72
85
  this._input = input;
73
86
  this.line = 1;
@@ -75,6 +88,10 @@ class LocConverter {
75
88
  this.pos = 0;
76
89
  }
77
90
 
91
+ /**
92
+ * @param {number} pos position
93
+ * @returns {LocConverter} location converter
94
+ */
78
95
  get(pos) {
79
96
  if (this.pos !== pos) {
80
97
  if (this.pos < pos) {
@@ -106,31 +123,9 @@ const CSS_MODE_TOP_LEVEL = 0;
106
123
  const CSS_MODE_IN_RULE = 1;
107
124
  const CSS_MODE_IN_LOCAL_RULE = 2;
108
125
  const CSS_MODE_AT_IMPORT_EXPECT_URL = 3;
109
- // TODO implement layer and supports for @import
110
- const CSS_MODE_AT_IMPORT_EXPECT_SUPPORTS = 4;
111
- const CSS_MODE_AT_IMPORT_EXPECT_MEDIA = 5;
112
- const CSS_MODE_AT_OTHER = 6;
113
-
114
- const explainMode = mode => {
115
- switch (mode) {
116
- case CSS_MODE_TOP_LEVEL:
117
- return "parsing top level css";
118
- case CSS_MODE_IN_RULE:
119
- return "parsing css rule content (global)";
120
- case CSS_MODE_IN_LOCAL_RULE:
121
- return "parsing css rule content (local)";
122
- case CSS_MODE_AT_IMPORT_EXPECT_URL:
123
- return "parsing @import (expecting url)";
124
- case CSS_MODE_AT_IMPORT_EXPECT_SUPPORTS:
125
- return "parsing @import (expecting optionally supports or media query)";
126
- case CSS_MODE_AT_IMPORT_EXPECT_MEDIA:
127
- return "parsing @import (expecting optionally media query)";
128
- case CSS_MODE_AT_OTHER:
129
- return "parsing at-rule";
130
- default:
131
- return mode;
132
- }
133
- };
126
+ const CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA = 4;
127
+ const CSS_MODE_AT_IMPORT_INVALID = 5;
128
+ const CSS_MODE_AT_NAMESPACE_INVALID = 6;
134
129
 
135
130
  class CssParser extends Parser {
136
131
  constructor({
@@ -144,6 +139,25 @@ class CssParser extends Parser {
144
139
  this.defaultMode = defaultMode;
145
140
  }
146
141
 
142
+ /**
143
+ * @param {ParserState} state parser state
144
+ * @param {string} message warning message
145
+ * @param {LocConverter} locConverter location converter
146
+ * @param {number} start start offset
147
+ * @param {number} end end offset
148
+ */
149
+ _emitWarning(state, message, locConverter, start, end) {
150
+ const { line: sl, column: sc } = locConverter.get(start);
151
+ const { line: el, column: ec } = locConverter.get(end);
152
+
153
+ state.current.addWarning(
154
+ new ModuleDependencyWarning(state.module, new WebpackError(message), {
155
+ start: { line: sl, column: sc },
156
+ end: { line: el, column: ec }
157
+ })
158
+ );
159
+ }
160
+
147
161
  /**
148
162
  * @param {string | Buffer | PreparsedAst} source the source to parse
149
163
  * @param {ParserState} state the parser state
@@ -164,32 +178,26 @@ class CssParser extends Parser {
164
178
  const declaredCssVariables = new Set();
165
179
 
166
180
  const locConverter = new LocConverter(source);
181
+ /** @type {number} */
167
182
  let mode = CSS_MODE_TOP_LEVEL;
168
- let modePos = 0;
183
+ /** @type {number} */
169
184
  let modeNestingLevel = 0;
185
+ /** @type {boolean} */
186
+ let allowImportAtRule = true;
170
187
  let modeData = undefined;
188
+ /** @type {string | boolean | undefined} */
171
189
  let singleClassSelector = undefined;
190
+ /** @type {[number, number] | undefined} */
172
191
  let lastIdentifier = undefined;
192
+ /** @type {boolean} */
173
193
  let awaitRightParenthesis = false;
174
194
  /** @type [string, number, number][] */
175
- const functionStack = [];
195
+ let balanced = [];
176
196
  const modeStack = [];
177
197
 
178
198
  const isTopLevelLocal = () =>
179
199
  modeData === "local" ||
180
200
  (this.defaultMode === "local" && modeData === undefined);
181
- const eatWhiteLine = (input, pos) => {
182
- for (;;) {
183
- const cc = input.charCodeAt(pos);
184
- if (cc === 32 || cc === 9) {
185
- pos++;
186
- continue;
187
- }
188
- if (cc === 10) pos++;
189
- break;
190
- }
191
- return pos;
192
- };
193
201
  const eatUntil = chars => {
194
202
  const charCodes = Array.from({ length: chars.length }, (_, i) =>
195
203
  chars.charCodeAt(i)
@@ -240,10 +248,16 @@ class CssParser extends Parser {
240
248
  const parseExports = (input, pos) => {
241
249
  pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
242
250
  const cc = input.charCodeAt(pos);
243
- if (cc !== CC_LEFT_CURLY)
244
- throw new Error(
245
- `Unexpected ${input[pos]} at ${pos} during parsing of ':export' (expected '{')`
251
+ if (cc !== CC_LEFT_CURLY) {
252
+ this._emitWarning(
253
+ state,
254
+ `Unexpected '${input[pos]}' at ${pos} during parsing of ':export' (expected '{')`,
255
+ locConverter,
256
+ pos,
257
+ pos
246
258
  );
259
+ return pos;
260
+ }
247
261
  pos++;
248
262
  pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
249
263
  for (;;) {
@@ -255,9 +269,14 @@ class CssParser extends Parser {
255
269
  [pos, name] = eatText(input, pos, eatExportName);
256
270
  if (pos === input.length) return pos;
257
271
  if (input.charCodeAt(pos) !== CC_COLON) {
258
- throw new Error(
259
- `Unexpected ${input[pos]} at ${pos} during parsing of export name in ':export' (expected ':')`
272
+ this._emitWarning(
273
+ state,
274
+ `Unexpected '${input[pos]}' at ${pos} during parsing of export name in ':export' (expected ':')`,
275
+ locConverter,
276
+ start,
277
+ pos
260
278
  );
279
+ return pos;
261
280
  }
262
281
  pos++;
263
282
  if (pos === input.length) return pos;
@@ -273,9 +292,14 @@ class CssParser extends Parser {
273
292
  pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
274
293
  if (pos === input.length) return pos;
275
294
  } else if (cc !== CC_RIGHT_CURLY) {
276
- throw new Error(
277
- `Unexpected ${input[pos]} at ${pos} during parsing of export value in ':export' (expected ';' or '}')`
295
+ this._emitWarning(
296
+ state,
297
+ `Unexpected '${input[pos]}' at ${pos} during parsing of export value in ':export' (expected ';' or '}')`,
298
+ locConverter,
299
+ start,
300
+ pos
278
301
  );
302
+ return pos;
279
303
  }
280
304
  const dep = new CssExportDependency(name, value);
281
305
  const { line: sl, column: sc } = locConverter.get(start);
@@ -285,7 +309,7 @@ class CssParser extends Parser {
285
309
  }
286
310
  pos++;
287
311
  if (pos === input.length) return pos;
288
- pos = eatWhiteLine(input, pos);
312
+ pos = walkCssTokens.eatWhiteLine(input, pos);
289
313
  return pos;
290
314
  };
291
315
  const eatPropertyName = eatUntil(":{};");
@@ -315,8 +339,7 @@ class CssParser extends Parser {
315
339
  module.addDependency(dep);
316
340
  declaredCssVariables.add(name);
317
341
  } else if (
318
- propertyName.toLowerCase() === "animation-name" ||
319
- propertyName.toLowerCase() === "animation"
342
+ OPTIONALLY_VENDOR_PREFIXED_ANIMATION_PROPERTY.test(propertyName)
320
343
  ) {
321
344
  modeData = "animation";
322
345
  lastIdentifier = undefined;
@@ -338,34 +361,36 @@ class CssParser extends Parser {
338
361
  const eatNameInVar = eatUntil(",)};/");
339
362
  walkCssTokens(source, {
340
363
  isSelector: () => {
341
- return mode !== CSS_MODE_IN_RULE && mode !== CSS_MODE_IN_LOCAL_RULE;
342
- },
343
- url: (input, start, end, contentStart, contentEnd, isString) => {
344
- let value = normalizeUrl(
345
- input.slice(contentStart, contentEnd),
346
- isString
364
+ return (
365
+ mode !== CSS_MODE_IN_RULE &&
366
+ mode !== CSS_MODE_IN_LOCAL_RULE &&
367
+ mode !== CSS_MODE_AT_IMPORT_EXPECT_URL &&
368
+ mode !== CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA &&
369
+ mode !== CSS_MODE_AT_IMPORT_INVALID &&
370
+ mode !== CSS_MODE_AT_NAMESPACE_INVALID
347
371
  );
372
+ },
373
+ url: (input, start, end, contentStart, contentEnd) => {
374
+ let value = normalizeUrl(input.slice(contentStart, contentEnd), false);
348
375
  switch (mode) {
349
376
  case CSS_MODE_AT_IMPORT_EXPECT_URL: {
350
377
  modeData.url = value;
351
- mode = CSS_MODE_AT_IMPORT_EXPECT_SUPPORTS;
378
+ modeData.lastPos = end;
379
+ mode = CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA;
380
+ break;
381
+ }
382
+ // Do not parse URLs in `supports(...)`
383
+ case CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA: {
384
+ break;
385
+ }
386
+ // Do not parse URLs in import between rules
387
+ case CSS_MODE_AT_NAMESPACE_INVALID:
388
+ case CSS_MODE_AT_IMPORT_INVALID: {
352
389
  break;
353
390
  }
354
- case CSS_MODE_AT_IMPORT_EXPECT_SUPPORTS:
355
- case CSS_MODE_AT_IMPORT_EXPECT_MEDIA:
356
- throw new Error(
357
- `Unexpected ${input.slice(
358
- start,
359
- end
360
- )} at ${start} during ${explainMode(mode)}`
361
- );
362
391
  default: {
363
- if (
364
- // Ignore `url(#highlight)` URLs
365
- /^#/.test(value) ||
366
- // Ignore `url()`, `url('')` and `url("")`, they are valid by spec
367
- value.length === 0
368
- ) {
392
+ // Ignore `url()`, `url('')` and `url("")`, they are valid by spec
393
+ if (value.length === 0) {
369
394
  break;
370
395
  }
371
396
 
@@ -384,31 +409,37 @@ class CssParser extends Parser {
384
409
  switch (mode) {
385
410
  case CSS_MODE_AT_IMPORT_EXPECT_URL: {
386
411
  modeData.url = normalizeUrl(input.slice(start + 1, end - 1), true);
387
- mode = CSS_MODE_AT_IMPORT_EXPECT_SUPPORTS;
412
+ modeData.lastPos = end;
413
+ const insideURLFunction =
414
+ balanced[balanced.length - 1] &&
415
+ balanced[balanced.length - 1][0] === "url";
416
+
417
+ if (!insideURLFunction) {
418
+ mode = CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA;
419
+ }
420
+ break;
421
+ }
422
+ // Do not parse URLs in `supports(...)`
423
+ case CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA: {
388
424
  break;
389
425
  }
390
426
  default: {
391
427
  // TODO move escaped parsing to tokenizer
392
- const lastFunction = functionStack[functionStack.length - 1];
428
+ const last = balanced[balanced.length - 1];
393
429
 
394
430
  if (
395
- lastFunction &&
396
- (lastFunction[0].replace(/\\/g, "").toLowerCase() === "url" ||
397
- IMAGE_SET_FUNCTION.test(lastFunction[0].replace(/\\/g, "")))
431
+ last &&
432
+ (last[0].replace(/\\/g, "").toLowerCase() === "url" ||
433
+ IMAGE_SET_FUNCTION.test(last[0].replace(/\\/g, "")))
398
434
  ) {
399
435
  let value = normalizeUrl(input.slice(start + 1, end - 1), true);
400
436
 
401
- if (
402
- // Ignore `url(#highlight)` URLs
403
- /^#/.test(value) ||
404
- // Ignore `url()`, `url('')` and `url("")`, they are valid by spec
405
- value.length === 0
406
- ) {
437
+ // Ignore `url()`, `url('')` and `url("")`, they are valid by spec
438
+ if (value.length === 0) {
407
439
  break;
408
440
  }
409
441
 
410
- const isUrl =
411
- lastFunction[0].replace(/\\/g, "").toLowerCase() === "url";
442
+ const isUrl = last[0].replace(/\\/g, "").toLowerCase() === "url";
412
443
  const dep = new CssUrlDependency(
413
444
  value,
414
445
  [start, end],
@@ -427,52 +458,81 @@ class CssParser extends Parser {
427
458
  atKeyword: (input, start, end) => {
428
459
  const name = input.slice(start, end).toLowerCase();
429
460
  if (name === "@namespace") {
430
- throw new Error("@namespace is not supported in bundled CSS");
431
- }
432
- if (name === "@import") {
433
- if (mode !== CSS_MODE_TOP_LEVEL) {
434
- throw new Error(
435
- `Unexpected @import at ${start} during ${explainMode(mode)}`
461
+ mode = CSS_MODE_AT_NAMESPACE_INVALID;
462
+ this._emitWarning(
463
+ state,
464
+ "@namespace is not supported in bundled CSS",
465
+ locConverter,
466
+ start,
467
+ end
468
+ );
469
+ return end;
470
+ } else if (name === "@import") {
471
+ if (!allowImportAtRule) {
472
+ mode = CSS_MODE_AT_IMPORT_INVALID;
473
+ this._emitWarning(
474
+ state,
475
+ "Any @import rules must precede all other rules",
476
+ locConverter,
477
+ start,
478
+ end
436
479
  );
480
+ return end;
437
481
  }
482
+
438
483
  mode = CSS_MODE_AT_IMPORT_EXPECT_URL;
439
- modePos = end;
440
484
  modeData = {
441
- start: start,
485
+ atRuleStart: start,
486
+ lastPos: end,
442
487
  url: undefined,
443
- supports: undefined
488
+ layer: undefined,
489
+ supports: undefined,
490
+ media: undefined
444
491
  };
445
- }
446
- if (name === "@keyframes") {
492
+ } else if (
493
+ isTopLevelLocal() &&
494
+ OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE.test(name)
495
+ ) {
447
496
  let pos = end;
448
497
  pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
449
498
  if (pos === input.length) return pos;
450
499
  const [newPos, name] = eatText(input, pos, eatKeyframes);
500
+ if (newPos === input.length) return newPos;
501
+ if (input.charCodeAt(newPos) !== CC_LEFT_CURLY) {
502
+ this._emitWarning(
503
+ state,
504
+ `Unexpected '${input[newPos]}' at ${newPos} during parsing of @keyframes (expected '{')`,
505
+ locConverter,
506
+ start,
507
+ end
508
+ );
509
+
510
+ return newPos;
511
+ }
451
512
  const { line: sl, column: sc } = locConverter.get(pos);
452
513
  const { line: el, column: ec } = locConverter.get(newPos);
453
514
  const dep = new CssLocalIdentifierDependency(name, [pos, newPos]);
454
515
  dep.setLoc(sl, sc, el, ec);
455
516
  module.addDependency(dep);
456
517
  pos = newPos;
457
- if (pos === input.length) return pos;
458
- if (input.charCodeAt(pos) !== CC_LEFT_CURLY) {
459
- throw new Error(
460
- `Unexpected ${input[pos]} at ${pos} during parsing of @keyframes (expected '{')`
461
- );
462
- }
463
518
  mode = CSS_MODE_IN_LOCAL_RULE;
464
519
  modeNestingLevel = 1;
465
520
  return pos + 1;
466
- }
467
- if (name === "@media" || name === "@supports") {
521
+ } else if (name === "@media" || name === "@supports") {
522
+ // TODO handle nested CSS syntax
468
523
  let pos = end;
469
524
  const [newPos] = eatText(input, pos, eatAtRuleNested);
470
525
  pos = newPos;
471
526
  if (pos === input.length) return pos;
472
527
  if (input.charCodeAt(pos) !== CC_LEFT_CURLY) {
473
- throw new Error(
474
- `Unexpected ${input[pos]} at ${pos} during parsing of @media or @supports (expected '{')`
528
+ this._emitWarning(
529
+ state,
530
+ `Unexpected ${input[pos]} at ${pos} during parsing of @media or @supports (expected '{')`,
531
+ locConverter,
532
+ start,
533
+ pos
475
534
  );
535
+ return pos;
476
536
  }
477
537
  return pos + 1;
478
538
  }
@@ -480,22 +540,56 @@ class CssParser extends Parser {
480
540
  },
481
541
  semicolon: (input, start, end) => {
482
542
  switch (mode) {
483
- case CSS_MODE_AT_IMPORT_EXPECT_URL:
484
- throw new Error(`Expected URL for @import at ${start}`);
485
- case CSS_MODE_AT_IMPORT_EXPECT_MEDIA:
486
- case CSS_MODE_AT_IMPORT_EXPECT_SUPPORTS: {
487
- const { line: sl, column: sc } = locConverter.get(modeData.start);
543
+ case CSS_MODE_AT_IMPORT_EXPECT_URL: {
544
+ this._emitWarning(
545
+ state,
546
+ `Expected URL for @import at ${start}`,
547
+ locConverter,
548
+ start,
549
+ end
550
+ );
551
+ return end;
552
+ }
553
+ case CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA: {
554
+ if (modeData.url === undefined) {
555
+ this._emitWarning(
556
+ state,
557
+ `Expected URL for @import at ${modeData.atRuleStart}`,
558
+ locConverter,
559
+ modeData.atRuleStart,
560
+ modeData.lastPos
561
+ );
562
+ return end;
563
+ }
564
+ const semicolonPos = end;
565
+ end = walkCssTokens.eatWhiteLine(input, end + 1);
566
+ const { line: sl, column: sc } = locConverter.get(
567
+ modeData.atRuleStart
568
+ );
488
569
  const { line: el, column: ec } = locConverter.get(end);
489
- end = eatWhiteLine(input, end);
490
- const media = input.slice(modePos, start).trim();
570
+ const pos = walkCssTokens.eatWhitespaceAndComments(
571
+ input,
572
+ modeData.lastPos
573
+ );
574
+ // Prevent to consider comments as a part of media query
575
+ if (pos !== semicolonPos - 1) {
576
+ modeData.media = input
577
+ .slice(modeData.lastPos, semicolonPos - 1)
578
+ .trim();
579
+ }
491
580
  const dep = new CssImportDependency(
492
- modeData.url,
581
+ modeData.url.trim(),
493
582
  [modeData.start, end],
583
+ modeData.layer,
494
584
  modeData.supports,
495
- media
585
+ modeData.media && modeData.media.length > 0
586
+ ? modeData.media
587
+ : undefined
496
588
  );
497
589
  dep.setLoc(sl, sc, el, ec);
498
590
  module.addDependency(dep);
591
+ modeData = undefined;
592
+ mode = CSS_MODE_TOP_LEVEL;
499
593
  break;
500
594
  }
501
595
  case CSS_MODE_IN_LOCAL_RULE: {
@@ -514,6 +608,7 @@ class CssParser extends Parser {
514
608
  leftCurlyBracket: (input, start, end) => {
515
609
  switch (mode) {
516
610
  case CSS_MODE_TOP_LEVEL:
611
+ allowImportAtRule = false;
517
612
  mode = isTopLevelLocal()
518
613
  ? CSS_MODE_IN_LOCAL_RULE
519
614
  : CSS_MODE_IN_RULE;
@@ -570,6 +665,13 @@ class CssParser extends Parser {
570
665
  lastIdentifier = [start, end];
571
666
  }
572
667
  break;
668
+ case CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA: {
669
+ if (input.slice(start, end).toLowerCase() === "layer") {
670
+ modeData.layer = "";
671
+ modeData.lastPos = end;
672
+ }
673
+ break;
674
+ }
573
675
  }
574
676
  return end;
575
677
  },
@@ -595,7 +697,40 @@ class CssParser extends Parser {
595
697
  }
596
698
  return end;
597
699
  },
700
+ function: (input, start, end) => {
701
+ let name = input.slice(start, end - 1);
702
+
703
+ balanced.push([name, start, end]);
704
+
705
+ switch (mode) {
706
+ case CSS_MODE_IN_LOCAL_RULE: {
707
+ name = name.toLowerCase();
708
+
709
+ if (name === "var") {
710
+ let pos = walkCssTokens.eatWhitespaceAndComments(input, end);
711
+ if (pos === input.length) return pos;
712
+ const [newPos, name] = eatText(input, pos, eatNameInVar);
713
+ if (!name.startsWith("--")) return end;
714
+ const { line: sl, column: sc } = locConverter.get(pos);
715
+ const { line: el, column: ec } = locConverter.get(newPos);
716
+ const dep = new CssSelfLocalIdentifierDependency(
717
+ name.slice(2),
718
+ [pos, newPos],
719
+ "--",
720
+ declaredCssVariables
721
+ );
722
+ dep.setLoc(sl, sc, el, ec);
723
+ module.addDependency(dep);
724
+ return newPos;
725
+ }
726
+ break;
727
+ }
728
+ }
729
+ return end;
730
+ },
598
731
  leftParenthesis: (input, start, end) => {
732
+ balanced.push(["(", start, end]);
733
+
599
734
  switch (mode) {
600
735
  case CSS_MODE_TOP_LEVEL: {
601
736
  modeStack.push(false);
@@ -605,7 +740,9 @@ class CssParser extends Parser {
605
740
  return end;
606
741
  },
607
742
  rightParenthesis: (input, start, end) => {
608
- functionStack.pop();
743
+ const last = balanced[balanced.length - 1];
744
+
745
+ balanced.pop();
609
746
 
610
747
  switch (mode) {
611
748
  case CSS_MODE_TOP_LEVEL: {
@@ -620,6 +757,23 @@ class CssParser extends Parser {
620
757
  }
621
758
  break;
622
759
  }
760
+ case CSS_MODE_AT_IMPORT_EXPECT_URL: {
761
+ if (last && last[0] === "url") {
762
+ modeData.lastPos = end;
763
+ mode = CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA;
764
+ }
765
+ break;
766
+ }
767
+ case CSS_MODE_AT_IMPORT_EXPECT_LAYER_OR_SUPPORTS_OR_MEDIA: {
768
+ if (last && last[0].toLowerCase() === "layer") {
769
+ modeData.layer = input.slice(last[2], end - 1).trim();
770
+ modeData.lastPos = end;
771
+ } else if (last && last[0].toLowerCase() === "supports") {
772
+ modeData.supports = input.slice(last[2], end - 1).trim();
773
+ modeData.lastPos = end;
774
+ }
775
+ break;
776
+ }
623
777
  }
624
778
 
625
779
  return end;
@@ -651,7 +805,7 @@ class CssParser extends Parser {
651
805
  pseudoFunction: (input, start, end) => {
652
806
  let name = input.slice(start, end - 1);
653
807
 
654
- functionStack.push([name, start, end]);
808
+ balanced.push([name, start, end]);
655
809
 
656
810
  switch (mode) {
657
811
  case CSS_MODE_TOP_LEVEL: {
@@ -676,37 +830,6 @@ class CssParser extends Parser {
676
830
  }
677
831
  return end;
678
832
  },
679
- function: (input, start, end) => {
680
- let name = input.slice(start, end - 1);
681
-
682
- functionStack.push([name, start, end]);
683
-
684
- switch (mode) {
685
- case CSS_MODE_IN_LOCAL_RULE: {
686
- name = name.toLowerCase();
687
-
688
- if (name === "var") {
689
- let pos = walkCssTokens.eatWhitespaceAndComments(input, end);
690
- if (pos === input.length) return pos;
691
- const [newPos, name] = eatText(input, pos, eatNameInVar);
692
- if (!name.startsWith("--")) return end;
693
- const { line: sl, column: sc } = locConverter.get(pos);
694
- const { line: el, column: ec } = locConverter.get(newPos);
695
- const dep = new CssSelfLocalIdentifierDependency(
696
- name.slice(2),
697
- [pos, newPos],
698
- "--",
699
- declaredCssVariables
700
- );
701
- dep.setLoc(sl, sc, el, ec);
702
- module.addDependency(dep);
703
- return newPos;
704
- }
705
- break;
706
- }
707
- }
708
- return end;
709
- },
710
833
  comma: (input, start, end) => {
711
834
  switch (mode) {
712
835
  case CSS_MODE_TOP_LEVEL: