webpack 5.35.1 → 5.37.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 (37) hide show
  1. package/lib/Chunk.js +8 -2
  2. package/lib/ChunkGraph.js +58 -35
  3. package/lib/Compilation.js +73 -43
  4. package/lib/Compiler.js +27 -13
  5. package/lib/Dependency.js +69 -4
  6. package/lib/EntryPlugin.js +1 -1
  7. package/lib/FileSystemInfo.js +1 -1
  8. package/lib/InitFragment.js +21 -6
  9. package/lib/ModuleGraph.js +2 -2
  10. package/lib/NormalModule.js +16 -2
  11. package/lib/NormalModuleFactory.js +27 -23
  12. package/lib/RuntimeGlobals.js +7 -0
  13. package/lib/RuntimePlugin.js +19 -1
  14. package/lib/SourceMapDevToolPlugin.js +1 -1
  15. package/lib/WebpackOptionsApply.js +1 -0
  16. package/lib/buildChunkGraph.js +7 -2
  17. package/lib/cache/PackFileCacheStrategy.js +65 -4
  18. package/lib/config/defaults.js +12 -1
  19. package/lib/config/normalization.js +10 -0
  20. package/lib/dependencies/CreateScriptUrlDependency.js +54 -0
  21. package/lib/dependencies/HarmonyExportInitFragment.js +47 -0
  22. package/lib/dependencies/NullDependency.js +0 -8
  23. package/lib/dependencies/WorkerPlugin.js +32 -4
  24. package/lib/javascript/JavascriptParser.js +39 -31
  25. package/lib/optimize/InnerGraphPlugin.js +8 -9
  26. package/lib/runtime/CreateScriptUrlRuntimeModule.js +61 -0
  27. package/lib/runtime/LoadScriptRuntimeModule.js +10 -2
  28. package/lib/util/AsyncQueue.js +6 -1
  29. package/lib/util/comparators.js +22 -16
  30. package/lib/util/fs.js +8 -8
  31. package/lib/util/internalSerializables.js +2 -0
  32. package/lib/webworker/ImportScriptsChunkLoadingPlugin.js +13 -1
  33. package/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js +14 -4
  34. package/package.json +5 -5
  35. package/schemas/WebpackOptions.check.js +1 -1
  36. package/schemas/WebpackOptions.json +35 -0
  37. package/types.d.ts +479 -44
@@ -168,6 +168,13 @@ exports.scriptNonce = "__webpack_require__.nc";
168
168
  */
169
169
  exports.loadScript = "__webpack_require__.l";
170
170
 
171
+ /**
172
+ * function to promote a string to a TrustedScriptURL using webpack's Trusted
173
+ * Types policy
174
+ * Arguments: (url: string) => TrustedScriptURL
175
+ */
176
+ exports.createScriptUrl = "__webpack_require__.tu";
177
+
171
178
  /**
172
179
  * the chunk name of the chunk with the runtime
173
180
  */
