webpack 5.94.0 → 5.96.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 (151) hide show
  1. package/README.md +1 -1
  2. package/lib/AsyncDependenciesBlock.js +1 -1
  3. package/lib/BannerPlugin.js +2 -1
  4. package/lib/Chunk.js +30 -0
  5. package/lib/ChunkGraph.js +11 -6
  6. package/lib/ChunkGroup.js +2 -2
  7. package/lib/CleanPlugin.js +4 -5
  8. package/lib/CodeGenerationResults.js +6 -5
  9. package/lib/Compilation.js +71 -48
  10. package/lib/Compiler.js +7 -5
  11. package/lib/ConcatenationScope.js +7 -20
  12. package/lib/ContextModule.js +7 -8
  13. package/lib/CssModule.js +25 -21
  14. package/lib/DefinePlugin.js +14 -8
  15. package/lib/DelegatedModule.js +3 -3
  16. package/lib/DllModule.js +4 -4
  17. package/lib/DynamicEntryPlugin.js +29 -22
  18. package/lib/EnvironmentPlugin.js +3 -2
  19. package/lib/EvalDevToolModulePlugin.js +5 -2
  20. package/lib/EvalSourceMapDevToolPlugin.js +5 -2
  21. package/lib/ExternalModule.js +118 -99
  22. package/lib/ExternalModuleFactoryPlugin.js +33 -9
  23. package/lib/FileSystemInfo.js +12 -8
  24. package/lib/Generator.js +5 -4
  25. package/lib/HotModuleReplacementPlugin.js +8 -6
  26. package/lib/IgnorePlugin.js +19 -1
  27. package/lib/LoaderOptionsPlugin.js +3 -1
  28. package/lib/Module.js +9 -8
  29. package/lib/ModuleSourceTypesConstants.js +100 -0
  30. package/lib/NormalModule.js +27 -13
  31. package/lib/NormalModuleFactory.js +38 -22
  32. package/lib/OptionsApply.js +12 -1
  33. package/lib/ProgressPlugin.js +50 -10
  34. package/lib/RawModule.js +3 -4
  35. package/lib/RuntimeModule.js +3 -4
  36. package/lib/RuntimePlugin.js +11 -4
  37. package/lib/RuntimeTemplate.js +13 -42
  38. package/lib/SourceMapDevToolPlugin.js +10 -7
  39. package/lib/TemplatedPathPlugin.js +9 -3
  40. package/lib/Watching.js +2 -2
  41. package/lib/WebpackOptionsApply.js +42 -21
  42. package/lib/asset/AssetGenerator.js +347 -194
  43. package/lib/asset/AssetModulesPlugin.js +2 -1
  44. package/lib/asset/AssetSourceGenerator.js +82 -27
  45. package/lib/asset/RawDataUrlModule.js +5 -4
  46. package/lib/buildChunkGraph.js +79 -62
  47. package/lib/cache/PackFileCacheStrategy.js +69 -31
  48. package/lib/cache/ResolverCachePlugin.js +248 -173
  49. package/lib/config/defaults.js +135 -126
  50. package/lib/container/ContainerEntryModule.js +3 -4
  51. package/lib/container/ContainerPlugin.js +8 -0
  52. package/lib/container/FallbackModule.js +2 -2
  53. package/lib/container/HoistContainerReferencesPlugin.js +250 -0
  54. package/lib/container/ModuleFederationPlugin.js +38 -1
  55. package/lib/container/RemoteModule.js +4 -2
  56. package/lib/container/RemoteRuntimeModule.js +4 -2
  57. package/lib/css/CssExportsGenerator.js +16 -12
  58. package/lib/css/CssGenerator.js +22 -16
  59. package/lib/css/CssLoadingRuntimeModule.js +7 -6
  60. package/lib/css/CssModulesPlugin.js +122 -77
  61. package/lib/css/CssParser.js +655 -526
  62. package/lib/css/walkCssTokens.js +1168 -338
  63. package/lib/debug/ProfilingPlugin.js +5 -0
  64. package/lib/dependencies/CommonJsExportsParserPlugin.js +5 -2
  65. package/lib/dependencies/CommonJsImportsParserPlugin.js +3 -6
  66. package/lib/dependencies/ContextDependency.js +6 -1
  67. package/lib/dependencies/ContextElementDependency.js +33 -6
  68. package/lib/dependencies/CssExportDependency.js +3 -3
  69. package/lib/dependencies/CssLocalIdentifierDependency.js +26 -17
  70. package/lib/dependencies/CssUrlDependency.js +33 -3
  71. package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +3 -3
  72. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +39 -14
  73. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +15 -82
  74. package/lib/dependencies/HarmonyImportSpecifierDependency.js +5 -2
  75. package/lib/dependencies/ImportParserPlugin.js +9 -7
  76. package/lib/dependencies/LoaderPlugin.js +19 -0
  77. package/lib/dependencies/SystemPlugin.js +2 -1
  78. package/lib/dependencies/URLPlugin.js +7 -1
  79. package/lib/dependencies/WorkerPlugin.js +1 -1
  80. package/lib/esm/ModuleChunkLoadingRuntimeModule.js +4 -2
  81. package/lib/hmr/HotModuleReplacement.runtime.js +1 -0
  82. package/lib/hmr/JavascriptHotModuleReplacement.runtime.js +1 -0
  83. package/lib/hmr/LazyCompilationPlugin.js +16 -4
  84. package/lib/hmr/lazyCompilationBackend.js +1 -7
  85. package/lib/index.js +35 -6
  86. package/lib/javascript/EnableChunkLoadingPlugin.js +2 -2
  87. package/lib/javascript/JavascriptGenerator.js +8 -8
  88. package/lib/javascript/JavascriptModulesPlugin.js +166 -88
  89. package/lib/javascript/JavascriptParser.js +338 -117
  90. package/lib/json/JsonGenerator.js +5 -5
  91. package/lib/library/EnableLibraryPlugin.js +2 -2
  92. package/lib/library/ExportPropertyLibraryPlugin.js +1 -1
  93. package/lib/library/UmdLibraryPlugin.js +16 -8
  94. package/lib/logging/Logger.js +11 -11
  95. package/lib/logging/createConsoleLogger.js +14 -14
  96. package/lib/logging/truncateArgs.js +1 -1
  97. package/lib/node/NodeWatchFileSystem.js +3 -1
  98. package/lib/node/ReadFileCompileAsyncWasmPlugin.js +20 -18
  99. package/lib/node/ReadFileCompileWasmPlugin.js +1 -2
  100. package/lib/node/nodeConsole.js +11 -8
  101. package/lib/optimize/AggressiveSplittingPlugin.js +21 -7
  102. package/lib/optimize/ConcatenatedModule.js +44 -148
  103. package/lib/optimize/FlagIncludedChunksPlugin.js +6 -0
  104. package/lib/optimize/InnerGraphPlugin.js +57 -16
  105. package/lib/optimize/LimitChunkCountPlugin.js +2 -4
  106. package/lib/optimize/MergeDuplicateChunksPlugin.js +2 -2
  107. package/lib/optimize/ModuleConcatenationPlugin.js +4 -2
  108. package/lib/optimize/RealContentHashPlugin.js +1 -1
  109. package/lib/optimize/SideEffectsFlagPlugin.js +6 -3
  110. package/lib/rules/RuleSetCompiler.js +2 -2
  111. package/lib/runtime/GetChunkFilenameRuntimeModule.js +2 -2
  112. package/lib/schemes/DataUriPlugin.js +1 -1
  113. package/lib/serialization/BinaryMiddleware.js +32 -19
  114. package/lib/serialization/ObjectMiddleware.js +23 -9
  115. package/lib/serialization/SerializerMiddleware.js +3 -2
  116. package/lib/serialization/types.js +2 -2
  117. package/lib/sharing/ConsumeSharedModule.js +2 -3
  118. package/lib/sharing/ConsumeSharedRuntimeModule.js +3 -1
  119. package/lib/sharing/ProvideSharedModule.js +2 -3
  120. package/lib/stats/DefaultStatsFactoryPlugin.js +22 -20
  121. package/lib/stats/StatsFactory.js +12 -12
  122. package/lib/stats/StatsPrinter.js +7 -7
  123. package/lib/util/AsyncQueue.js +17 -1
  124. package/lib/util/IterableHelpers.js +1 -1
  125. package/lib/util/LazySet.js +12 -0
  126. package/lib/util/SetHelpers.js +1 -1
  127. package/lib/util/cleverMerge.js +48 -24
  128. package/lib/util/concatenate.js +227 -0
  129. package/lib/util/create-schema-validation.js +22 -9
  130. package/lib/util/deprecation.js +86 -28
  131. package/lib/util/fs.js +10 -10
  132. package/lib/util/hash/wasm-hash.js +12 -1
  133. package/lib/util/magicComment.js +21 -0
  134. package/lib/util/makeSerializable.js +24 -1
  135. package/lib/util/memoize.js +2 -1
  136. package/lib/util/runtime.js +10 -1
  137. package/lib/util/semver.js +130 -23
  138. package/lib/wasm/EnableWasmLoadingPlugin.js +2 -2
  139. package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +3 -3
  140. package/lib/wasm-async/AsyncWebAssemblyGenerator.js +5 -5
  141. package/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js +5 -5
  142. package/lib/wasm-sync/WebAssemblyGenerator.js +8 -9
  143. package/lib/wasm-sync/WebAssemblyJavascriptGenerator.js +5 -5
  144. package/lib/web/FetchCompileAsyncWasmPlugin.js +1 -2
  145. package/lib/web/FetchCompileWasmPlugin.js +1 -2
  146. package/lib/web/JsonpChunkLoadingRuntimeModule.js +6 -6
  147. package/package.json +19 -20
  148. package/schemas/WebpackOptions.check.js +1 -1
  149. package/schemas/WebpackOptions.json +12 -2
  150. package/types.d.ts +817 -269
  151. package/lib/util/mergeScope.js +0 -76
@@ -5,9 +5,12 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ const vm = require("vm");
9
+ const CommentCompilationWarning = require("../CommentCompilationWarning");
8
10
  const ModuleDependencyWarning = require("../ModuleDependencyWarning");
9
11
  const { CSS_MODULE_TYPE_AUTO } = require("../ModuleTypeConstants");
10
12
  const Parser = require("../Parser");
13
+ const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning");
11
14
  const WebpackError = require("../WebpackError");
12
15
  const ConstDependency = require("../dependencies/ConstDependency");
13
16
  const CssExportDependency = require("../dependencies/CssExportDependency");
@@ -16,18 +19,29 @@ const CssLocalIdentifierDependency = require("../dependencies/CssLocalIdentifier
16
19
  const CssSelfLocalIdentifierDependency = require("../dependencies/CssSelfLocalIdentifierDependency");
17
20
  const CssUrlDependency = require("../dependencies/CssUrlDependency");
18
21
  const StaticExportsDependency = require("../dependencies/StaticExportsDependency");
22
+ const binarySearchBounds = require("../util/binarySearchBounds");
19
23
  const { parseResource } = require("../util/identifier");
24
+ const {
25
+ webpackCommentRegExp,
26
+ createMagicCommentContext
27
+ } = require("../util/magicComment");
20
28
  const walkCssTokens = require("./walkCssTokens");
21
29
 
30
+ /** @typedef {import("../Module").BuildInfo} BuildInfo */
31
+ /** @typedef {import("../Module").BuildMeta} BuildMeta */
22
32
  /** @typedef {import("../Parser").ParserState} ParserState */
23
33
  /** @typedef {import("../Parser").PreparsedAst} PreparsedAst */
34
+
24
35
  /** @typedef {[number, number]} Range */
36
+ /** @typedef {{ line: number, column: number }} Position */
37
+ /** @typedef {{ value: string, range: Range, loc: { start: Position, end: Position } }} Comment */
25
38
 
26
39
  const CC_LEFT_CURLY = "{".charCodeAt(0);
27
40
  const CC_RIGHT_CURLY = "}".charCodeAt(0);
28
41
  const CC_COLON = ":".charCodeAt(0);
29
42
  const CC_SLASH = "/".charCodeAt(0);
30
43
  const CC_SEMICOLON = ";".charCodeAt(0);
44
+ const CC_LEFT_PARENTHESIS = "(".charCodeAt(0);
31
45
 
32
46
  // https://www.w3.org/TR/css-syntax-3/#newline
33
47
  // We don't have `preprocessing` stage, so we need specify all of them
@@ -123,22 +137,27 @@ class LocConverter {
123
137
  }
124
138
  }
125
139
 
140
+ const EMPTY_COMMENT_OPTIONS = {
141
+ options: null,
142
+ errors: null
143
+ };
144
+
126
145
  const CSS_MODE_TOP_LEVEL = 0;
127
146
  const CSS_MODE_IN_BLOCK = 1;
128
- const CSS_MODE_IN_AT_IMPORT = 2;
129
- const CSS_MODE_AT_IMPORT_INVALID = 3;
130
- const CSS_MODE_AT_NAMESPACE_INVALID = 4;
131
147
 