@@ -13,6 +13,7 @@ const AutoPublicPathRuntimeModule = require("./runtime/AutoPublicPathRuntimeModu
13
13
  const CompatGetDefaultExportRuntimeModule = require("./runtime/CompatGetDefaultExportRuntimeModule");
14
14
  const CompatRuntimeModule = require("./runtime/CompatRuntimeModule");
15
15
  const CreateFakeNamespaceObjectRuntimeModule = require("./runtime/CreateFakeNamespaceObjectRuntimeModule");
16
+ const CreateScriptUrlRuntimeModule = require("./runtime/CreateScriptUrlRuntimeModule");
16
17
  const DefinePropertyGettersRuntimeModule = require("./runtime/DefinePropertyGettersRuntimeModule");
17
18
  const EnsureChunkRuntimeModule = require("./runtime/EnsureChunkRuntimeModule");
18
19
  const GetChunkFilenameRuntimeModule = require("./runtime/GetChunkFilenameRuntimeModule");
@@ -38,6 +39,7 @@ const GLOBALS_ON_REQUIRE = [
38
39
  RuntimeGlobals.runtimeId,
39
40
  RuntimeGlobals.compatGetDefaultExport,
40
41
  RuntimeGlobals.createFakeNamespaceObject,
42
+ RuntimeGlobals.createScriptUrl,
41
43
  RuntimeGlobals.definePropertyGetters,
42
44
  RuntimeGlobals.ensureChunk,
43
45
  RuntimeGlobals.entryModuleId,
@@ -319,7 +321,23 @@ class RuntimePlugin {
319
321
  compilation.hooks.runtimeRequirementInTree
320
322
  .for(RuntimeGlobals.loadScript)
321
323
  .tap("RuntimePlugin", (chunk, set) => {
322
- compilation.addRuntimeModule(chunk, new LoadScriptRuntimeModule());
324
+ const withCreateScriptUrl = !!compilation.outputOptions.trustedTypes;
325
+ if (withCreateScriptUrl) {
326
+ set.add(RuntimeGlobals.createScriptUrl);
327
+ }
328
+ compilation.addRuntimeModule(
329
+ chunk,
330
+ new LoadScriptRuntimeModule(withCreateScriptUrl)
331
+ );
332
+ return true;
333
+ });
334
+ compilation.hooks.runtimeRequirementInTree
335
+ .for(RuntimeGlobals.createScriptUrl)
336
+ .tap("RuntimePlugin", (chunk, set) => {
337
+ compilation.addRuntimeModule(
338
+ chunk,
339
+ new CreateScriptUrlRuntimeModule()
340
+ );
323
341
  return true;
324
342
  });
325
343
  compilation.hooks.runtimeRequirementInTree
@@ -16,7 +16,6 @@ const createHash = require("./util/createHash");
16
16
  const { relative, dirname } = require("./util/fs");
17
17
  const { absolutify } = require("./util/identifier");
18
18
 
19
- /** @typedef {import("source-map").RawSourceMap} SourceMap */
20
19
  /** @typedef {import("webpack-sources").MapOptions} MapOptions */
21
20
  /** @typedef {import("webpack-sources").Source} Source */
22
21
  /** @typedef {import("../declarations/plugins/SourceMapDevToolPlugin").SourceMapDevToolPluginOptions} SourceMapDevToolPluginOptions */
@@ -26,6 +25,7 @@ const { absolutify } = require("./util/identifier");
26
25
  /** @typedef {import("./Compilation").AssetInfo} AssetInfo */
27
26
  /** @typedef {import("./Compiler")} Compiler */
28
27
  /** @typedef {import("./Module")} Module */
28
+ /** @typedef {import("./NormalModule").SourceMap} SourceMap */
29
29
  /** @typedef {import("./util/Hash")} Hash */
30
30
 
31
31
  const validate = createSchemaValidation(
@@ -569,6 +569,7 @@ class WebpackOptionsApply extends OptionsApply {
569
569
  ),
570
570
  snapshot: options.snapshot,
571
571
  maxAge: cacheOptions.maxAge,
572
+ profile: cacheOptions.profile,
572
573
  allowCollectingMemory: cacheOptions.allowCollectingMemory
573
574
  }),
574
575
  cacheOptions.idleTimeout,
@@ -997,10 +997,15 @@ const visitModules = (
997
997
  };
998
998
 
999
999
  const processChunkGroupsForCombining = () => {
1000
- loop: for (const info of chunkGroupsForCombining) {
1000
+ for (const info of chunkGroupsForCombining) {
1001
1001
  for (const source of info.availableSources) {
1002
- if (!source.minAvailableModules) continue loop;
1002
+ if (!source.minAvailableModules) {
1003
+ chunkGroupsForCombining.delete(info);
1004
+ break;
1005
+ }
1003
1006
  }
1007
+ }
1008
+ for (const info of chunkGroupsForCombining) {
1004
1009
  const availableModules = /** @type {ModuleSetPlus} */ (new Set());
1005
1010
  availableModules.plus = EMPTY_SET;
1006
1011
  const mergeSet = set => {
@@ -561,7 +561,40 @@ class PackContentItems {
561
561
  this.map = map;
562
562
  }
563
563
 
564
- serialize({ write, snapshot, rollback, logger }) {
564
+ serialize({ write, snapshot, rollback, logger, profile }) {
565
+ if (profile) {
566
+ write(false);
567
+ for (const [key, value] of this.map) {
568
+ const s = snapshot();
569
+ try {
570
+ write(key);
571
+ const start = process.hrtime();
572
+ write(value);
573
+ const durationHr = process.hrtime(start);
574
+ const duration = durationHr[0] * 1000 + durationHr[1] / 1e6;
575
+ if (duration > 1) {
576
+ if (duration > 500)
577
+ logger.error(`Serialization of '${key}': ${duration} ms`);
578
+ else if (duration > 50)
579
+ logger.warn(`Serialization of '${key}': ${duration} ms`);
580
+ else if (duration > 10)
581
+ logger.info(`Serialization of '${key}': ${duration} ms`);
582
+ else if (duration > 5)
583
+ logger.log(`Serialization of '${key}': ${duration} ms`);
584
+ else logger.debug(`Serialization of '${key}': ${duration} ms`);
585
+ }
586
+ } catch (e) {
587
+ rollback(s);
588
+ if (e === NOT_SERIALIZABLE) continue;
589
+ logger.warn(
590
+ `Skipped not serializable cache item '${key}': ${e.message}`
591
+ );
592
+ logger.debug(e.stack);
593
+ }
594
+ }
595
+ write(null);
596
+ return;
597
+ }
565
598
  // Try to serialize all at once
566
599
  const s = snapshot();
567
600
  try {
@@ -590,9 +623,32 @@ class PackContentItems {
590
623
  }
591
624
  }
592
625
 
593
- deserialize({ read }) {
626
+ deserialize({ read, logger, profile }) {
594
627
  if (read()) {
595
628
  this.map = read();
629
+ } else if (profile) {
630
+ const map = new Map();
631
+ let key = read();
632
+ while (key !== null) {
633
+ const start = process.hrtime();
634
+ const value = read();
635
+ const durationHr = process.hrtime(start);
636
+ const duration = durationHr[0] * 1000 + durationHr[1] / 1e6;
637
+ if (duration > 1) {
638
+ if (duration > 100)
639
+ logger.error(`Deserialization of '${key}': ${duration} ms`);
640
+ else if (duration > 20)
641
+ logger.warn(`Deserialization of '${key}': ${duration} ms`);
642
+ else if (duration > 5)
643
+ logger.info(`Deserialization of '${key}': ${duration} ms`);
644
+ else if (duration > 2)
645
+ logger.log(`Deserialization of '${key}': ${duration} ms`);
646
+ else logger.debug(`Deserialization of '${key}': ${duration} ms`);
647
+ }
648
+ map.set(key, value);
649
+ key = read();
650
+ }
651
+ this.map = map;
596
652
  } else {
597
653
  const map = new Map();
598
654
  let key = read();
@@ -787,6 +843,7 @@ class PackFileCacheStrategy {
787
843
  * @param {Logger} options.logger a logger
788
844
  * @param {SnapshotOptions} options.snapshot options regarding snapshotting
789
845
  * @param {number} options.maxAge max age of cache items
846
+ * @param {boolean} options.profile track and log detailed timing information for individual cache items
790
847
  * @param {boolean} options.allowCollectingMemory allow to collect unused memory created during deserialization
791
848
  */
792
849
  constructor({
@@ -798,6 +855,7 @@ class PackFileCacheStrategy {
798
855
  logger,
799
856
  snapshot,
800
857
  maxAge,
858
+ profile,
801
859
  allowCollectingMemory
802
860
  }) {
803
861
  this.fileSerializer = createFileSerializer(fs);
@@ -812,6 +870,7 @@ class PackFileCacheStrategy {
812
870
  this.version = version;
813
871
  this.logger = logger;
814
872
  this.maxAge = maxAge;
873
+ this.profile = profile;
815
874
  this.allowCollectingMemory = allowCollectingMemory;
816
875
  this.snapshot = snapshot;
817
876
  /** @type {Set<string>} */
@@ -840,7 +899,7 @@ class PackFileCacheStrategy {
840
899
  * @returns {Promise<Pack>} the pack
841
900
  */
842
901
  _openPack() {
843
- const { logger, cacheLocation, version } = this;
902
+ const { logger, profile, cacheLocation, version } = this;
844
903
  /** @type {Snapshot} */
845
904
  let buildSnapshot;
846
905
  /** @type {Set<string>} */
@@ -857,6 +916,7 @@ class PackFileCacheStrategy {
857
916
  filename: `${cacheLocation}/index.pack`,
858
917
  extension: ".pack",
859
918
  logger,
919
+ profile,
860
920
  retainedBuffer: this.allowCollectingMemory
861
921
  ? allowCollectingMemory
862
922
  : undefined
@@ -1172,7 +1232,8 @@ class PackFileCacheStrategy {
1172
1232
  .serialize(content, {
1173
1233
  filename: `${this.cacheLocation}/index.pack`,
1174
1234
  extension: ".pack",
1175
- logger: this.logger
1235
+ logger: this.logger,
1236
+ profile: this.profile
1176
1237
  })
1177
1238
  .then(() => {
1178
1239
  for (const dep of newBuildDependencies) {
@@ -293,6 +293,7 @@ const applyCacheDefaults = (cache, { name, mode, development }) => {
293
293
  );
294
294
  D(cache, "hashAlgorithm", "md4");
295
295
  D(cache, "store", "pack");
296
+ D(cache, "profile", false);
296
297
  D(cache, "idleTimeout", 60000);
297
298
  D(cache, "idleTimeoutForInitialStore", 0);
298
299
  D(cache, "maxMemoryGenerations", development ? 5 : Infinity);
@@ -731,6 +732,16 @@ const applyOutputDefaults = (
731
732
  F(output.environment, "dynamicImport", () => tp && tp.dynamicImport);
732
733
  F(output.environment, "module", () => tp && tp.module);
733
734
 
735
+ const { trustedTypes } = output;
736
+ if (trustedTypes) {
737
+ F(
738
+ trustedTypes,
739
+ "policyName",
740
+ () =>
741
+ output.uniqueName.replace(/[^a-zA-Z0-9\-#=_/@.%]+/g, "_") || "webpack"
742
+ );
743
+ }
744
+
734
745
  /**
735
746
  * @param {function(EntryDescription): void} fn iterator
736
747
  * @returns {void}
@@ -948,7 +959,7 @@ const applyOptimizationDefaults = (
948
959
  A(splitChunks, "defaultSizeTypes", () => ["javascript", "unknown"]);
949
960
  D(splitChunks, "hidePathInfo", production);
950
961
  D(splitChunks, "chunks", "async");
951
- D(splitChunks, "usedExports", true);
962
+ D(splitChunks, "usedExports", optimization.usedExports === true);
952
963
  D(splitChunks, "minChunks", 1);
953
964
  F(splitChunks, "minSize", () => (production ? 20000 : 10000));
954
965
  F(splitChunks, "minRemainingSize", () => (development ? 0 : undefined));
@@ -131,6 +131,7 @@ const getNormalizedWebpackOptions = config => {
131
131
  type: "filesystem",
132
132
  maxMemoryGenerations: cache.maxMemoryGenerations,
133
133
  maxAge: cache.maxAge,
134
+ profile: cache.profile,
134
135
  buildDependencies: cloneObject(cache.buildDependencies),
135
136
  cacheDirectory: cache.cacheDirectory,
136
137
  cacheLocation: cache.cacheLocation,
@@ -337,6 +338,15 @@ const getNormalizedWebpackOptions = config => {
337
338
  sourceMapFilename: output.sourceMapFilename,
338
339
  sourcePrefix: output.sourcePrefix,
339
340
  strictModuleExceptionHandling: output.strictModuleExceptionHandling,
341
+ trustedTypes: optionalNestedConfig(
342
+ output.trustedTypes,
343
+ trustedTypes => {
344
+ if (trustedTypes === true) return {};
345
+ if (typeof trustedTypes === "string")
346
+ return { policyName: trustedTypes };
347
+ return { ...trustedTypes };
348
+ }
349
+ ),
340
350
  uniqueName: output.uniqueName,
341
351
  wasmLoading: output.wasmLoading,
342
352
  webassemblyModuleFilename: output.webassemblyModuleFilename,
@@ -0,0 +1,54 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ Author Tobias Koppers @sokra
4
+ */
5
+
6
+ "use strict";
7
+
8
+ const RuntimeGlobals = require("../RuntimeGlobals");
9
+ const makeSerializable = require("../util/makeSerializable");
10
+ const NullDependency = require("./NullDependency");
11
+
12
+ /** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
13
+ /** @typedef {import("../Dependency")} Dependency */
14
+ /** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
15
+
16
+ class CreateScriptUrlDependency extends NullDependency {
17
+ /**
18
+ * @param {[number, number]} range range
19
+ */
20
+ constructor(range) {
21
+ super();
22
+ this.range = range;
23
+ }
24
+
25
+ get type() {
26
+ return "create script url";
27
+ }
28
+ }
29
+
30
+ CreateScriptUrlDependency.Template = class CreateScriptUrlDependencyTemplate extends (
31
+ NullDependency.Template
32
+ ) {
33
+ /**
34
+ * @param {Dependency} dependency the dependency for which the template should be applied
35
+ * @param {ReplaceSource} source the current replace source which can be modified
36
+ * @param {DependencyTemplateContext} templateContext the context object
37
+ * @returns {void}
38
+ */
39
+ apply(dependency, source, { runtimeRequirements }) {
40
+ const dep = /** @type {CreateScriptUrlDependency} */ (dependency);
41
+
42
+ runtimeRequirements.add(RuntimeGlobals.createScriptUrl);
43
+
44
+ source.insert(dep.range[0], `${RuntimeGlobals.createScriptUrl}(`);
45
+ source.insert(dep.range[1], ")");
46
+ }
47
+ };
48
+
49
+ makeSerializable(
50
+ CreateScriptUrlDependency,
51
+ "webpack/lib/dependencies/CreateScriptUrlDependency"
52
+ );
53
+
54
+ module.exports = CreateScriptUrlDependency;
@@ -48,6 +48,53 @@ class HarmonyExportInitFragment extends InitFragment {
48
48
  this.unusedExports = unusedExports;
49
49
  }
50
50
 
51
+ /**
52
+ * @param {HarmonyExportInitFragment[]} fragments all fragments to merge
53
+ * @returns {HarmonyExportInitFragment} merged fragment
54
+ */
55
+ mergeAll(fragments) {
56
+ let exportMap;
57
+ let exportMapOwned = false;
58
+ let unusedExports;
59
+ let unusedExportsOwned = false;
60
+
61
+ for (const fragment of fragments) {
62
+ if (fragment.exportMap.size !== 0) {
63
+ if (exportMap === undefined) {
64
+ exportMap = fragment.exportMap;
65
+ exportMapOwned = false;
66
+ } else {
67
+ if (!exportMapOwned) {
68
+ exportMap = new Map(exportMap);
69
+ exportMapOwned = true;
70
+ }
71
+ for (const [key, value] of fragment.exportMap) {
72
+ if (!exportMap.has(key)) exportMap.set(key, value);
73
+ }
74
+ }
75
+ }
76
+ if (fragment.unusedExports.size !== 0) {
77
+ if (unusedExports === undefined) {
78
+ unusedExports = fragment.unusedExports;
79
+ unusedExportsOwned = false;
80
+ } else {
81
+ if (!unusedExportsOwned) {
82
+ unusedExports = new Set(unusedExports);
83
+ unusedExportsOwned = true;
84
+ }
85
+ for (const value of fragment.unusedExports) {
86
+ unusedExports.add(value);
87
+ }
88
+ }
89
+ }
90
+ }
91
+ return new HarmonyExportInitFragment(
92
+ this.exportsArgument,
93
+ exportMap,
94
+ unusedExports
95
+ );
96
+ }
97
+
51
98
  merge(other) {
52
99
  let exportMap;
53
100
  if (this.exportMap.size === 0) {
@@ -19,14 +19,6 @@ class NullDependency extends Dependency {
19
19
  get type() {
20
20
  return "null";
21
21
  }
22
-
23
- serialize({ write }) {
24
- write(this.loc);
25
- }
26
-
27
- deserialize({ read }) {
28
- this.loc = read();
29
- }
30
22
  }
31
23
 
32
24
  NullDependency.Template = class NullDependencyTemplate extends (
@@ -9,12 +9,13 @@ const { pathToFileURL } = require("url");
9
9
  const AsyncDependenciesBlock = require("../AsyncDependenciesBlock");
10
10
  const CommentCompilationWarning = require("../CommentCompilationWarning");
11
11
  const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning");
12
- const formatLocation = require("../formatLocation");
13
12
  const EnableChunkLoadingPlugin = require("../javascript/EnableChunkLoadingPlugin");
14
13
  const { equals } = require("../util/ArrayHelpers");
14
+ const createHash = require("../util/createHash");
15
15
  const { contextify } = require("../util/identifier");
16
16
  const EnableWasmLoadingPlugin = require("../wasm/EnableWasmLoadingPlugin");
17
17
  const ConstDependency = require("./ConstDependency");
18
+ const CreateScriptUrlDependency = require("./CreateScriptUrlDependency");
18
19
  const {
19
20
  harmonySpecifierTag
20
21
  } = require("./HarmonyImportDependencyParserPlugin");
@@ -27,6 +28,7 @@ const WorkerDependency = require("./WorkerDependency");
27
28
  /** @typedef {import("estree").SpreadElement} SpreadElement */
28
29
  /** @typedef {import("../Compiler")} Compiler */
29
30
  /** @typedef {import("../Entrypoint").EntryOptions} EntryOptions */
31
+ /** @typedef {import("../Parser").ParserState} ParserState */
30
32
  /** @typedef {import("../javascript/BasicEvaluatedExpression")} BasicEvaluatedExpression */
31
33
  /** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
32
34
  /** @typedef {import("./HarmonyImportDependencyParserPlugin").HarmonySettings} HarmonySettings */
@@ -42,6 +44,9 @@ const DEFAULT_SYNTAX = [
42
44
  "Worker from worker_threads"
43
45
  ];
44
46
 
47
+ /** @type {WeakMap<ParserState, number>} */
48
+ const workerIndexMap = new WeakMap();
49
+
45
50
  class WorkerPlugin {
46
51
  constructor(chunkLoading, wasmLoading) {
47
52
  this._chunkLoading = chunkLoading;
@@ -74,6 +79,10 @@ class WorkerPlugin {
74
79
  WorkerDependency,
75
80
  new WorkerDependency.Template()
76
81
  );
82
+ compilation.dependencyTemplates.set(
83
+ CreateScriptUrlDependency,
84
+ new CreateScriptUrlDependency.Template()
85
+ );
77
86
 
78
87
  /**
79
88
  * @param {JavascriptParser} parser the parser
@@ -264,9 +273,20 @@ class WorkerPlugin {
264
273
  }
265
274
 
266
275
  if (!entryOptions.runtime) {
267
- entryOptions.runtime = `${cachedContextify(
276
+ let i = workerIndexMap.get(parser.state) || 0;
277
+ workerIndexMap.set(parser.state, i + 1);
278
+ let name = `${cachedContextify(
268
279
  parser.state.module.identifier()
269
- )}|${formatLocation(expr.loc)}`;
280
+ )}|${i}`;
281
+ const hash = createHash(compilation.outputOptions.hashFunction);
282
+ hash.update(name);
283
+ const digest = /** @type {string} */ (hash.digest(
284
+ compilation.outputOptions.hashDigest
285
+ ));
286
+ entryOptions.runtime = digest.slice(
287
+ 0,
288
+ compilation.outputOptions.hashDigestLength
289
+ );
270
290
  }
271
291
 
272
292
  const block = new AsyncDependenciesBlock({
@@ -282,7 +302,14 @@ class WorkerPlugin {
282
302
  dep.loc = expr.loc;
283
303
  block.addDependency(dep);
284
304
  parser.state.module.addBlock(block);
285
- parser.walkExpression(expr.callee);
305
+
306
+ if (compilation.outputOptions.trustedTypes) {
307
+ const dep = new CreateScriptUrlDependency(
308
+ expr.arguments[0].range
309
+ );
310
+ dep.loc = expr.loc;
311
+ parser.state.module.addDependency(dep);
312
+ }
286
313
 
287
314
  if (expressions.type) {
288
315
  const expr = expressions.type;
@@ -314,6 +341,7 @@ class WorkerPlugin {
314
341
  parser.state.module.addPresentationalDependency(dep2);
315
342
  }
316
343
 
344
+ parser.walkExpression(expr.callee);
317
345
  for (const key of Object.keys(expressions)) {
318
346
  if (expressions[key]) parser.walkExpression(expressions[key]);
319
347
  }
@@ -161,7 +161,7 @@ class JavascriptParser extends Parser {
161
161
  evaluateCallExpressionMember: new HookMap(
162
162
  () => new SyncBailHook(["expression", "param"])
163
163
  ),
164
- /** @type {HookMap<SyncBailHook<[ExpressionNode | DeclarationNode, number], boolean | void>>} */
164
+ /** @type {HookMap<SyncBailHook<[ExpressionNode | DeclarationNode | PrivateIdentifierNode, number], boolean | void>>} */
165
165
  isPure: new HookMap(
166
166
  () => new SyncBailHook(["expression", "commentsStartPosition"])
167
167
  ),
@@ -176,8 +176,10 @@ class JavascriptParser extends Parser {
176
176
  statementIf: new SyncBailHook(["statement"]),
177
177
  /** @type {SyncBailHook<[ExpressionNode, ClassExpressionNode | ClassDeclarationNode], boolean | void>} */
178
178
  classExtendsExpression: new SyncBailHook(["expression", "statement"]),
179
- /** @type {SyncBailHook<[MethodDefinitionNode, ClassExpressionNode | ClassDeclarationNode], boolean | void>} */
179
+ /** @type {SyncBailHook<[MethodDefinitionNode | PropertyDefinitionNode, ClassExpressionNode | ClassDeclarationNode], boolean | void>} */
180
180
  classBodyElement: new SyncBailHook(["element", "statement"]),
181
+ /** @type {SyncBailHook<[ExpressionNode, MethodDefinitionNode | PropertyDefinitionNode, ClassExpressionNode | ClassDeclarationNode], boolean | void>} */
182
+ classBodyValue: new SyncBailHook(["expression", "element", "statement"]),
181
183
  /** @type {HookMap<SyncBailHook<[LabeledStatementNode], boolean | void>>} */
182
184
  label: new HookMap(() => new SyncBailHook(["statement"])),
183
185
  /** @type {SyncBailHook<[StatementNode, ImportSource], boolean | void>} */
@@ -1363,29 +1365,30 @@ class JavascriptParser extends Parser {
1363
1365
  }
1364
1366
  }
1365
1367
  if (classy.body && classy.body.type === "ClassBody") {
1366
- const wasTopLevel = this.scope.topLevelScope;
1367
- for (const classElement of classy.body.body) {
1368
+ for (const classElement of /** @type {TODO} */ (classy.body.body)) {
1368
1369
  if (!this.hooks.classBodyElement.call(classElement, classy)) {
1369
- if (classElement.type === "MethodDefinition") {
1370
- this.scope.topLevelScope = false;
1371
- this.walkMethodDefinition(classElement);
1372
- this.scope.topLevelScope = wasTopLevel;
1370
+ if (classElement.computed && classElement.key) {
1371
+ this.walkExpression(classElement.key);
1372
+ }
1373
+ if (classElement.value) {
1374
+ if (
1375
+ !this.hooks.classBodyValue.call(
1376
+ classElement.value,
1377
+ classElement,
1378
+ classy
1379
+ )
1380
+ ) {
1381
+ const wasTopLevel = this.scope.topLevelScope;
1382
+ this.scope.topLevelScope = false;
1383
+ this.walkExpression(classElement.value);
1384
+ this.scope.topLevelScope = wasTopLevel;
1385
+ }
1373
1386
  }
1374
- // TODO add support for ClassProperty here once acorn supports it
1375
1387
  }
1376
1388
  }
1377
1389
  }
1378
1390
  }
1379
1391
 
1380
- walkMethodDefinition(methodDefinition) {
1381
- if (methodDefinition.computed && methodDefinition.key) {
1382
- this.walkExpression(methodDefinition.key);
1383
- }
1384
- if (methodDefinition.value) {
1385
- this.walkExpression(methodDefinition.value);
1386
- }
1387
- }
1388
-
1389
1392
  // Pre walking iterates the scope for variable declarations
1390
1393
  preWalkStatements(statements) {
1391
1394
  for (let index = 0, len = statements.length; index < len; index++) {
@@ -3316,7 +3319,7 @@ class JavascriptParser extends Parser {
3316
3319
  }
3317
3320
 
3318
3321
  /**
3319
- * @param {ExpressionNode | DeclarationNode | null | undefined} expr an expression
3322
+ * @param {ExpressionNode | DeclarationNode | PrivateIdentifierNode | null | undefined} expr an expression
3320
3323
  * @param {number} commentsStartPos source position from which annotation comments are checked
3321
3324
  * @returns {boolean} true, when the expression is pure
3322
3325
  */
@@ -3328,27 +3331,32 @@ class JavascriptParser extends Parser {
3328
3331
  if (typeof result === "boolean") return result;
3329
3332
  switch (expr.type) {
3330
3333
  case "ClassDeclaration":
3331
- case "ClassExpression":
3334
+ case "ClassExpression": {
3332
3335
  if (expr.body.type !== "ClassBody") return false;
3333
3336
  if (expr.superClass && !this.isPure(expr.superClass, expr.range[0])) {
3334
3337
  return false;
3335
3338
  }
3336
- return expr.body.body.every(item => {
3337
- switch (item.type) {
3338
- // @ts-expect-error not yet supported by acorn
3339
- case "ClassProperty":
3340
- // TODO add test case once acorn supports it
3341
- // Currently this is not parsable
3342
- if (item.static) return this.isPure(item.value, item.range[0]);
3343
- break;
3344
- }
3345
- return true;
3346
- });
3339
+ const items = /** @type {(MethodDefinitionNode | PropertyDefinitionNode)[]} */ (expr
3340
+ .body.body);
3341
+ return items.every(
3342
+ item =>
3343
+ (!item.computed ||
3344
+ !item.key ||
3345
+ this.isPure(item.key, item.range[0])) &&
3346
+ (!item.static ||
3347
+ !item.value ||
3348
+ this.isPure(
3349
+ item.value,
3350
+ item.key ? item.key.range[1] : item.range[0]
3351
+ ))
3352
+ );
3353
+ }
3347
3354
 
3348
3355
  case "FunctionDeclaration":
3349
3356
  case "FunctionExpression":
3350
3357
  case "ArrowFunctionExpression":
3351
3358
  case "Literal":
3359
+ case "PrivateIdentifier":
3352
3360
  return true;
3353
3361
 
3354
3362
  case "VariableDeclaration":
@@ -238,21 +238,20 @@ class InnerGraphPlugin {
238
238
  }
239
239
  );
240
240
 
241
- parser.hooks.classBodyElement.tap(
241
+ parser.hooks.classBodyValue.tap(
242
242
  "InnerGraphPlugin",
243
- (element, statement) => {
243
+ (expression, element, statement) => {
244
244
  if (!InnerGraph.isEnabled(parser.state)) return;
245
245
  if (parser.scope.topLevelScope === true) {
246
246
  const fn = classWithTopLevelSymbol.get(statement);
247
247
  if (fn) {
248
- if (element.type === "MethodDefinition") {
249
- InnerGraph.setTopLevelSymbol(parser.state, fn);
250
- } else if (
251
- element.type === "ClassProperty" &&
252
- !element.static
248
+ if (
249
+ !element.static ||
250
+ parser.isPure(
251
+ expression,
252
+ element.key ? element.key.range[1] : element.range[0]
253
+ )
253
254
  ) {
254
- // TODO add test case once acorn supports it
255
- // Currently this is not parsable
256
255
  InnerGraph.setTopLevelSymbol(parser.state, fn);
257
256
  } else {
258
257
  InnerGraph.setTopLevelSymbol(parser.state, undefined);