132
148
  class CssParser extends Parser {
133
- constructor({
134
- allowModeSwitch = true,
135
- defaultMode = "global",
136
- namedExports = true
137
- } = {}) {
149
+ /**
150
+ * @param {object} options options
151
+ * @param {("pure" | "global" | "local" | "auto")=} options.defaultMode default mode
152
+ * @param {boolean=} options.namedExports is named exports
153
+ */
154
+ constructor({ defaultMode = "pure", namedExports = true } = {}) {
138
155
  super();
139
- this.allowModeSwitch = allowModeSwitch;
140
156
  this.defaultMode = defaultMode;
141
157
  this.namedExports = namedExports;
158
+ /** @type {Comment[] | undefined} */
159
+ this.comments = undefined;
160
+ this.magicCommentContext = createMagicCommentContext();
142
161
  }
143
162
 
144
163
  /**
@@ -175,43 +194,44 @@ class CssParser extends Parser {
175
194
  source = source.slice(1);
176
195
  }
177
196
 
178
- const module = state.module;
197
+ let mode = this.defaultMode;
179
198
 
180
- /** @type {string | undefined} */
181
- let oldDefaultMode;
199
+ const module = state.module;
182
200
 
183
201
  if (
202
+ mode === "auto" &&
184
203
  module.type === CSS_MODULE_TYPE_AUTO &&
185
204
  IS_MODULES.test(
186
205
  parseResource(module.matchResource || module.resource).path
187
206
  )
188
207
  ) {
189
- oldDefaultMode = this.defaultMode;
190
-
191
- this.defaultMode = "local";
208
+ mode = "local";
192
209
  }
193
210
 
211
+ const isModules = mode === "global" || mode === "local";
212
+
194
213
  const locConverter = new LocConverter(source);
195
- /** @type {Set<string>} */
196
- const declaredCssVariables = new Set();
214
+
197
215
  /** @type {number} */
198
216
  let scope = CSS_MODE_TOP_LEVEL;
199
- /** @type {number} */
200
- let blockNestingLevel = 0;
201
217
  /** @type {boolean} */
202
218
  let allowImportAtRule = true;
203
- /** @type {"local" | "global" | undefined} */
204
- let modeData;
205
- /** @type {[number, number] | undefined} */
206
- let lastIdentifier;
207
219
  /** @type [string, number, number][] */
208
220
  const balanced = [];
209
- /** @type {undefined | { start: number, url?: string, urlStart?: number, urlEnd?: number, layer?: string, layerStart?: number, layerEnd?: number, supports?: string, supportsStart?: number, supportsEnd?: number, inSupports?:boolean, media?: string }} */
210
- let importData;
221
+ let lastTokenEndForComments = 0;
222
+
211
223
  /** @type {boolean} */
212
- let inAnimationProperty = false;
224
+ let isNextRulePrelude = isModules;
225
+ /** @type {number} */
226
+ let blockNestingLevel = 0;
227
+ /** @type {"local" | "global" | undefined} */
228
+ let modeData;
213
229
  /** @type {boolean} */
214
- let isNextRulePrelude = true;
230
+ let inAnimationProperty = false;
231
+ /** @type {Set<string>} */
232
+ const declaredCssVariables = new Set();
233
+ /** @type {[number, number, boolean] | undefined} */
234
+ let lastIdentifier;
215
235
 
216
236
  /**
217
237
  * @param {string} input input
@@ -236,34 +256,8 @@ class CssParser extends Parser {
236
256
  * @returns {boolean} true, when in local scope
237
257
  */
238
258
  const isLocalMode = () =>
239
- modeData === "local" ||
240
- (this.defaultMode === "local" && modeData === undefined);
241
- /**
242
- * @param {string} chars characters
243
- * @returns {(input: string, pos: number) => number} function to eat characters
244
- */
245
- const eatUntil = chars => {
246
- const charCodes = Array.from({ length: chars.length }, (_, i) =>
247
- chars.charCodeAt(i)
248
- );
249
- const arr = Array.from(
250
- { length: charCodes.reduce((a, b) => Math.max(a, b), 0) + 1 },
251
- () => false
252
- );
253
- for (const cc of charCodes) {
254
- arr[cc] = true;
255
- }
256
- return (input, pos) => {
257
- for (;;) {
258
- const cc = input.charCodeAt(pos);
259
- if (cc < arr.length && arr[cc]) {
260
- return pos;
261
- }
262
- pos++;
263
- if (pos === input.length) return pos;
264
- }
265
- };
266
- };
259
+ modeData === "local" || (mode === "local" && modeData === undefined);
260
+
267
261
  /**
268
262
  * @param {string} input input
269
263
  * @param {number} pos start position
@@ -295,8 +289,8 @@ class CssParser extends Parser {
295
289
  }
296
290
  return [pos, text.trimEnd()];
297
291
  };
298
- const eatExportName = eatUntil(":};/");
299
- const eatExportValue = eatUntil("};/");
292
+ const eatExportName = walkCssTokens.eatUntil(":};/");
293
+ const eatExportValue = walkCssTokens.eatUntil("};/");
300
294
  /**
301
295
  * @param {string} input input
302
296
  * @param {number} pos start position
@@ -369,7 +363,7 @@ class CssParser extends Parser {
369
363
  pos = walkCssTokens.eatWhiteLine(input, pos);
370
364
  return pos;
371
365
  };
372
- const eatPropertyName = eatUntil(":{};");
366
+ const eatPropertyName = walkCssTokens.eatUntil(":{};");
373
367
  /**
374
368
  * @param {string} input input
375
369
  * @param {number} pos name start position
@@ -401,7 +395,6 @@ class CssParser extends Parser {
401
395
  module.addDependency(dep);
402
396
  declaredCssVariables.add(name);
403
397
  } else if (
404
- !propertyName.startsWith("--") &&
405
398
  OPTIONALLY_VENDOR_PREFIXED_ANIMATION_PROPERTY.test(propertyName)
406
399
  ) {
407
400
  inAnimationProperty = true;
@@ -415,141 +408,149 @@ class CssParser extends Parser {
415
408
  if (inAnimationProperty && lastIdentifier) {
416
409
  const { line: sl, column: sc } = locConverter.get(lastIdentifier[0]);
417
410
  const { line: el, column: ec } = locConverter.get(lastIdentifier[1]);
418
- const name = input.slice(lastIdentifier[0], lastIdentifier[1]);
419
- const dep = new CssSelfLocalIdentifierDependency(name, lastIdentifier);
411
+ const name = lastIdentifier[2]
412
+ ? input.slice(lastIdentifier[0], lastIdentifier[1])
413
+ : input.slice(lastIdentifier[0] + 1, lastIdentifier[1] - 1);
414
+ const dep = new CssSelfLocalIdentifierDependency(name, [
415
+ lastIdentifier[0],
416
+ lastIdentifier[1]
417
+ ]);
420
418
  dep.setLoc(sl, sc, el, ec);
421
419
  module.addDependency(dep);
422
420
  lastIdentifier = undefined;
423
421
  }
424
422
  };
425
- const eatKeyframes = eatUntil("{};/");
426
- const eatNameInVar = eatUntil(",)};/");
427
- walkCssTokens(source, {
428
- isSelector: () => isNextRulePrelude,
429
- url: (input, start, end, contentStart, contentEnd) => {
430
- const value = normalizeUrl(
431
- input.slice(contentStart, contentEnd),
432
- false
433
- );
434
423
 
435
- switch (scope) {
436
- case CSS_MODE_IN_AT_IMPORT: {
437
- // Do not parse URLs in `supports(...)`
438
- if (importData.inSupports) {
439
- break;
440
- }
424
+ const eatUntilSemi = walkCssTokens.eatUntil(";");
425
+ const eatUntilLeftCurly = walkCssTokens.eatUntil("{");
441
426
 
442
- if (importData.url) {
443
- this._emitWarning(
444
- state,
445
- `Duplicate of 'url(...)' in '${input.slice(
446
- importData.start,
447
- end
448
- )}'`,
449
- locConverter,
450
- start,
451
- end
452
- );
427
+ /**
428
+ * @param {string} input input
429
+ * @param {number} start start
430
+ * @param {number} end end
431
+ * @returns {number} end
432
+ */
433
+ const comment = (input, start, end) => {
434
+ if (!this.comments) this.comments = [];
435
+ const { line: sl, column: sc } = locConverter.get(start);
436
+ const { line: el, column: ec } = locConverter.get(end);
437
+
438
+ /** @type {Comment} */
439
+ const comment = {
440
+ value: input.slice(start + 2, end - 2),
441
+ range: [start, end],
442
+ loc: {
443
+ start: { line: sl, column: sc },
444
+ end: { line: el, column: ec }
445
+ }
446
+ };
447
+ this.comments.push(comment);
448
+ return end;
449
+ };
453
450
 
454
- break;
451
+ walkCssTokens(source, {
452
+ comment,
453
+ leftCurlyBracket: (input, start, end) => {
454
+ switch (scope) {
455
+ case CSS_MODE_TOP_LEVEL: {
456
+ allowImportAtRule = false;
457
+ scope = CSS_MODE_IN_BLOCK;
458
+
459
+ if (isModules) {
460
+ blockNestingLevel = 1;
461
+ isNextRulePrelude = isNextNestedSyntax(input, end);
455
462
  }
456
463
 
457
- importData.url = value;
458
- importData.urlStart = start;
459
- importData.urlEnd = end;
460
- break;
461
- }
462
- // Do not parse URLs in import between rules
463
- case CSS_MODE_AT_NAMESPACE_INVALID:
464
- case CSS_MODE_AT_IMPORT_INVALID: {
465
464
  break;
466
465
  }
467
466
  case CSS_MODE_IN_BLOCK: {
468
- // Ignore `url()`, `url('')` and `url("")`, they are valid by spec
469
- if (value.length === 0) {
470
- break;
467
+ if (isModules) {
468
+ blockNestingLevel++;
469
+ isNextRulePrelude = isNextNestedSyntax(input, end);
471
470
  }
472
-
473
- const dep = new CssUrlDependency(value, [start, end], "url");
474
- const { line: sl, column: sc } = locConverter.get(start);
475
- const { line: el, column: ec } = locConverter.get(end);
476
- dep.setLoc(sl, sc, el, ec);
477
- module.addDependency(dep);
478
- module.addCodeGenerationDependency(dep);
479
471
  break;
480
472
  }
481
473
  }
482
474
  return end;
483
475
  },
484
- string: (input, start, end) => {
476
+ rightCurlyBracket: (input, start, end) => {
485
477
  switch (scope) {
486
- case CSS_MODE_IN_AT_IMPORT: {
487
- const insideURLFunction =
488
- balanced[balanced.length - 1] &&
489
- balanced[balanced.length - 1][0] === "url";
490
-
491
- // Do not parse URLs in `supports(...)` and other strings if we already have a URL
492
- if (
493
- importData.inSupports ||
494
- (!insideURLFunction && importData.url)
495
- ) {
496
- break;
497
- }
478
+ case CSS_MODE_IN_BLOCK: {
479
+ if (--blockNestingLevel === 0) {
480
+ scope = CSS_MODE_TOP_LEVEL;
498
481
 
499
- if (insideURLFunction && importData.url) {
500
- this._emitWarning(
501
- state,
502
- `Duplicate of 'url(...)' in '${input.slice(
503
- importData.start,
504
- end
505
- )}'`,
506
- locConverter,
507
- start,
508
- end
509
- );
482
+ if (isModules) {
483
+ isNextRulePrelude = true;
484
+ modeData = undefined;
485
+ }
486
+ } else if (isModules) {
487
+ if (isLocalMode()) {
488
+ processDeclarationValueDone(input);
489
+ inAnimationProperty = false;
490
+ }
510
491
 
511
- break;
492
+ isNextRulePrelude = isNextNestedSyntax(input, end);
512
493
  }
513
-
514
- importData.url = normalizeUrl(
515
- input.slice(start + 1, end - 1),
516
- true
494
+ break;
495
+ }
496
+ }
497
+ return end;
498
+ },
499
+ url: (input, start, end, contentStart, contentEnd) => {
500
+ const { options, errors: commentErrors } = this.parseCommentOptions([
501
+ lastTokenEndForComments,
502
+ end
503
+ ]);
504
+ if (commentErrors) {
505
+ for (const e of commentErrors) {
506
+ const { comment } = e;
507
+ state.module.addWarning(
508
+ new CommentCompilationWarning(
509
+ `Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`,
510
+ comment.loc
511
+ )
517
512
  );
513
+ }
514
+ }
515
+ if (options && options.webpackIgnore !== undefined) {
516
+ if (typeof options.webpackIgnore !== "boolean") {
517
+ const { line: sl, column: sc } = locConverter.get(
518
+ lastTokenEndForComments
519
+ );
520
+ const { line: el, column: ec } = locConverter.get(end);
518
521
 
519
- if (!insideURLFunction) {
520
- importData.urlStart = start;
521
- importData.urlEnd = end;
522
- }
523
-
524
- break;
522
+ state.module.addWarning(
523
+ new UnsupportedFeatureWarning(
524
+ `\`webpackIgnore\` expected a boolean, but received: ${options.webpackIgnore}.`,
525
+ {
526
+ start: { line: sl, column: sc },
527
+ end: { line: el, column: ec }
528
+ }
529
+ )
530
+ );
531
+ } else if (options.webpackIgnore) {
532
+ return end;
525
533
  }
534
+ }
535
+ const value = normalizeUrl(
536
+ input.slice(contentStart, contentEnd),
537
+ false
538
+ );
539
+ // Ignore `url()`, `url('')` and `url("")`, they are valid by spec
540
+ if (value.length === 0) return end;
541
+ const dep = new CssUrlDependency(value, [start, end], "url");
542
+ const { line: sl, column: sc } = locConverter.get(start);
543
+ const { line: el, column: ec } = locConverter.get(end);
544
+ dep.setLoc(sl, sc, el, ec);
545
+ module.addDependency(dep);
546
+ module.addCodeGenerationDependency(dep);
547
+ return end;
548
+ },
549
+ string: (_input, start, end) => {
550
+ switch (scope) {
526
551
  case CSS_MODE_IN_BLOCK: {
527
- // TODO move escaped parsing to tokenizer
528
- const last = balanced[balanced.length - 1];
529
-
530
- if (
531
- last &&
532
- (last[0].replace(/\\/g, "").toLowerCase() === "url" ||
533
- IMAGE_SET_FUNCTION.test(last[0].replace(/\\/g, "")))
534
- ) {
535
- const value = normalizeUrl(input.slice(start + 1, end - 1), true);
536
-
537
- // Ignore `url()`, `url('')` and `url("")`, they are valid by spec
538
- if (value.length === 0) {
539
- break;
540
- }
541
-
542
- const isUrl = last[0].replace(/\\/g, "").toLowerCase() === "url";
543
- const dep = new CssUrlDependency(
544
- value,
545
- [start, end],
546
- isUrl ? "string" : "url"
547
- );
548
- const { line: sl, column: sc } = locConverter.get(start);
549
- const { line: el, column: ec } = locConverter.get(end);
550
- dep.setLoc(sl, sc, el, ec);
551
- module.addDependency(dep);
552
- module.addCodeGenerationDependency(dep);
552
+ if (inAnimationProperty && balanced.length === 0) {
553
+ lastIdentifier = [start, end, false];
553
554
  }
554
555
  }
555
556
  }
@@ -557,264 +558,196 @@ class CssParser extends Parser {
557
558
  },
558
559
  atKeyword: (input, start, end) => {
559
560
  const name = input.slice(start, end).toLowerCase();
560
- if (name === "@namespace") {
561
- scope = CSS_MODE_AT_NAMESPACE_INVALID;
562
- this._emitWarning(
563
- state,
564
- "'@namespace' is not supported in bundled CSS",
565
- locConverter,
566
- start,
567
- end
568
- );
569
- return end;
570
- } else if (name === "@import") {
571
- if (!allowImportAtRule) {
572
- scope = CSS_MODE_AT_IMPORT_INVALID;
573
- this._emitWarning(
574
- state,
575
- "Any '@import' rules must precede all other rules",
576
- locConverter,
577
- start,
578
- end
579
- );
580
- return end;
581
- }
582
561
 
583
- scope = CSS_MODE_IN_AT_IMPORT;
584
- importData = { start };
585
- } else if (
586
- this.allowModeSwitch &&
587
- OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE.test(name)
588
- ) {
589
- let pos = end;
590
- pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
591
- if (pos === input.length) return pos;
592
- const [newPos, name] = eatText(input, pos, eatKeyframes);
593
- if (newPos === input.length) return newPos;
594
- if (input.charCodeAt(newPos) !== CC_LEFT_CURLY) {
562
+ switch (name) {
563
+ case "@namespace": {
595
564
  this._emitWarning(
596
565
  state,
597
- `Unexpected '${input[newPos]}' at ${newPos} during parsing of @keyframes (expected '{')`,
566
+ "'@namespace' is not supported in bundled CSS",
598
567
  locConverter,
599
568
  start,
600
569
  end
601
570
  );
602
571
 
603
- return newPos;
572
+ return eatUntilSemi(input, start);
604
573
  }
605
- if (isLocalMode()) {
606
- const { line: sl, column: sc } = locConverter.get(pos);
607
- const { line: el, column: ec } = locConverter.get(newPos);
608
- const dep = new CssLocalIdentifierDependency(name, [pos, newPos]);
609
- dep.setLoc(sl, sc, el, ec);
610
- module.addDependency(dep);
611
- }
612
- pos = newPos;
613
- return pos + 1;
614
- } else if (this.allowModeSwitch && name === "@property") {
615
- let pos = end;
616
- pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
617
- if (pos === input.length) return pos;
618
- const propertyNameStart = pos;
619
- const [propertyNameEnd, propertyName] = eatText(
620
- input,
621
- pos,
622
- eatKeyframes
623
- );
624
- if (propertyNameEnd === input.length) return propertyNameEnd;
625
- if (!propertyName.startsWith("--")) return propertyNameEnd;
626
- if (input.charCodeAt(propertyNameEnd) !== CC_LEFT_CURLY) {
627
- this._emitWarning(
628
- state,
629
- `Unexpected '${input[propertyNameEnd]}' at ${propertyNameEnd} during parsing of @property (expected '{')`,
630
- locConverter,
631
- start,
632
- end
633
- );
634
-
635
- return propertyNameEnd;
636
- }
637
- const name = propertyName.slice(2);
638
- declaredCssVariables.add(name);
639
- if (isLocalMode()) {
640
- const { line: sl, column: sc } = locConverter.get(pos);
641
- const { line: el, column: ec } = locConverter.get(propertyNameEnd);
642
- const dep = new CssLocalIdentifierDependency(
643
- name,
644
- [propertyNameStart, propertyNameEnd],
645
- "--"
646
- );
647
- dep.setLoc(sl, sc, el, ec);
648
- module.addDependency(dep);
649
- }
650
- pos = propertyNameEnd;
651
- return pos + 1;
652
- } else if (
653
- name === "@media" ||
654
- name === "@supports" ||
655
- name === "@layer" ||
656
- name === "@container"
657
- ) {
658
- modeData = isLocalMode() ? "local" : "global";
659
- isNextRulePrelude = true;
660
- return end;
661
- } else if (this.allowModeSwitch) {
662
- modeData = "global";
663
- isNextRulePrelude = false;
664
- }
665
- return end;
666
- },
667
- semicolon: (input, start, end) => {
668
- switch (scope) {
669
- case CSS_MODE_IN_AT_IMPORT: {
670
- const { start } = importData;
671
-
672
- if (importData.url === undefined) {
673
- this._emitWarning(
674
- state,
675
- `Expected URL in '${input.slice(start, end)}'`,
676
- locConverter,
677
- start,
678
- end
679
- );
680
- importData = undefined;
681
- scope = CSS_MODE_TOP_LEVEL;
682
- return end;
683
- }
684
- if (
685
- importData.urlStart > importData.layerStart ||
686
- importData.urlStart > importData.supportsStart
687
- ) {
574
+ case "@import": {
575
+ if (!allowImportAtRule) {
688
576
  this._emitWarning(
689
577
  state,
690
- `An URL in '${input.slice(
691
- start,
692
- end
693
- )}' should be before 'layer(...)' or 'supports(...)'`,
578
+ "Any '@import' rules must precede all other rules",
694
579
  locConverter,
695
580
  start,
696
581
  end
697
582
  );
698
- importData = undefined;
699
- scope = CSS_MODE_TOP_LEVEL;
700
583
  return end;
701
584
  }
702
- if (importData.layerStart > importData.supportsStart) {
585
+
586
+ const tokens = walkCssTokens.eatImportTokens(input, end, {
587
+ comment
588
+ });
589
+ if (!tokens[3]) return end;
590
+ const semi = tokens[3][1];
591
+ if (!tokens[0]) {
703
592
  this._emitWarning(
704
593
  state,
705
- `The 'layer(...)' in '${input.slice(
706
- start,
707
- end
708
- )}' should be before 'supports(...)'`,
594
+ `Expected URL in '${input.slice(start, semi)}'`,
709
595
  locConverter,
710
596
  start,
711
- end
597
+ semi
712
598
  );
713
- importData = undefined;
714
- scope = CSS_MODE_TOP_LEVEL;
715
599
  return end;
716
600
  }
717
601
 
718
- const semicolonPos = end;
719
- end = walkCssTokens.eatWhiteLine(input, end);
720
- const { line: sl, column: sc } = locConverter.get(start);
721
- const { line: el, column: ec } = locConverter.get(end);
722
- const lastEnd =
723
- importData.supportsEnd ||
724
- importData.layerEnd ||
725
- importData.urlEnd ||
726
- start;
727
- const pos = walkCssTokens.eatWhitespaceAndComments(input, lastEnd);
728
- // Prevent to consider comments as a part of media query
729
- if (pos !== semicolonPos - 1) {
730
- importData.media = input.slice(lastEnd, semicolonPos - 1).trim();
602
+ const urlToken = tokens[0];
603
+ const url = normalizeUrl(
604
+ input.slice(urlToken[2], urlToken[3]),
605
+ true
606
+ );
607
+ const newline = walkCssTokens.eatWhiteLine(input, semi);
608
+ const { options, errors: commentErrors } = this.parseCommentOptions(
609
+ [end, urlToken[1]]
610
+ );
611
+ if (commentErrors) {
612
+ for (const e of commentErrors) {
613
+ const { comment } = e;
614
+ state.module.addWarning(
615
+ new CommentCompilationWarning(
616
+ `Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`,
617
+ comment.loc
618
+ )
619
+ );
620
+ }
621
+ }
622
+ if (options && options.webpackIgnore !== undefined) {
623
+ if (typeof options.webpackIgnore !== "boolean") {
624
+ const { line: sl, column: sc } = locConverter.get(start);
625
+ const { line: el, column: ec } = locConverter.get(newline);
626
+
627
+ state.module.addWarning(
628
+ new UnsupportedFeatureWarning(
629
+ `\`webpackIgnore\` expected a boolean, but received: ${options.webpackIgnore}.`,
630
+ {
631
+ start: { line: sl, column: sc },
632
+ end: { line: el, column: ec }
633
+ }
634
+ )
635
+ );
636
+ } else if (options.webpackIgnore) {
637
+ return newline;
638
+ }
731
639
  }
732
-
733
- const url = importData.url.trim();
734
-
735
640
  if (url.length === 0) {
736
- const dep = new ConstDependency("", [start, end]);
641
+ const { line: sl, column: sc } = locConverter.get(start);
642
+ const { line: el, column: ec } = locConverter.get(newline);
643
+ const dep = new ConstDependency("", [start, newline]);
737
644
  module.addPresentationalDependency(dep);
738
645
  dep.setLoc(sl, sc, el, ec);
739
- } else {
740
- const dep = new CssImportDependency(
741
- url,
742
- [start, end],
743
- importData.layer,
744
- importData.supports,
745
- importData.media && importData.media.length > 0
746
- ? importData.media
747
- : undefined
748
- );
749
- dep.setLoc(sl, sc, el, ec);
750
- module.addDependency(dep);
646
+
647
+ return newline;
751
648
  }
752
649
 
753
- importData = undefined;
754
- scope = CSS_MODE_TOP_LEVEL;
650
+ let layer;
755
651
 
756
- break;
757
- }
758
- case CSS_MODE_AT_IMPORT_INVALID:
759
- case CSS_MODE_AT_NAMESPACE_INVALID: {
760
- scope = CSS_MODE_TOP_LEVEL;
652
+ if (tokens[1]) {
653
+ layer = input.slice(tokens[1][0] + 6, tokens[1][1] - 1).trim();
654
+ }
761
655
 
762
- break;
763
- }
764
- case CSS_MODE_IN_BLOCK: {
765
- if (this.allowModeSwitch) {
766
- processDeclarationValueDone(input);
767
- inAnimationProperty = false;
768
- isNextRulePrelude = isNextNestedSyntax(input, end);
656
+ let supports;
657
+
658
+ if (tokens[2]) {
659
+ supports = input.slice(tokens[2][0] + 9, tokens[2][1] - 1).trim();
769
660
  }
770
- break;
771
- }
772
- }
773
- return end;
774
- },
775
- leftCurlyBracket: (input, start, end) => {
776
- switch (scope) {
777
- case CSS_MODE_TOP_LEVEL: {
778
- allowImportAtRule = false;
779
- scope = CSS_MODE_IN_BLOCK;
780
- blockNestingLevel = 1;
781
661
 
782
- if (this.allowModeSwitch) {
783
- isNextRulePrelude = isNextNestedSyntax(input, end);
662
+ const last = tokens[2] || tokens[1] || tokens[0];
663
+ const mediaStart = walkCssTokens.eatWhitespaceAndComments(
664
+ input,
665
+ last[1]
666
+ );
667
+
668
+ let media;
669
+
670
+ if (mediaStart !== semi - 1) {
671
+ media = input.slice(mediaStart, semi - 1).trim();
784
672
  }
785
673
 
786
- break;
674
+ const { line: sl, column: sc } = locConverter.get(start);
675
+ const { line: el, column: ec } = locConverter.get(newline);
676
+ const dep = new CssImportDependency(
677
+ url,
678
+ [start, newline],
679
+ layer,
680
+ supports && supports.length > 0 ? supports : undefined,
681
+ media && media.length > 0 ? media : undefined
682
+ );
683
+ dep.setLoc(sl, sc, el, ec);
684
+ module.addDependency(dep);
685
+
686
+ return newline;
787
687
  }
788
- case CSS_MODE_IN_BLOCK: {
789
- blockNestingLevel++;
688
+ default: {
689
+ if (isModules) {
690
+ if (OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE.test(name)) {
691
+ const ident = walkCssTokens.eatIdentSequenceOrString(
692
+ input,
693
+ end
694
+ );
695
+ if (!ident) return end;
696
+ const name =
697
+ ident[2] === true
698
+ ? 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
+ }
710
+ return ident[1];
711
+ } else if (name === "@property") {
712
+ const ident = walkCssTokens.eatIdentSequence(input, end);
713
+ if (!ident) return end;
714
+ let name = input.slice(ident[0], ident[1]);
715
+ if (!name.startsWith("--")) return end;
716
+ name = name.slice(2);
717
+ 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
+ }
729
+ return ident[1];
730
+ } else if (isModules && name === "@scope") {
731
+ modeData = isLocalMode() ? "local" : "global";
732
+ isNextRulePrelude = true;
733
+ return end;
734
+ }
790
735
 
791
- if (this.allowModeSwitch) {
792
- isNextRulePrelude = isNextNestedSyntax(input, end);
736
+ isNextRulePrelude = false;
793
737
  }
794
- break;
795
738
  }
796
739
  }
740
+
797
741
  return end;
798
742
  },
799
- rightCurlyBracket: (input, start, end) => {
800
- switch (scope) {
801
- case CSS_MODE_IN_BLOCK: {
802
- if (isLocalMode()) {
803
- processDeclarationValueDone(input);
804
- inAnimationProperty = false;
805
- }
806
- if (--blockNestingLevel === 0) {
807
- scope = CSS_MODE_TOP_LEVEL;
808
-
809
- if (this.allowModeSwitch) {
810
- isNextRulePrelude = true;
811
- modeData = undefined;
812
- }
813
- } else if (this.allowModeSwitch) {
814
- isNextRulePrelude = isNextNestedSyntax(input, end);
815
- }
816
- break;
743
+ semicolon: (input, start, end) => {
744
+ if (isModules && scope === CSS_MODE_IN_BLOCK) {
745
+ if (isLocalMode()) {
746
+ processDeclarationValueDone(input);
747
+ inAnimationProperty = false;
817
748
  }
749
+
750
+ isNextRulePrelude = isNextNestedSyntax(input, end);
818
751
  }
819
752
  return end;
820
753
  },
@@ -824,83 +757,291 @@ class CssParser extends Parser {
824
757
  if (isLocalMode()) {
825
758
  // Handle only top level values and not inside functions
826
759
  if (inAnimationProperty && balanced.length === 0) {
827
- lastIdentifier = [start, end];
760
+ lastIdentifier = [start, end, true];
828
761
  } else {
829
762
  return processLocalDeclaration(input, start, end);
830
763
  }
831
764
  }
832
765
  break;
833
766
  }
834
- case CSS_MODE_IN_AT_IMPORT: {
835
- if (input.slice(start, end).toLowerCase() === "layer") {
836
- importData.layer = "";
837
- importData.layerStart = start;
838
- importData.layerEnd = end;
839
- }
840
- break;
841
- }
842
767
  }
843
768
  return end;
844
769
  },
845
- class: (input, start, end) => {
846
- if (isLocalMode()) {
847
- const name = input.slice(start + 1, end);
848
- const dep = new CssLocalIdentifierDependency(name, [start + 1, end]);
849
- const { line: sl, column: sc } = locConverter.get(start);
850
- const { line: el, column: ec } = locConverter.get(end);
770
+ delim: (input, start, end) => {
771
+ if (isNextRulePrelude && isLocalMode()) {
772
+ const ident = walkCssTokens.skipCommentsAndEatIdentSequence(
773
+ input,
774
+ end
775
+ );
776
+ if (!ident) return end;
777
+ const name = input.slice(ident[0], ident[1]);
778
+ const dep = new CssLocalIdentifierDependency(name, [
779
+ ident[0],
780
+ ident[1]
781
+ ]);
782
+ const { line: sl, column: sc } = locConverter.get(ident[0]);
783
+ const { line: el, column: ec } = locConverter.get(ident[1]);
851
784
  dep.setLoc(sl, sc, el, ec);
852
785
  module.addDependency(dep);
786
+ return ident[1];
853
787
  }
854
788
 
855
789
  return end;
856
790
  },
857
- id: (input, start, end) => {
858
- if (isLocalMode()) {
859
- const name = input.slice(start + 1, end);
860
- const dep = new CssLocalIdentifierDependency(name, [start + 1, end]);
791
+ hash: (input, start, end, isID) => {
792
+ if (isNextRulePrelude && isLocalMode() && isID) {
793
+ const valueStart = start + 1;
794
+ const name = input.slice(valueStart, end);
795
+ const dep = new CssLocalIdentifierDependency(name, [valueStart, end]);
861
796
  const { line: sl, column: sc } = locConverter.get(start);
862
797
  const { line: el, column: ec } = locConverter.get(end);
863
798
  dep.setLoc(sl, sc, el, ec);
864
799
  module.addDependency(dep);
865
800
  }
801
+
866
802
  return end;
867
803
  },
868
- function: (input, start, end) => {
869
- let name = input.slice(start, end - 1);
870
-
871
- balanced.push([name, start, end]);
804
+ colon: (input, start, end) => {
805
+ if (isModules) {
806
+ const ident = walkCssTokens.skipCommentsAndEatIdentSequence(
807
+ input,
808
+ end
809
+ );
810
+ if (!ident) return end;
811
+ const name = input.slice(ident[0], ident[1]).toLowerCase();
872
812
 
873
- if (
874
- scope === CSS_MODE_IN_AT_IMPORT &&
875
- name.toLowerCase() === "supports"
876
- ) {
877
- importData.inSupports = true;
813
+ switch (scope) {
814
+ case CSS_MODE_TOP_LEVEL: {
815
+ if (name === "export") {
816
+ const pos = parseExports(input, ident[1]);
817
+ const dep = new ConstDependency("", [start, pos]);
818
+ module.addPresentationalDependency(dep);
819
+ return pos;
820
+ }
821
+ }
822
+ // falls through
823
+ default: {
824
+ if (isNextRulePrelude) {
825
+ const isFn = input.charCodeAt(ident[1]) === CC_LEFT_PARENTHESIS;
826
+
827
+ if (isFn && name === "local") {
828
+ const end = ident[1] + 1;
829
+ modeData = "local";
830
+ const dep = new ConstDependency("", [start, end]);
831
+ module.addPresentationalDependency(dep);
832
+ balanced.push([":local", start, end]);
833
+ return end;
834
+ } else if (name === "local") {
835
+ modeData = "local";
836
+ // Eat extra whitespace
837
+ end = walkCssTokens.eatWhitespace(input, ident[1]);
838
+
839
+ if (ident[1] === end) {
840
+ this._emitWarning(
841
+ state,
842
+ `Missing whitespace after ':local' in '${input.slice(
843
+ start,
844
+ eatUntilLeftCurly(input, end) + 1
845
+ )}'`,
846
+ locConverter,
847
+ start,
848
+ end
849
+ );
850
+ }
851
+
852
+ const dep = new ConstDependency("", [start, end]);
853
+ module.addPresentationalDependency(dep);
854
+ return end;
855
+ } else if (isFn && name === "global") {
856
+ const end = ident[1] + 1;
857
+ modeData = "global";
858
+ const dep = new ConstDependency("", [start, end]);
859
+ module.addPresentationalDependency(dep);
860
+ balanced.push([":global", start, end]);
861
+ return end;
862
+ } else if (name === "global") {
863
+ modeData = "global";
864
+ // Eat extra whitespace
865
+ end = walkCssTokens.eatWhitespace(input, ident[1]);
866
+
867
+ if (ident[1] === end) {
868
+ this._emitWarning(
869
+ state,
870
+ `Missing whitespace after ':global' in '${input.slice(
871
+ start,
872
+ eatUntilLeftCurly(input, end) + 1
873
+ )}'`,
874
+ locConverter,
875
+ start,
876
+ end
877
+ );
878
+ }
879
+
880
+ const dep = new ConstDependency("", [start, end]);
881
+ module.addPresentationalDependency(dep);
882
+ return end;
883
+ }
884
+ }
885
+ }
886
+ }
878
887
  }
879
888
 
880
- if (isLocalMode()) {
881
- name = name.toLowerCase();
889
+ lastTokenEndForComments = end;
882
890
 
883
- // Don't rename animation name when we have `var()` function
884
- if (inAnimationProperty && balanced.length === 1) {
885
- lastIdentifier = undefined;
886
- }
891
+ return end;
892
+ },
893
+ function: (input, start, end) => {
894
+ const name = input
895
+ .slice(start, end - 1)
896
+ .replace(/\\/g, "")
897
+ .toLowerCase();
898
+
899
+ balanced.push([name, start, end]);
887
900
 
888
- if (name === "var") {
889
- const pos = walkCssTokens.eatWhitespaceAndComments(input, end);
890
- if (pos === input.length) return pos;
891
- const [newPos, name] = eatText(input, pos, eatNameInVar);
892
- if (!name.startsWith("--")) return end;
893
- const { line: sl, column: sc } = locConverter.get(pos);
894
- const { line: el, column: ec } = locConverter.get(newPos);
895
- const dep = new CssSelfLocalIdentifierDependency(
896
- name.slice(2),
897
- [pos, newPos],
898
- "--",
899
- declaredCssVariables
901
+ switch (name) {
902
+ case "src":
903
+ case "url": {
904
+ const string = walkCssTokens.eatString(input, end);
905
+ if (!string) return end;
906
+ const { options, errors: commentErrors } = this.parseCommentOptions(
907
+ [lastTokenEndForComments, end]
908
+ );
909
+ if (commentErrors) {
910
+ for (const e of commentErrors) {
911
+ const { comment } = e;
912
+ state.module.addWarning(
913
+ new CommentCompilationWarning(
914
+ `Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`,
915
+ comment.loc
916
+ )
917
+ );
918
+ }
919
+ }
920
+ if (options && options.webpackIgnore !== undefined) {
921
+ if (typeof options.webpackIgnore !== "boolean") {
922
+ const { line: sl, column: sc } = locConverter.get(string[0]);
923
+ const { line: el, column: ec } = locConverter.get(string[1]);
924
+
925
+ state.module.addWarning(
926
+ new UnsupportedFeatureWarning(
927
+ `\`webpackIgnore\` expected a boolean, but received: ${options.webpackIgnore}.`,
928
+ {
929
+ start: { line: sl, column: sc },
930
+ end: { line: el, column: ec }
931
+ }
932
+ )
933
+ );
934
+ } else if (options.webpackIgnore) {
935
+ return end;
936
+ }
937
+ }
938
+ const value = normalizeUrl(
939
+ input.slice(string[0] + 1, string[1] - 1),
940
+ true
941
+ );
942
+ // Ignore `url()`, `url('')` and `url("")`, they are valid by spec
943
+ if (value.length === 0) return end;
944
+ const isUrl = name === "url" || name === "src";
945
+ const dep = new CssUrlDependency(
946
+ value,
947
+ [string[0], string[1]],
948
+ isUrl ? "string" : "url"
900
949
  );
950
+ const { line: sl, column: sc } = locConverter.get(string[0]);
951
+ const { line: el, column: ec } = locConverter.get(string[1]);
901
952
  dep.setLoc(sl, sc, el, ec);
902
953
  module.addDependency(dep);
903
- return newPos;
954
+ module.addCodeGenerationDependency(dep);
955
+ return string[1];
956
+ }
957
+ default: {
958
+ if (IMAGE_SET_FUNCTION.test(name)) {
959
+ lastTokenEndForComments = end;
960
+ const values = walkCssTokens.eatImageSetStrings(input, end, {
961
+ comment
962
+ });
963
+ if (values.length === 0) return end;
964
+ for (const [index, string] of values.entries()) {
965
+ const value = normalizeUrl(
966
+ input.slice(string[0] + 1, string[1] - 1),
967
+ true
968
+ );
969
+ if (value.length === 0) return end;
970
+ const { options, errors: commentErrors } =
971
+ this.parseCommentOptions([
972
+ index === 0 ? start : values[index - 1][1],
973
+ string[1]
974
+ ]);
975
+ if (commentErrors) {
976
+ for (const e of commentErrors) {
977
+ const { comment } = e;
978
+ state.module.addWarning(
979
+ new CommentCompilationWarning(
980
+ `Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`,
981
+ comment.loc
982
+ )
983
+ );
984
+ }
985
+ }
986
+ if (options && options.webpackIgnore !== undefined) {
987
+ if (typeof options.webpackIgnore !== "boolean") {
988
+ const { line: sl, column: sc } = locConverter.get(
989
+ string[0]
990
+ );
991
+ const { line: el, column: ec } = locConverter.get(
992
+ string[1]
993
+ );
994
+
995
+ state.module.addWarning(
996
+ new UnsupportedFeatureWarning(
997
+ `\`webpackIgnore\` expected a boolean, but received: ${options.webpackIgnore}.`,
998
+ {
999
+ start: { line: sl, column: sc },
1000
+ end: { line: el, column: ec }
1001
+ }
1002
+ )
1003
+ );
1004
+ } else if (options.webpackIgnore) {
1005
+ continue;
1006
+ }
1007
+ }
1008
+ const dep = new CssUrlDependency(
1009
+ value,
1010
+ [string[0], string[1]],
1011
+ "url"
1012
+ );
1013
+ const { line: sl, column: sc } = locConverter.get(string[0]);
1014
+ const { line: el, column: ec } = locConverter.get(string[1]);
1015
+ dep.setLoc(sl, sc, el, ec);
1016
+ module.addDependency(dep);
1017
+ module.addCodeGenerationDependency(dep);
1018
+ }
1019
+ // Can contain `url()` inside, so let's return end to allow parse them
1020
+ return end;
1021
+ } else if (isLocalMode()) {
1022
+ // Don't rename animation name when we have `var()` function
1023
+ if (inAnimationProperty && balanced.length === 1) {
1024
+ lastIdentifier = undefined;
1025
+ }
1026
+
1027
+ 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
1039
+ );
1040
+ dep.setLoc(sl, sc, el, ec);
1041
+ module.addDependency(dep);
1042
+ return ident[1];
1043
+ }
1044
+ }
904
1045
  }
905
1046
  }
906
1047
 
@@ -912,11 +1053,10 @@ class CssParser extends Parser {
912
1053
  return end;
913
1054
  },
914
1055
  rightParenthesis: (input, start, end) => {
915
- const last = balanced[balanced.length - 1];
916
1056
  const popped = balanced.pop();
917
1057
 
918
1058
  if (
919
- this.allowModeSwitch &&
1059
+ isModules &&
920
1060
  popped &&
921
1061
  (popped[0] === ":local" || popped[0] === ":global")
922
1062
  ) {
@@ -926,124 +1066,113 @@ class CssParser extends Parser {
926
1066
  : undefined;
927
1067
  const dep = new ConstDependency("", [start, end]);
928
1068
  module.addPresentationalDependency(dep);
929
-
930
- return end;
931
- }
932
-
933
- switch (scope) {
934
- case CSS_MODE_IN_AT_IMPORT: {
935
- if (last && last[0] === "url" && !importData.inSupports) {
936
- importData.urlStart = last[1];
937
- importData.urlEnd = end;
938
- } else if (
939
- last &&
940
- last[0].toLowerCase() === "layer" &&
941
- !importData.inSupports
942
- ) {
943
- importData.layer = input.slice(last[2], end - 1).trim();
944
- importData.layerStart = last[1];
945
- importData.layerEnd = end;
946
- } else if (last && last[0].toLowerCase() === "supports") {
947
- importData.supports = input.slice(last[2], end - 1).trim();
948
- importData.supportsStart = last[1];
949
- importData.supportsEnd = end;
950
- importData.inSupports = false;
951
- }
952
- break;
953
- }
954
- }
955
-
956
- return end;
957
- },
958
- pseudoClass: (input, start, end) => {
959
- if (this.allowModeSwitch) {
960
- const name = input.slice(start, end).toLowerCase();
961
-
962
- if (name === ":global") {
963
- modeData = "global";
964
- // Eat extra whitespace and comments
965
- end = walkCssTokens.eatWhitespace(input, end);
966
- const dep = new ConstDependency("", [start, end]);
967
- module.addPresentationalDependency(dep);
968
- return end;
969
- } else if (name === ":local") {
970
- modeData = "local";
971
- // Eat extra whitespace and comments
972
- end = walkCssTokens.eatWhitespace(input, end);
973
- const dep = new ConstDependency("", [start, end]);
974
- module.addPresentationalDependency(dep);
975
- return end;
976
- }
977
-
978
- switch (scope) {
979
- case CSS_MODE_TOP_LEVEL: {
980
- if (name === ":export") {
981
- const pos = parseExports(input, end);
982
- const dep = new ConstDependency("", [start, pos]);
983
- module.addPresentationalDependency(dep);
984
- return pos;
985
- }
986
- break;
987
- }
988
- }
989
- }
990
-
991
- return end;
992
- },
993
- pseudoFunction: (input, start, end) => {
994
- let name = input.slice(start, end - 1);
995
-
996
- balanced.push([name, start, end]);
997
-
998
- if (this.allowModeSwitch) {
999
- name = name.toLowerCase();
1000
-
1001
- if (name === ":global") {
1002
- modeData = "global";
1003
- const dep = new ConstDependency("", [start, end]);
1004
- module.addPresentationalDependency(dep);
1005
- } else if (name === ":local") {
1006
- modeData = "local";
1007
- const dep = new ConstDependency("", [start, end]);
1008
- module.addPresentationalDependency(dep);
1009
- }
1010
1069
  }
1011
1070
 
1012
1071
  return end;
1013
1072
  },
1014
1073
  comma: (input, start, end) => {
1015
- if (this.allowModeSwitch) {
1074
+ if (isModules) {
1016
1075
  // Reset stack for `:global .class :local .class-other` selector after
1017
1076
  modeData = undefined;
1018
1077
 
1019
- switch (scope) {
1020
- case CSS_MODE_IN_BLOCK: {
1021
- if (isLocalMode()) {
1022
- processDeclarationValueDone(input);
1023
- }
1024
-
1025
- break;
1026
- }
1078
+ if (scope === CSS_MODE_IN_BLOCK && isLocalMode()) {
1079
+ processDeclarationValueDone(input);
1027
1080
  }
1028
1081
  }
1082
+
1083
+ lastTokenEndForComments = start;
1084
+
1029
1085
  return end;
1030
1086
  }
1031
1087
  });
1032
1088
 
1033
- if (oldDefaultMode) {
1034
- this.defaultMode = oldDefaultMode;
1035
- }
1036
-
1037
- module.buildInfo.strict = true;
1038
- module.buildMeta.exportsType = this.namedExports ? "namespace" : "default";
1089
+ /** @type {BuildInfo} */
1090
+ (module.buildInfo).strict = true;
1091
+ /** @type {BuildMeta} */
1092
+ (module.buildMeta).exportsType = this.namedExports
1093
+ ? "namespace"
1094
+ : "default";
1039
1095
 
1040
1096
  if (!this.namedExports) {
1041
- module.buildMeta.defaultObject = "redirect";
1097
+ /** @type {BuildMeta} */
1098
+ (module.buildMeta).defaultObject = "redirect";
1042
1099
  }
1043
1100
 
1044
1101
  module.addDependency(new StaticExportsDependency([], true));
1045
1102
  return state;
1046
1103
  }
1104
+
1105
+ /**
1106
+ * @param {Range} range range
1107
+ * @returns {Comment[]} comments in the range
1108
+ */
1109
+ getComments(range) {
1110
+ if (!this.comments) return [];
1111
+ const [rangeStart, rangeEnd] = range;
1112
+ /**
1113
+ * @param {Comment} comment comment
1114
+ * @param {number} needle needle
1115
+ * @returns {number} compared
1116
+ */
1117
+ const compare = (comment, needle) =>
1118
+ /** @type {Range} */ (comment.range)[0] - needle;
1119
+ const comments = /** @type {Comment[]} */ (this.comments);
1120
+ let idx = binarySearchBounds.ge(comments, rangeStart, compare);
1121
+ /** @type {Comment[]} */
1122
+ const commentsInRange = [];
1123
+ while (
1124
+ comments[idx] &&
1125
+ /** @type {Range} */ (comments[idx].range)[1] <= rangeEnd
1126
+ ) {
1127
+ commentsInRange.push(comments[idx]);
1128
+ idx++;
1129
+ }
1130
+
1131
+ return commentsInRange;
1132
+ }
1133
+
1134
+ /**
1135
+ * @param {Range} range range of the comment
1136
+ * @returns {{ options: Record<string, any> | null, errors: (Error & { comment: Comment })[] | null }} result
1137
+ */
1138
+ parseCommentOptions(range) {
1139
+ const comments = this.getComments(range);
1140
+ if (comments.length === 0) {
1141
+ return EMPTY_COMMENT_OPTIONS;
1142
+ }
1143
+ /** @type {Record<string, EXPECTED_ANY> } */
1144
+ const options = {};
1145
+ /** @type {(Error & { comment: Comment })[]} */
1146
+ const errors = [];
1147
+ for (const comment of comments) {
1148
+ const { value } = comment;
1149
+ if (value && webpackCommentRegExp.test(value)) {
1150
+ // try compile only if webpack options comment is present
1151
+ try {
1152
+ for (let [key, val] of Object.entries(
1153
+ vm.runInContext(
1154
+ `(function(){return {${value}};})()`,
1155
+ this.magicCommentContext
1156
+ )
1157
+ )) {
1158
+ if (typeof val === "object" && val !== null) {
1159
+ val =
1160
+ val.constructor.name === "RegExp"
1161
+ ? new RegExp(val)
1162
+ : JSON.parse(JSON.stringify(val));
1163
+ }
1164
+ options[key] = val;
1165
+ }
1166
+ } catch (err) {
1167
+ const newErr = new Error(String(/** @type {Error} */ (err).message));
1168
+ newErr.stack = String(/** @type {Error} */ (err).stack);
1169
+ Object.assign(newErr, { comment });
1170
+ errors.push(/** @type (Error & { comment: Comment }) */ (newErr));
1171
+ }
1172
+ }
1173
+ }
1174
+ return { options, errors };
1175
+ }
1047
1176
  }
1048
1177
 
1049
1178
  module.exports = CssParser;