webpack 5.108.3 → 5.109.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.
- package/lib/APIPlugin.js +48 -29
- package/lib/CacheFacade.js +8 -0
- package/lib/ChunkGroup.js +1 -0
- package/lib/CompatibilityPlugin.js +31 -29
- package/lib/Compilation.js +50 -8
- package/lib/ConstPlugin.js +11 -11
- package/lib/ContextModule.js +239 -6
- package/lib/ContextModuleFactory.js +139 -14
- package/lib/DefinePlugin.js +396 -101
- package/lib/Entrypoint.js +1 -1
- package/lib/ExportsInfoApiPlugin.js +2 -2
- package/lib/ExternalModule.js +107 -5
- package/lib/ExternalModuleFactoryPlugin.js +20 -1
- package/lib/FileSystemInfo.js +130 -74
- package/lib/FlagDependencyExportsPlugin.js +55 -8
- package/lib/HotModuleReplacementPlugin.js +18 -15
- package/lib/LazyBarrel.js +30 -3
- package/lib/Module.js +3 -0
- package/lib/ModuleFilenameHelpers.js +2 -2
- package/lib/ModuleTypeConstants.js +8 -1
- package/lib/MultiCompiler.js +13 -2
- package/lib/MultiWatching.js +1 -0
- package/lib/NodeStuffPlugin.js +51 -33
- package/lib/NormalModule.js +169 -405
- package/lib/NormalModuleFactory.js +76 -2
- package/lib/ProgressPlugin.js +211 -119
- package/lib/ProvidePlugin.js +2 -2
- package/lib/RuntimeGlobals.js +47 -0
- package/lib/RuntimePlugin.js +33 -0
- package/lib/RuntimeTemplate.js +304 -16
- package/lib/UseStrictPlugin.js +1 -1
- package/lib/WebpackIsIncludedPlugin.js +1 -1
- package/lib/WebpackOptionsApply.js +24 -19
- package/lib/asset/AssetGenerator.js +110 -28
- package/lib/asset/AssetModulesPlugin.js +92 -2
- package/lib/asset/WebManifestGenerator.js +164 -0
- package/lib/asset/WebManifestParser.js +130 -0
- package/lib/async-modules/AwaitDependenciesInitFragment.js +14 -4
- package/lib/async-modules/isGeneratorLowered.js +26 -0
- package/lib/cache/PackFileCacheStrategy.js +9 -3
- package/lib/config/browserslistTargetHandler.js +40 -0
- package/lib/config/defaults.js +222 -32
- package/lib/config/normalization.js +26 -0
- package/lib/config/target.js +9 -1
- package/lib/css/CssGenerator.js +73 -73
- package/lib/css/CssLoadingRuntimeModule.js +5 -1
- package/lib/css/CssModulesPlugin.js +92 -53
- package/lib/css/CssParser.js +843 -302
- package/lib/css/syntax.js +1219 -483
- package/lib/dependencies/AMDDefineDependencyParserPlugin.js +6 -6
- package/lib/dependencies/AMDPlugin.js +2 -2
- package/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js +13 -13
- package/lib/dependencies/CommonJsDependencyHelpers.js +39 -0
- package/lib/dependencies/CommonJsExportsDependency.js +47 -2
- package/lib/dependencies/CommonJsExportsParserPlugin.js +10 -10
- package/lib/dependencies/CommonJsImportsParserPlugin.js +18 -18
- package/lib/dependencies/CommonJsPlugin.js +2 -2
- package/lib/dependencies/CommonJsRequireDependency.js +26 -1
- package/lib/dependencies/CommonJsSelfReferenceDependency.js +32 -1
- package/lib/dependencies/ContextDependencyHelpers.js +3 -3
- package/lib/dependencies/CreateRequireParserPlugin.js +6 -6
- package/lib/dependencies/CssIcssExportDependency.js +190 -87
- package/lib/dependencies/CssUrlDependency.js +35 -4
- package/lib/dependencies/ExternalModuleInitFragmentDependency.js +2 -2
- package/lib/dependencies/HarmonyCompatibilityDependency.js +32 -14
- package/lib/dependencies/HarmonyDetectionParserPlugin.js +43 -13
- package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +7 -19
- package/lib/dependencies/HarmonyImportDependency.js +12 -1
- package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +34 -107
- package/lib/dependencies/HarmonyImportGuard.js +192 -20
- package/lib/dependencies/HarmonyModulesPlugin.js +6 -0
- package/lib/dependencies/HarmonyTopLevelThisParserPlugin.js +1 -1
- package/lib/dependencies/HtmlEntryDependency.js +797 -172
- package/lib/dependencies/HtmlSourceDependency.js +26 -0
- package/lib/dependencies/ImportDependency.js +43 -1
- package/lib/dependencies/ImportMetaContextDependencyParserPlugin.js +31 -18
- package/lib/dependencies/ImportMetaContextPlugin.js +38 -7
- package/lib/dependencies/ImportMetaGlobDependency.js +81 -0
- package/lib/dependencies/ImportMetaGlobDependencyParserPlugin.js +78 -0
- package/lib/dependencies/ImportMetaGlobHelpers.js +660 -0
- package/lib/dependencies/ImportMetaPlugin.js +532 -180
- package/lib/dependencies/ImportMetaResolveDependency.js +90 -0
- package/lib/dependencies/ImportParserPlugin.js +87 -26
- package/lib/dependencies/ImportPhase.js +10 -8
- package/lib/dependencies/LoaderPlugin.js +5 -1
- package/lib/dependencies/RequireContextDependencyParserPlugin.js +1 -1
- package/lib/dependencies/RequireEnsureDependenciesBlockParserPlugin.js +3 -6
- package/lib/dependencies/RequireIncludeDependencyParserPlugin.js +4 -11
- package/lib/dependencies/SystemPlugin.js +2 -4
- package/lib/dependencies/TopLevelAwaitDependency.js +93 -0
- package/lib/dependencies/URLDependency.js +141 -21
- package/lib/dependencies/{WorkerPlugin.js → WorkerAndWorkletPlugin.js} +324 -112
- package/lib/dependencies/WorkerDependency.js +86 -18
- package/lib/dependencies/WorkletDependency.js +278 -0
- package/lib/dll/DelegatedModuleFactoryPlugin.js +19 -0
- package/lib/errors/EnvironmentNotSupportAsyncWarning.js +1 -1
- package/lib/errors/LoaderLoadingError.js +20 -0
- package/lib/errors/ModuleParseError.js +39 -22
- package/lib/errors/NodeStuffInWebError.js +1 -1
- package/lib/esm/ModuleChunkFormatPlugin.js +47 -14
- package/lib/esm/ModuleChunkLoadingPlugin.js +8 -1
- package/lib/esm/ModuleChunkLoadingRuntimeModule.js +29 -1
- package/lib/hmr/lazyCompilationBackend.js +32 -8
- package/lib/html/HtmlGenerator.js +940 -91
- package/lib/html/HtmlModule.js +3 -2
- package/lib/html/HtmlModulesPlugin.js +625 -170
- package/lib/html/HtmlParser.js +812 -340
- package/lib/html/favicon.svg +1 -0
- package/lib/html/syntax.js +2116 -834
- package/lib/ids/IdHelpers.js +1 -1
- package/lib/index.js +6 -0
- package/lib/javascript/ArrayPushCallbackChunkFormatPlugin.js +4 -5
- package/lib/javascript/BasicEvaluatedExpression.js +366 -48
- package/lib/javascript/JavascriptGenerator.js +197 -49
- package/lib/javascript/JavascriptModulesPlugin.js +178 -24
- package/lib/javascript/JavascriptParser.js +711 -355
- package/lib/javascript/JavascriptParserHelpers.js +3 -6
- package/lib/javascript/syntax.js +4380 -0
- package/lib/library/ModuleLibraryPlugin.js +38 -1
- package/lib/loaders/LoaderRunner.js +714 -0
- package/lib/loaders/loadLoader.js +100 -0
- package/lib/node/ReadFileCompileAsyncWasmPlugin.js +19 -0
- package/lib/node/ReadFileCompileWasmPlugin.js +14 -0
- package/lib/optimize/ConcatenatedModule.js +120 -16
- package/lib/optimize/FlagIncludedChunksPlugin.js +13 -3
- package/lib/optimize/InnerGraphPlugin.js +50 -30
- package/lib/optimize/ModuleConcatenationPlugin.js +69 -3
- package/lib/optimize/SideEffectsFlagPlugin.js +86 -43
- package/lib/prefetch/ChunkPrefetchPreloadPlugin.js +15 -0
- package/lib/prefetch/ChunkPreloadTriggerRuntimeModule.js +24 -13
- package/lib/prefetch/ResourceHintPlugin.js +663 -0
- package/lib/prefetch/ResourceHintRuntimeModule.js +149 -0
- package/lib/prefetch/StartupAssetHintRuntimeModule.js +210 -0
- package/lib/prefetch/parseResourceHintOptions.js +103 -0
- package/lib/rules/RuleSetCompiler.js +114 -0
- package/lib/runtime/AsyncModuleGeneratorRuntimeModule.js +56 -0
- package/lib/runtime/AsyncModuleRuntimeModule.js +24 -8
- package/lib/runtime/AutoPublicPathRuntimeModule.js +7 -1
- package/lib/runtime/CommonJsWrapRuntimeModule.js +37 -0
- package/lib/runtime/GetWorkletBootstrapRuntimeModule.js +59 -0
- package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +204 -8
- package/lib/runtime/SetAnonymousDefaultNameRuntimeModule.js +4 -1
- package/lib/schemes/HttpUriPlugin.js +40 -1
- package/lib/schemes/VirtualUrlPlugin.js +1 -2
- package/lib/serialization/FileMiddleware.js +29 -3
- package/lib/stats/DefaultStatsFactoryPlugin.js +32 -3
- package/lib/stats/DefaultStatsPresetPlugin.js +2 -0
- package/lib/stats/DefaultStatsPrinterPlugin.js +12 -2
- package/lib/stats/StatsFactory.js +15 -8
- package/lib/url/URLParserPlugin.js +98 -19
- package/lib/util/AsyncQueue.js +122 -72
- package/lib/util/LocConverter.js +9 -8
- package/lib/util/SetHelpers.js +1 -1
- package/lib/util/SourceProcessor.js +41 -28
- package/lib/util/StackedMap.js +122 -48
- package/lib/util/binarySearchBounds.js +2 -2
- package/lib/util/concatenate.js +40 -14
- package/lib/util/createHooksRegistry.js +13 -5
- package/lib/util/dataURL.js +2 -2
- package/lib/util/deterministicGrouping.js +7 -5
- package/lib/util/formatSize.js +6 -2
- package/lib/util/globUtils.js +710 -0
- package/lib/util/identifier.js +23 -6
- package/lib/util/implicitTypeLoaderFallback.js +62 -0
- package/lib/util/internalSerializables.js +88 -71
- package/lib/util/magicComment.js +121 -25
- package/lib/util/numberHash.js +2 -2
- package/lib/wasm-async/AsyncWasmCompileRuntimeModule.js +24 -18
- package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +33 -22
- package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +79 -16
- package/lib/web/FetchCompileAsyncWasmPlugin.js +19 -0
- package/lib/web/FetchCompileWasmPlugin.js +14 -0
- package/lib/web/JsonpChunkLoadingRuntimeModule.js +2 -0
- package/lib/webpack.js +65 -0
- package/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js +3 -0
- package/module.d.ts +21 -0
- package/package.json +14 -13
- package/schemas/WebpackOptions.check.js +1 -1
- package/schemas/WebpackOptions.json +759 -36
- package/schemas/plugins/HtmlParserOptions.check.js +1 -1
- package/schemas/plugins/ProgressPlugin.check.js +1 -1
- package/schemas/plugins/ProgressPlugin.json +17 -1
- package/schemas/plugins/container/ContainerReferencePlugin.check.js +1 -1
- package/schemas/plugins/container/ContainerReferencePlugin.json +1 -0
- package/schemas/plugins/container/ExternalsType.check.js +1 -1
- package/schemas/plugins/container/ModuleFederationPlugin.check.js +1 -1
- package/schemas/plugins/container/ModuleFederationPlugin.json +1 -0
- package/schemas/plugins/css/CssAutoOrModuleParserOptions.check.js +1 -1
- package/schemas/plugins/css/CssModuleParserOptions.check.js +1 -1
- package/schemas/plugins/css/CssParserOptions.check.js +1 -1
- package/types.d.ts +1300 -325
|
@@ -5,20 +5,27 @@
|
|
|
5
5
|
|
|
6
6
|
"use strict";
|
|
7
7
|
|
|
8
|
-
const vm = require("vm");
|
|
9
|
-
const { Parser: AcornParser, tokTypes } = require("acorn");
|
|
10
8
|
const { HookMap, SyncBailHook } = require("tapable");
|
|
11
9
|
const NormalModule = require("../NormalModule");
|
|
12
10
|
const Parser = require("../Parser");
|
|
11
|
+
const WebpackError = require("../WebpackError");
|
|
13
12
|
const StackedMap = require("../util/StackedMap");
|
|
14
|
-
const binarySearchBounds = require("../util/binarySearchBounds");
|
|
15
13
|
const {
|
|
16
14
|
CompilerHintNotationRegExp,
|
|
17
15
|
createMagicCommentContext,
|
|
18
|
-
|
|
16
|
+
getCommentsInRange,
|
|
17
|
+
parseCommentOptionsInRange
|
|
19
18
|
} = require("../util/magicComment");
|
|
20
19
|
const BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
|
|
21
|
-
|
|
20
|
+
const {
|
|
21
|
+
LEGACY_ASSERT_ATTRIBUTES,
|
|
22
|
+
WebpackParser,
|
|
23
|
+
buildLineStarts,
|
|
24
|
+
hasOctalEscape,
|
|
25
|
+
positionAt
|
|
26
|
+
} = require("./syntax");
|
|
27
|
+
|
|
28
|
+
/** @typedef {typeof import("acorn").Parser} AcornParser */
|
|
22
29
|
/** @typedef {import("acorn").Options} AcornOptions */
|
|
23
30
|
/** @typedef {import("acorn").ecmaVersion} EcmaVersion */
|
|
24
31
|
/** @typedef {import("estree").AssignmentExpression} AssignmentExpression */
|
|
@@ -32,7 +39,9 @@ const BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
|
|
|
32
39
|
/** @typedef {import("estree").SwitchStatement} SwitchStatement */
|
|
33
40
|
/** @typedef {import("estree").ClassExpression} ClassExpression */
|
|
34
41
|
/** @typedef {import("estree").SourceLocation} SourceLocation */
|
|
35
|
-
/** @typedef {import("
|
|
42
|
+
/** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */
|
|
43
|
+
/** @typedef {import("../Dependency").SourcePosition} SourcePosition */
|
|
44
|
+
/** @typedef {import("estree").Comment & { start: number, end: number, loc?: SourceLocation | null }} Comment */
|
|
36
45
|
/** @typedef {import("estree").ConditionalExpression} ConditionalExpression */
|
|
37
46
|
/** @typedef {import("estree").Declaration} Declaration */
|
|
38
47
|
/** @typedef {import("estree").PrivateIdentifier} PrivateIdentifier */
|
|
@@ -156,77 +165,21 @@ const ALLOWED_MEMBER_TYPES_CALL_EXPRESSION = 0b01;
|
|
|
156
165
|
const ALLOWED_MEMBER_TYPES_EXPRESSION = 0b10;
|
|
157
166
|
const ALLOWED_MEMBER_TYPES_ALL = 0b11;
|
|
158
167
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
const importAssertions = (Parser) =>
|
|
163
|
-
class extends Parser {
|
|
164
|
-
/**
|
|
165
|
-
* Parses with clause.
|
|
166
|
-
* @this {InstanceType<AcornParser>}
|
|
167
|
-
* @returns {ImportAttribute[]} import attributes
|
|
168
|
-
*/
|
|
169
|
-
parseWithClause() {
|
|
170
|
-
/** @type {ImportAttribute[]} */
|
|
171
|
-
const nodes = [];
|
|
172
|
-
|
|
173
|
-
const isAssertLegacy = this.value === "assert";
|
|
174
|
-
|
|
175
|
-
if (isAssertLegacy) {
|
|
176
|
-
if (!this.eat(tokTypes.name)) {
|
|
177
|
-
return nodes;
|
|
178
|
-
}
|
|
179
|
-
} else if (!this.eat(tokTypes._with)) {
|
|
180
|
-
return nodes;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
this.expect(tokTypes.braceL);
|
|
184
|
-
|
|
185
|
-
/** @type {Record<string, boolean>} */
|
|
186
|
-
const attributeKeys = {};
|
|
187
|
-
let first = true;
|
|
188
|
-
|
|
189
|
-
while (!this.eat(tokTypes.braceR)) {
|
|
190
|
-
if (!first) {
|
|
191
|
-
this.expect(tokTypes.comma);
|
|
192
|
-
if (this.afterTrailingComma(tokTypes.braceR)) {
|
|
193
|
-
break;
|
|
194
|
-
}
|
|
195
|
-
} else {
|
|
196
|
-
first = false;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const attr =
|
|
200
|
-
/** @type {ImportAttribute} */
|
|
201
|
-
this.parseImportAttribute();
|
|
202
|
-
const keyName =
|
|
203
|
-
attr.key.type === "Identifier" ? attr.key.name : attr.key.value;
|
|
204
|
-
|
|
205
|
-
if (Object.prototype.hasOwnProperty.call(attributeKeys, keyName)) {
|
|
206
|
-
this.raiseRecoverable(
|
|
207
|
-
attr.key.start,
|
|
208
|
-
`Duplicate attribute key '${keyName}'`
|
|
209
|
-
);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
attributeKeys[keyName] = true;
|
|
213
|
-
nodes.push(attr);
|
|
214
|
-
}
|
|
168
|
+
// Shared `() => false` so the members-optionals fallback in walkCallExpression
|
|
169
|
+
// doesn't allocate a fresh closure per identifier-rooted call.
|
|
170
|
+
const RETURN_FALSE = () => false;
|
|
215
171
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
return nodes;
|
|
222
|
-
}
|
|
223
|
-
};
|
|
172
|
+
// Shared `() => []` for the member-less identifier/this evaluation results,
|
|
173
|
+
// replacing three fresh closures per evaluated free variable.
|
|
174
|
+
const RETURN_EMPTY_ARRAY = () => [];
|
|
224
175
|
|
|
225
176
|
// Syntax: https://developer.mozilla.org/en/SpiderMonkey/Parser_API
|
|
226
|
-
let parser = AcornParser
|
|
177
|
+
let parser = /** @type {AcornParser} */ (WebpackParser);
|
|
227
178
|
|
|
228
179
|
/** @typedef {Record<string, string> & { _isLegacyAssert?: boolean }} ImportAttributes */
|
|
229
180
|
|
|
181
|
+
// Conceptually pairs with ./syntax's LEGACY_ASSERT_ATTRIBUTES marker, but is
|
|
182
|
+
// pinned here by its public `JavascriptParser.getImportAttributes` typing.
|
|
230
183
|
/**
|
|
231
184
|
* Gets import attributes.
|
|
232
185
|
* @param {ImportDeclaration | ExportNamedDeclaration | ExportAllDeclaration | ImportExpression} node node with assertions
|
|
@@ -362,9 +315,12 @@ class VariableInfo {
|
|
|
362
315
|
* @property {boolean=} locations
|
|
363
316
|
* @property {boolean=} comments
|
|
364
317
|
* @property {boolean=} ranges
|
|
365
|
-
* @property {boolean=} semicolons
|
|
366
318
|
* @property {boolean=} allowHashBang
|
|
367
319
|
* @property {boolean=} allowReturnOutsideFunction
|
|
320
|
+
* @property {boolean=} lazyNodes internal: serve `range` lazily and skip acorn's location/range tracking
|
|
321
|
+
* @property {Comment[]=} lazyComments internal: collect comments here without slicing their text eagerly
|
|
322
|
+
* @property {boolean=} importPhases enable parsing of the import phase proposals (import defer / import source)
|
|
323
|
+
* @property {boolean=} moduleFallback internal: for `auto`, let the parser downgrade module->script in place instead of re-parsing
|
|
368
324
|
*/
|
|
369
325
|
|
|
370
326
|
/**
|
|
@@ -372,7 +328,6 @@ class VariableInfo {
|
|
|
372
328
|
* @typedef {object} ParseResult
|
|
373
329
|
* @property {Program} ast
|
|
374
330
|
* @property {Comment[]} comments
|
|
375
|
-
* @property {Set<number>} semicolons
|
|
376
331
|
*/
|
|
377
332
|
|
|
378
333
|
/**
|
|
@@ -424,10 +379,10 @@ const SCOPE_INFO_TERMINATED_THROW = 2;
|
|
|
424
379
|
|
|
425
380
|
/**
|
|
426
381
|
* Defines the destructuring assignment property type used by this module.
|
|
382
|
+
* Carries only the range — consumers derive line/column via `getLocation`.
|
|
427
383
|
* @typedef {object} DestructuringAssignmentProperty
|
|
428
384
|
* @property {string} id
|
|
429
385
|
* @property {Range} range
|
|
430
|
-
* @property {SourceLocation} loc
|
|
431
386
|
* @property {Set<DestructuringAssignmentProperty> | undefined=} pattern
|
|
432
387
|
* @property {boolean | string} shorthand
|
|
433
388
|
*/
|
|
@@ -527,10 +482,16 @@ const defaultParserOptions = {
|
|
|
527
482
|
allowHashBang: true
|
|
528
483
|
};
|
|
529
484
|
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
485
|
+
// reused by _parse for every non-custom parse — all fields are reset per parse
|
|
486
|
+
/** @type {ParseOptions} */
|
|
487
|
+
const REUSED_PARSER_OPTIONS = { ...defaultParserOptions };
|
|
488
|
+
|
|
489
|
+
// Read-only snippet ASTs for `evaluate()`, released with the compilation;
|
|
490
|
+
// DefinePlugin evaluates the same strings once per usage per module.
|
|
491
|
+
/** @type {WeakMap<Compilation, Map<string, Program>>} */
|
|
492
|
+
const evaluateAstCaches = new WeakMap();
|
|
493
|
+
// The inner map is strong while the compilation lives, so cap it
|
|
494
|
+
const EVALUATE_AST_CACHE_LIMIT = 4096;
|
|
534
495
|
|
|
535
496
|
const CLASS_NAME = "JavascriptParser";
|
|
536
497
|
|
|
@@ -538,7 +499,7 @@ class JavascriptParser extends Parser {
|
|
|
538
499
|
/**
|
|
539
500
|
* Creates an instance of JavascriptParser.
|
|
540
501
|
* @param {"module" | "script" | "auto"=} sourceType default source type
|
|
541
|
-
* @param {{ parse?: ParseFunction, typescript?: boolean }=} options parser options
|
|
502
|
+
* @param {{ parse?: ParseFunction, typescript?: boolean, importPhases?: boolean, strictModeViolations?: "error" | "warn" | false }=} options parser options
|
|
542
503
|
*/
|
|
543
504
|
constructor(sourceType = "auto", options = {}) {
|
|
544
505
|
super();
|
|
@@ -571,9 +532,15 @@ class JavascriptParser extends Parser {
|
|
|
571
532
|
),
|
|
572
533
|
/** @type {SyncBailHook<[Statement | ModuleDeclaration | MaybeNamedClassDeclaration | MaybeNamedFunctionDeclaration], boolean | void>} */
|
|
573
534
|
preStatement: new SyncBailHook(["statement"]),
|
|
535
|
+
/** @type {HookMap<SyncBailHook<[Statement | ModuleDeclaration | MaybeNamedClassDeclaration | MaybeNamedFunctionDeclaration], boolean | void>>} */
|
|
536
|
+
preStatementByType: new HookMap(() => new SyncBailHook(["statement"])),
|
|
574
537
|
|
|
575
538
|
/** @type {SyncBailHook<[Statement | ModuleDeclaration | MaybeNamedClassDeclaration | MaybeNamedFunctionDeclaration], boolean | void>} */
|
|
576
539
|
blockPreStatement: new SyncBailHook(["declaration"]),
|
|
540
|
+
/** @type {HookMap<SyncBailHook<[Statement | ModuleDeclaration | MaybeNamedClassDeclaration | MaybeNamedFunctionDeclaration], boolean | void>>} */
|
|
541
|
+
blockPreStatementByType: new HookMap(
|
|
542
|
+
() => new SyncBailHook(["declaration"])
|
|
543
|
+
),
|
|
577
544
|
/** @type {SyncBailHook<[Statement | ModuleDeclaration | MaybeNamedFunctionDeclaration | MaybeNamedClassDeclaration], boolean | void>} */
|
|
578
545
|
statement: new SyncBailHook(["statement"]),
|
|
579
546
|
/** @type {SyncBailHook<[IfStatement], boolean | void>} */
|
|
@@ -744,7 +711,10 @@ class JavascriptParser extends Parser {
|
|
|
744
711
|
this.state = /** @type {EXPECTED_ANY} */ (undefined);
|
|
745
712
|
/** @type {Comment[] | undefined} */
|
|
746
713
|
this.comments = undefined;
|
|
747
|
-
|
|
714
|
+
// ASI overrides keyed by statement-end offset: true forces an ASI
|
|
715
|
+
// position, false forces a real semicolon. Absent offsets are derived
|
|
716
|
+
// from the source text. Allocated lazily by set/unsetAsiPosition.
|
|
717
|
+
/** @type {Map<number, boolean> | undefined} */
|
|
748
718
|
this.semicolons = undefined;
|
|
749
719
|
/** @type {StatementPath | undefined} */
|
|
750
720
|
this.statementPath = undefined;
|
|
@@ -754,11 +724,39 @@ class JavascriptParser extends Parser {
|
|
|
754
724
|
this.destructuringAssignmentProperties = undefined;
|
|
755
725
|
/** @type {TagData | undefined} */
|
|
756
726
|
this.currentTagData = undefined;
|
|
727
|
+
// True while parsing a loose module whose code is emitted as strict ESM.
|
|
728
|
+
this._strictInModuleOutput = false;
|
|
729
|
+
// Source text of the current parse, for offset → line/column mapping.
|
|
730
|
+
/** @type {string | undefined} */
|
|
731
|
+
this._source = undefined;
|
|
732
|
+
// Offset of each line's first character, built on first getLocation use.
|
|
733
|
+
/** @type {number[] | undefined} */
|
|
734
|
+
this._lineStarts = undefined;
|
|
735
|
+
// True while only the parser's own taps sit on evaluate.for("Identifier");
|
|
736
|
+
// recomputed per parse, gates the defined-identifier fast paths.
|
|
737
|
+
this._evalIdentOwnTaps = false;
|
|
757
738
|
this.magicCommentContext = createMagicCommentContext();
|
|
758
739
|
// Reused for enterPatterns on every scope entry to avoid per-scope closures.
|
|
759
740
|
/** @type {OnIdentString} */
|
|
760
741
|
this._defineVariable = (ident) => this.defineVariable(ident);
|
|
761
742
|
this._initializeEvaluating();
|
|
743
|
+
// keyed taps are free for every other member chain, and a shadowed
|
|
744
|
+
// `arguments` binding never dispatches the free-variable hooks
|
|
745
|
+
this.hooks.expressionMemberChain
|
|
746
|
+
.for("arguments")
|
|
747
|
+
.tap(CLASS_NAME, (expression, members) => {
|
|
748
|
+
if (this._strictInModuleOutput) {
|
|
749
|
+
this._checkStrictModeArgumentsMember(members[0], expression);
|
|
750
|
+
}
|
|
751
|
+
});
|
|
752
|
+
this.hooks.callMemberChain
|
|
753
|
+
.for("arguments")
|
|
754
|
+
.tap(CLASS_NAME, (expression, members) => {
|
|
755
|
+
// longer chains re-enter the member walk, which reports them
|
|
756
|
+
if (this._strictInModuleOutput && members.length === 1) {
|
|
757
|
+
this._checkStrictModeArgumentsMember(members[0], expression);
|
|
758
|
+
}
|
|
759
|
+
});
|
|
762
760
|
}
|
|
763
761
|
|
|
764
762
|
_initializeEvaluating() {
|
|
@@ -1383,6 +1381,16 @@ class JavascriptParser extends Parser {
|
|
|
1383
1381
|
return handleConstOperation((l, r) => l <= r);
|
|
1384
1382
|
} else if (expr.operator === ">=") {
|
|
1385
1383
|
return handleConstOperation((l, r) => l >= r);
|
|
1384
|
+
} else if (expr.operator === "in") {
|
|
1385
|
+
// `x in y` always evaluates to a boolean, so it is never nullish
|
|
1386
|
+
const left = this.evaluateExpression(expr.left);
|
|
1387
|
+
const right = this.evaluateExpression(expr.right);
|
|
1388
|
+
return new BasicEvaluatedExpression()
|
|
1389
|
+
.setNullish(false)
|
|
1390
|
+
.setSideEffects(
|
|
1391
|
+
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
1392
|
+
)
|
|
1393
|
+
.setRange(/** @type {Range} */ (expr.range));
|
|
1386
1394
|
}
|
|
1387
1395
|
});
|
|
1388
1396
|
this.hooks.evaluate.for("UnaryExpression").tap(CLASS_NAME, (_expr) => {
|
|
@@ -1597,9 +1605,9 @@ class JavascriptParser extends Parser {
|
|
|
1597
1605
|
return {
|
|
1598
1606
|
name: info,
|
|
1599
1607
|
rootInfo: info,
|
|
1600
|
-
getMembers:
|
|
1601
|
-
getMembersOptionals:
|
|
1602
|
-
getMemberRanges:
|
|
1608
|
+
getMembers: RETURN_EMPTY_ARRAY,
|
|
1609
|
+
getMembersOptionals: RETURN_EMPTY_ARRAY,
|
|
1610
|
+
getMemberRanges: RETURN_EMPTY_ARRAY
|
|
1603
1611
|
};
|
|
1604
1612
|
}
|
|
1605
1613
|
});
|
|
@@ -1612,9 +1620,9 @@ class JavascriptParser extends Parser {
|
|
|
1612
1620
|
return {
|
|
1613
1621
|
name: info,
|
|
1614
1622
|
rootInfo: info,
|
|
1615
|
-
getMembers:
|
|
1616
|
-
getMembersOptionals:
|
|
1617
|
-
getMemberRanges:
|
|
1623
|
+
getMembers: RETURN_EMPTY_ARRAY,
|
|
1624
|
+
getMembersOptionals: RETURN_EMPTY_ARRAY,
|
|
1625
|
+
getMemberRanges: RETURN_EMPTY_ARRAY
|
|
1618
1626
|
};
|
|
1619
1627
|
}
|
|
1620
1628
|
});
|
|
@@ -2063,6 +2071,15 @@ class JavascriptParser extends Parser {
|
|
|
2063
2071
|
* @returns {string | VariableInfo | undefined} identifier
|
|
2064
2072
|
*/
|
|
2065
2073
|
getRenameIdentifier(expr) {
|
|
2074
|
+
if (
|
|
2075
|
+
expr.type === "Identifier" &&
|
|
2076
|
+
this._evalIdentOwnTaps &&
|
|
2077
|
+
expr.name !== "undefined" &&
|
|
2078
|
+
this._isDefinedPlainVariable(expr.name)
|
|
2079
|
+
) {
|
|
2080
|
+
// the evaluation could only fall through — never an identifier result
|
|
2081
|
+
return;
|
|
2082
|
+
}
|
|
2066
2083
|
const result = this.evaluateExpression(expr);
|
|
2067
2084
|
if (result.isIdentifier()) {
|
|
2068
2085
|
return result.identifier;
|
|
@@ -2202,49 +2219,60 @@ class JavascriptParser extends Parser {
|
|
|
2202
2219
|
preWalkStatement(statement) {
|
|
2203
2220
|
/** @type {StatementPath} */
|
|
2204
2221
|
(this.statementPath).push(statement);
|
|
2205
|
-
|
|
2222
|
+
const { preStatement, preStatementByType } = this.hooks;
|
|
2223
|
+
// skip the broadcast entirely when nothing taps it; type-keyed taps
|
|
2224
|
+
// only run for their statement type
|
|
2225
|
+
let bail =
|
|
2226
|
+
preStatement.taps.length !== 0 ? preStatement.call(statement) : undefined;
|
|
2227
|
+
if (!bail) {
|
|
2228
|
+
const typed = preStatementByType.get(statement.type);
|
|
2229
|
+
if (typed !== undefined) bail = typed.call(statement);
|
|
2230
|
+
}
|
|
2231
|
+
if (bail) {
|
|
2206
2232
|
this.prevStatement =
|
|
2207
2233
|
/** @type {StatementPath} */
|
|
2208
2234
|
(this.statementPath).pop();
|
|
2209
2235
|
return;
|
|
2210
2236
|
}
|
|
2237
|
+
// cases ordered by measured statement frequency; the commonest statements
|
|
2238
|
+
// (expressions, returns) intentionally match nothing here
|
|
2211
2239
|
switch (statement.type) {
|
|
2212
|
-
case "
|
|
2213
|
-
this.
|
|
2214
|
-
break;
|
|
2215
|
-
case "DoWhileStatement":
|
|
2216
|
-
this.preWalkDoWhileStatement(statement);
|
|
2217
|
-
break;
|
|
2218
|
-
case "ForInStatement":
|
|
2219
|
-
this.preWalkForInStatement(statement);
|
|
2240
|
+
case "VariableDeclaration":
|
|
2241
|
+
this.preWalkVariableDeclaration(statement);
|
|
2220
2242
|
break;
|
|
2221
|
-
case "
|
|
2222
|
-
this.
|
|
2243
|
+
case "IfStatement":
|
|
2244
|
+
this.preWalkIfStatement(statement);
|
|
2223
2245
|
break;
|
|
2224
|
-
case "
|
|
2225
|
-
this.
|
|
2246
|
+
case "BlockStatement":
|
|
2247
|
+
this.preWalkBlockStatement(statement);
|
|
2226
2248
|
break;
|
|
2227
2249
|
case "FunctionDeclaration":
|
|
2228
2250
|
this.preWalkFunctionDeclaration(statement);
|
|
2229
2251
|
break;
|
|
2230
|
-
case "
|
|
2231
|
-
this.
|
|
2232
|
-
break;
|
|
2233
|
-
case "LabeledStatement":
|
|
2234
|
-
this.preWalkLabeledStatement(statement);
|
|
2235
|
-
break;
|
|
2236
|
-
case "SwitchStatement":
|
|
2237
|
-
this.preWalkSwitchStatement(statement);
|
|
2252
|
+
case "ForStatement":
|
|
2253
|
+
this.preWalkForStatement(statement);
|
|
2238
2254
|
break;
|
|
2239
2255
|
case "TryStatement":
|
|
2240
2256
|
this.preWalkTryStatement(statement);
|
|
2241
2257
|
break;
|
|
2242
|
-
case "
|
|
2243
|
-
this.
|
|
2258
|
+
case "SwitchStatement":
|
|
2259
|
+
this.preWalkSwitchStatement(statement);
|
|
2244
2260
|
break;
|
|
2245
2261
|
case "WhileStatement":
|
|
2246
2262
|
this.preWalkWhileStatement(statement);
|
|
2247
2263
|
break;
|
|
2264
|
+
case "ForInStatement":
|
|
2265
|
+
this.preWalkForInStatement(statement);
|
|
2266
|
+
break;
|
|
2267
|
+
case "ForOfStatement":
|
|
2268
|
+
this.preWalkForOfStatement(statement);
|
|
2269
|
+
break;
|
|
2270
|
+
case "DoWhileStatement":
|
|
2271
|
+
this.preWalkDoWhileStatement(statement);
|
|
2272
|
+
break;
|
|
2273
|
+
case "LabeledStatement":
|
|
2274
|
+
this.preWalkLabeledStatement(statement);
|
|
2275
|
+
break;
|
|
2248
2276
|
case "WithStatement":
|
|
2249
2277
|
this.preWalkWithStatement(statement);
|
|
2250
2278
|
break;
|
|
@@ -2261,27 +2289,37 @@ class JavascriptParser extends Parser {
|
|
|
2261
2289
|
blockPreWalkStatement(statement) {
|
|
2262
2290
|
/** @type {StatementPath} */
|
|
2263
2291
|
(this.statementPath).push(statement);
|
|
2264
|
-
|
|
2292
|
+
const { blockPreStatement, blockPreStatementByType } = this.hooks;
|
|
2293
|
+
let bail =
|
|
2294
|
+
blockPreStatement.taps.length !== 0
|
|
2295
|
+
? blockPreStatement.call(statement)
|
|
2296
|
+
: undefined;
|
|
2297
|
+
if (!bail) {
|
|
2298
|
+
const typed = blockPreStatementByType.get(statement.type);
|
|
2299
|
+
if (typed !== undefined) bail = typed.call(statement);
|
|
2300
|
+
}
|
|
2301
|
+
if (bail) {
|
|
2265
2302
|
this.prevStatement =
|
|
2266
2303
|
/** @type {StatementPath} */
|
|
2267
2304
|
(this.statementPath).pop();
|
|
2268
2305
|
return;
|
|
2269
2306
|
}
|
|
2307
|
+
// cases ordered by measured statement frequency
|
|
2270
2308
|
switch (statement.type) {
|
|
2271
|
-
case "ExportDefaultDeclaration":
|
|
2272
|
-
this.blockPreWalkExportDefaultDeclaration(statement);
|
|
2273
|
-
break;
|
|
2274
|
-
case "ExportNamedDeclaration":
|
|
2275
|
-
this.blockPreWalkExportNamedDeclaration(statement);
|
|
2276
|
-
break;
|
|
2277
2309
|
case "VariableDeclaration":
|
|
2278
2310
|
this.blockPreWalkVariableDeclaration(statement);
|
|
2279
2311
|
break;
|
|
2312
|
+
case "ExpressionStatement":
|
|
2313
|
+
this.blockPreWalkExpressionStatement(statement);
|
|
2314
|
+
break;
|
|
2280
2315
|
case "ClassDeclaration":
|
|
2281
2316
|
this.blockPreWalkClassDeclaration(statement);
|
|
2282
2317
|
break;
|
|
2283
|
-
case "
|
|
2284
|
-
this.
|
|
2318
|
+
case "ExportNamedDeclaration":
|
|
2319
|
+
this.blockPreWalkExportNamedDeclaration(statement);
|
|
2320
|
+
break;
|
|
2321
|
+
case "ExportDefaultDeclaration":
|
|
2322
|
+
this.blockPreWalkExportDefaultDeclaration(statement);
|
|
2285
2323
|
}
|
|
2286
2324
|
this.prevStatement =
|
|
2287
2325
|
/** @type {StatementPath} */
|
|
@@ -2295,51 +2333,42 @@ class JavascriptParser extends Parser {
|
|
|
2295
2333
|
walkStatement(statement) {
|
|
2296
2334
|
/** @type {StatementPath} */
|
|
2297
2335
|
(this.statementPath).push(statement);
|
|
2298
|
-
|
|
2336
|
+
const { statement: statementHook } = this.hooks;
|
|
2337
|
+
if (
|
|
2338
|
+
statementHook.taps.length !== 0 &&
|
|
2339
|
+
statementHook.call(statement) !== undefined
|
|
2340
|
+
) {
|
|
2299
2341
|
this.prevStatement =
|
|
2300
2342
|
/** @type {StatementPath} */
|
|
2301
2343
|
(this.statementPath).pop();
|
|
2302
2344
|
return;
|
|
2303
2345
|
}
|
|
2346
|
+
// cases ordered by measured statement frequency; V8 compiles this to
|
|
2347
|
+
// sequential compares, so hot types must come first
|
|
2304
2348
|
switch (statement.type) {
|
|
2305
|
-
case "BlockStatement":
|
|
2306
|
-
this.walkBlockStatement(statement);
|
|
2307
|
-
break;
|
|
2308
|
-
case "ClassDeclaration":
|
|
2309
|
-
this.walkClassDeclaration(statement);
|
|
2310
|
-
break;
|
|
2311
|
-
case "DoWhileStatement":
|
|
2312
|
-
this.walkDoWhileStatement(statement);
|
|
2313
|
-
break;
|
|
2314
|
-
case "ExportDefaultDeclaration":
|
|
2315
|
-
this.walkExportDefaultDeclaration(statement);
|
|
2316
|
-
break;
|
|
2317
|
-
case "ExportNamedDeclaration":
|
|
2318
|
-
this.walkExportNamedDeclaration(statement);
|
|
2319
|
-
break;
|
|
2320
2349
|
case "ExpressionStatement":
|
|
2321
2350
|
this.walkExpressionStatement(statement);
|
|
2322
2351
|
break;
|
|
2323
|
-
case "
|
|
2324
|
-
this.
|
|
2352
|
+
case "VariableDeclaration":
|
|
2353
|
+
this.walkVariableDeclaration(statement);
|
|
2325
2354
|
break;
|
|
2326
|
-
case "
|
|
2327
|
-
this.
|
|
2355
|
+
case "ReturnStatement":
|
|
2356
|
+
this.walkReturnStatement(statement);
|
|
2328
2357
|
break;
|
|
2329
|
-
case "
|
|
2330
|
-
this.
|
|
2358
|
+
case "IfStatement":
|
|
2359
|
+
this.walkIfStatement(statement);
|
|
2360
|
+
break;
|
|
2361
|
+
case "BlockStatement":
|
|
2362
|
+
this.walkBlockStatement(statement);
|
|
2331
2363
|
break;
|
|
2332
2364
|
case "FunctionDeclaration":
|
|
2333
2365
|
this.walkFunctionDeclaration(statement);
|
|
2334
2366
|
break;
|
|
2335
|
-
case "
|
|
2336
|
-
this.
|
|
2337
|
-
break;
|
|
2338
|
-
case "LabeledStatement":
|
|
2339
|
-
this.walkLabeledStatement(statement);
|
|
2367
|
+
case "ForStatement":
|
|
2368
|
+
this.walkForStatement(statement);
|
|
2340
2369
|
break;
|
|
2341
|
-
case "
|
|
2342
|
-
this.
|
|
2370
|
+
case "TryStatement":
|
|
2371
|
+
this.walkTryStatement(statement);
|
|
2343
2372
|
break;
|
|
2344
2373
|
case "SwitchStatement":
|
|
2345
2374
|
this.walkSwitchStatement(statement);
|
|
@@ -2347,15 +2376,30 @@ class JavascriptParser extends Parser {
|
|
|
2347
2376
|
case "ThrowStatement":
|
|
2348
2377
|
this.walkThrowStatement(statement);
|
|
2349
2378
|
break;
|
|
2350
|
-
case "TryStatement":
|
|
2351
|
-
this.walkTryStatement(statement);
|
|
2352
|
-
break;
|
|
2353
|
-
case "VariableDeclaration":
|
|
2354
|
-
this.walkVariableDeclaration(statement);
|
|
2355
|
-
break;
|
|
2356
2379
|
case "WhileStatement":
|
|
2357
2380
|
this.walkWhileStatement(statement);
|
|
2358
2381
|
break;
|
|
2382
|
+
case "ClassDeclaration":
|
|
2383
|
+
this.walkClassDeclaration(statement);
|
|
2384
|
+
break;
|
|
2385
|
+
case "ForInStatement":
|
|
2386
|
+
this.walkForInStatement(statement);
|
|
2387
|
+
break;
|
|
2388
|
+
case "ForOfStatement":
|
|
2389
|
+
this.walkForOfStatement(statement);
|
|
2390
|
+
break;
|
|
2391
|
+
case "DoWhileStatement":
|
|
2392
|
+
this.walkDoWhileStatement(statement);
|
|
2393
|
+
break;
|
|
2394
|
+
case "ExportNamedDeclaration":
|
|
2395
|
+
this.walkExportNamedDeclaration(statement);
|
|
2396
|
+
break;
|
|
2397
|
+
case "ExportDefaultDeclaration":
|
|
2398
|
+
this.walkExportDefaultDeclaration(statement);
|
|
2399
|
+
break;
|
|
2400
|
+
case "LabeledStatement":
|
|
2401
|
+
this.walkLabeledStatement(statement);
|
|
2402
|
+
break;
|
|
2359
2403
|
case "WithStatement":
|
|
2360
2404
|
this.walkWithStatement(statement);
|
|
2361
2405
|
break;
|
|
@@ -2511,6 +2555,12 @@ class JavascriptParser extends Parser {
|
|
|
2511
2555
|
* @param {WithStatement} statement with statement
|
|
2512
2556
|
*/
|
|
2513
2557
|
walkWithStatement(statement) {
|
|
2558
|
+
if (this._strictInModuleOutput) {
|
|
2559
|
+
this._reportStrictModeViolation(
|
|
2560
|
+
"`with` statements are not allowed",
|
|
2561
|
+
statement
|
|
2562
|
+
);
|
|
2563
|
+
}
|
|
2514
2564
|
this.inBlockScope(() => {
|
|
2515
2565
|
this.walkExpression(statement.object);
|
|
2516
2566
|
this.walkNestedStatement(statement.body);
|
|
@@ -2799,6 +2849,9 @@ class JavascriptParser extends Parser {
|
|
|
2799
2849
|
walkFunctionDeclaration(statement) {
|
|
2800
2850
|
const wasTopLevel = this.scope.topLevelScope;
|
|
2801
2851
|
this.scope.topLevelScope = false;
|
|
2852
|
+
if (this._strictInModuleOutput) {
|
|
2853
|
+
this._checkStrictModeParams(statement.params);
|
|
2854
|
+
}
|
|
2802
2855
|
this.inFunctionScope(true, statement.params, () => {
|
|
2803
2856
|
for (const param of statement.params) {
|
|
2804
2857
|
this.walkPattern(param);
|
|
@@ -3243,7 +3296,6 @@ class JavascriptParser extends Parser {
|
|
|
3243
3296
|
props.add({
|
|
3244
3297
|
id: key.name,
|
|
3245
3298
|
range: /** @type {Range} */ (key.range),
|
|
3246
|
-
loc: /** @type {SourceLocation} */ (key.loc),
|
|
3247
3299
|
pattern,
|
|
3248
3300
|
shorthand: this.scope.inShorthand
|
|
3249
3301
|
});
|
|
@@ -3260,7 +3312,6 @@ class JavascriptParser extends Parser {
|
|
|
3260
3312
|
props.add({
|
|
3261
3313
|
id: str,
|
|
3262
3314
|
range: /** @type {Range} */ (key.range),
|
|
3263
|
-
loc: /** @type {SourceLocation} */ (key.loc),
|
|
3264
3315
|
pattern,
|
|
3265
3316
|
shorthand: this.scope.inShorthand
|
|
3266
3317
|
});
|
|
@@ -3297,7 +3348,6 @@ class JavascriptParser extends Parser {
|
|
|
3297
3348
|
props.add({
|
|
3298
3349
|
id: `${i}`,
|
|
3299
3350
|
range: /** @type {Range} */ (element.range),
|
|
3300
|
-
loc: /** @type {SourceLocation} */ (element.loc),
|
|
3301
3351
|
pattern,
|
|
3302
3352
|
shorthand: false
|
|
3303
3353
|
});
|
|
@@ -3457,6 +3507,12 @@ class JavascriptParser extends Parser {
|
|
|
3457
3507
|
*/
|
|
3458
3508
|
walkPattern(pattern) {
|
|
3459
3509
|
switch (pattern.type) {
|
|
3510
|
+
// plain identifier bindings are the common case and walk nothing
|
|
3511
|
+
case "Identifier":
|
|
3512
|
+
break;
|
|
3513
|
+
case "ObjectPattern":
|
|
3514
|
+
this.walkObjectPattern(pattern);
|
|
3515
|
+
break;
|
|
3460
3516
|
case "ArrayPattern":
|
|
3461
3517
|
this.walkArrayPattern(pattern);
|
|
3462
3518
|
break;
|
|
@@ -3466,9 +3522,6 @@ class JavascriptParser extends Parser {
|
|
|
3466
3522
|
case "MemberExpression":
|
|
3467
3523
|
this.walkMemberExpression(pattern);
|
|
3468
3524
|
break;
|
|
3469
|
-
case "ObjectPattern":
|
|
3470
|
-
this.walkObjectPattern(pattern);
|
|
3471
|
-
break;
|
|
3472
3525
|
case "RestElement":
|
|
3473
3526
|
this.walkRestElement(pattern);
|
|
3474
3527
|
break;
|
|
@@ -3538,78 +3591,86 @@ class JavascriptParser extends Parser {
|
|
|
3538
3591
|
* @param {Expression | SpreadElement | PrivateIdentifier | Super} expression expression
|
|
3539
3592
|
*/
|
|
3540
3593
|
walkExpression(expression) {
|
|
3594
|
+
// cases ordered by measured node frequency (identifiers are ~40% of all
|
|
3595
|
+
// expressions) — V8 compiles this to sequential compares, so hot types
|
|
3596
|
+
// must come first
|
|
3541
3597
|
switch (expression.type) {
|
|
3542
|
-
case "
|
|
3543
|
-
this.
|
|
3598
|
+
case "Identifier":
|
|
3599
|
+
this.walkIdentifier(expression);
|
|
3544
3600
|
break;
|
|
3545
|
-
case "
|
|
3546
|
-
this.
|
|
3601
|
+
case "MemberExpression":
|
|
3602
|
+
this.walkMemberExpression(expression);
|
|
3547
3603
|
break;
|
|
3548
|
-
case "
|
|
3549
|
-
this.
|
|
3604
|
+
case "Literal":
|
|
3605
|
+
if (this._strictInModuleOutput) {
|
|
3606
|
+
this._checkStrictModeLiteral(expression);
|
|
3607
|
+
}
|
|
3550
3608
|
break;
|
|
3551
|
-
case "
|
|
3552
|
-
this.
|
|
3609
|
+
case "CallExpression":
|
|
3610
|
+
this.walkCallExpression(expression);
|
|
3553
3611
|
break;
|
|
3554
3612
|
case "BinaryExpression":
|
|
3555
3613
|
this.walkBinaryExpression(expression);
|
|
3556
3614
|
break;
|
|
3557
|
-
case "
|
|
3558
|
-
this.
|
|
3559
|
-
break;
|
|
3560
|
-
case "ChainExpression":
|
|
3561
|
-
this.walkChainExpression(expression);
|
|
3615
|
+
case "AssignmentExpression":
|
|
3616
|
+
this.walkAssignmentExpression(expression);
|
|
3562
3617
|
break;
|
|
3563
|
-
case "
|
|
3564
|
-
this.
|
|
3618
|
+
case "UnaryExpression":
|
|
3619
|
+
this.walkUnaryExpression(expression);
|
|
3565
3620
|
break;
|
|
3566
|
-
case "
|
|
3567
|
-
this.
|
|
3621
|
+
case "LogicalExpression":
|
|
3622
|
+
this.walkLogicalExpression(expression);
|
|
3568
3623
|
break;
|
|
3569
|
-
case "
|
|
3570
|
-
this.
|
|
3624
|
+
case "ArrowFunctionExpression":
|
|
3625
|
+
this.walkArrowFunctionExpression(expression);
|
|
3571
3626
|
break;
|
|
3572
|
-
case "
|
|
3573
|
-
this.
|
|
3627
|
+
case "ThisExpression":
|
|
3628
|
+
this.walkThisExpression(expression);
|
|
3574
3629
|
break;
|
|
3575
|
-
case "
|
|
3576
|
-
this.
|
|
3630
|
+
case "ConditionalExpression":
|
|
3631
|
+
this.walkConditionalExpression(expression);
|
|
3577
3632
|
break;
|
|
3578
|
-
case "
|
|
3579
|
-
this.
|
|
3633
|
+
case "ArrayExpression":
|
|
3634
|
+
this.walkArrayExpression(expression);
|
|
3580
3635
|
break;
|
|
3581
|
-
case "
|
|
3582
|
-
this.
|
|
3636
|
+
case "ObjectExpression":
|
|
3637
|
+
this.walkObjectExpression(expression);
|
|
3583
3638
|
break;
|
|
3584
|
-
case "
|
|
3585
|
-
this.
|
|
3639
|
+
case "FunctionExpression":
|
|
3640
|
+
this.walkFunctionExpression(expression);
|
|
3586
3641
|
break;
|
|
3587
3642
|
case "NewExpression":
|
|
3588
3643
|
this.walkNewExpression(expression);
|
|
3589
3644
|
break;
|
|
3590
|
-
case "
|
|
3591
|
-
this.
|
|
3645
|
+
case "TemplateLiteral":
|
|
3646
|
+
this.walkTemplateLiteral(expression);
|
|
3647
|
+
break;
|
|
3648
|
+
case "SpreadElement":
|
|
3649
|
+
this.walkSpreadElement(expression);
|
|
3592
3650
|
break;
|
|
3593
3651
|
case "SequenceExpression":
|
|
3594
3652
|
this.walkSequenceExpression(expression);
|
|
3595
3653
|
break;
|
|
3596
|
-
case "
|
|
3597
|
-
this.
|
|
3654
|
+
case "UpdateExpression":
|
|
3655
|
+
this.walkUpdateExpression(expression);
|
|
3598
3656
|
break;
|
|
3599
|
-
case "
|
|
3600
|
-
this.
|
|
3657
|
+
case "AwaitExpression":
|
|
3658
|
+
this.walkAwaitExpression(expression);
|
|
3601
3659
|
break;
|
|
3602
|
-
case "
|
|
3603
|
-
this.
|
|
3660
|
+
case "ChainExpression":
|
|
3661
|
+
this.walkChainExpression(expression);
|
|
3604
3662
|
break;
|
|
3605
|
-
case "
|
|
3606
|
-
this.
|
|
3663
|
+
case "ClassExpression":
|
|
3664
|
+
this.walkClassExpression(expression);
|
|
3607
3665
|
break;
|
|
3608
|
-
case "
|
|
3609
|
-
this.
|
|
3666
|
+
case "ImportExpression":
|
|
3667
|
+
this.walkImportExpression(expression);
|
|
3610
3668
|
break;
|
|
3611
|
-
case "
|
|
3612
|
-
this.
|
|
3669
|
+
case "MetaProperty":
|
|
3670
|
+
this.walkMetaProperty(expression);
|
|
3671
|
+
break;
|
|
3672
|
+
case "TaggedTemplateExpression":
|
|
3673
|
+
this.walkTaggedTemplateExpression(expression);
|
|
3613
3674
|
break;
|
|
3614
3675
|
case "YieldExpression":
|
|
3615
3676
|
this.walkYieldExpression(expression);
|
|
@@ -3617,6 +3678,35 @@ class JavascriptParser extends Parser {
|
|
|
3617
3678
|
}
|
|
3618
3679
|
}
|
|
3619
3680
|
|
|
3681
|
+
/**
|
|
3682
|
+
* Reports octal number literals (`0777`) and octal string escapes (`"\47"`),
|
|
3683
|
+
* both SyntaxErrors in strict-mode ESM output.
|
|
3684
|
+
* @param {Literal} expression literal
|
|
3685
|
+
*/
|
|
3686
|
+
_checkStrictModeLiteral(expression) {
|
|
3687
|
+
const raw = /** @type {string | undefined} */ (expression.raw);
|
|
3688
|
+
if (raw === undefined) return;
|
|
3689
|
+
if (typeof expression.value === "number") {
|
|
3690
|
+
// Legacy octal (`0777`) or non-octal decimal (`08`) integer literal.
|
|
3691
|
+
if (
|
|
3692
|
+
raw.length > 1 &&
|
|
3693
|
+
raw.charCodeAt(0) === 48 &&
|
|
3694
|
+
raw.charCodeAt(1) >= 48 &&
|
|
3695
|
+
raw.charCodeAt(1) <= 57
|
|
3696
|
+
) {
|
|
3697
|
+
this._reportStrictModeViolation(
|
|
3698
|
+
"Octal literals are not allowed",
|
|
3699
|
+
expression
|
|
3700
|
+
);
|
|
3701
|
+
}
|
|
3702
|
+
} else if (typeof expression.value === "string" && hasOctalEscape(raw)) {
|
|
3703
|
+
this._reportStrictModeViolation(
|
|
3704
|
+
"Octal escape sequences are not allowed",
|
|
3705
|
+
expression
|
|
3706
|
+
);
|
|
3707
|
+
}
|
|
3708
|
+
}
|
|
3709
|
+
|
|
3620
3710
|
/**
|
|
3621
3711
|
* Walk await expression.
|
|
3622
3712
|
* @param {AwaitExpression} expression await expression
|
|
@@ -3700,6 +3790,9 @@ class JavascriptParser extends Parser {
|
|
|
3700
3790
|
? [...expression.params, expression.id]
|
|
3701
3791
|
: expression.params;
|
|
3702
3792
|
|
|
3793
|
+
if (this._strictInModuleOutput) {
|
|
3794
|
+
this._checkStrictModeParams(expression.params);
|
|
3795
|
+
}
|
|
3703
3796
|
this.inFunctionScope(true, scopeParams, () => {
|
|
3704
3797
|
for (const param of expression.params) {
|
|
3705
3798
|
this.walkPattern(param);
|
|
@@ -3723,6 +3816,9 @@ class JavascriptParser extends Parser {
|
|
|
3723
3816
|
walkArrowFunctionExpression(expression) {
|
|
3724
3817
|
const wasTopLevel = this.scope.topLevelScope;
|
|
3725
3818
|
this.scope.topLevelScope = wasTopLevel ? "arrow" : false;
|
|
3819
|
+
if (this._strictInModuleOutput) {
|
|
3820
|
+
this._checkStrictModeParams(expression.params);
|
|
3821
|
+
}
|
|
3726
3822
|
this.inFunctionScope(false, expression.params, () => {
|
|
3727
3823
|
for (const param of expression.params) {
|
|
3728
3824
|
this.walkPattern(param);
|
|
@@ -3784,9 +3880,84 @@ class JavascriptParser extends Parser {
|
|
|
3784
3880
|
* @param {UpdateExpression} expression the update expression
|
|
3785
3881
|
*/
|
|
3786
3882
|
walkUpdateExpression(expression) {
|
|
3883
|
+
if (
|
|
3884
|
+
this._strictInModuleOutput &&
|
|
3885
|
+
expression.argument.type === "Identifier"
|
|
3886
|
+
) {
|
|
3887
|
+
this._checkStrictModeAssignTarget(expression.argument.name, expression);
|
|
3888
|
+
}
|
|
3787
3889
|
this.walkExpression(expression.argument);
|
|
3788
3890
|
}
|
|
3789
3891
|
|
|
3892
|
+
/**
|
|
3893
|
+
* Reports `arguments.callee` / `arguments.caller` — both throw a TypeError
|
|
3894
|
+
* once the module runs in strict-mode ESM output.
|
|
3895
|
+
* @param {string} name accessed member name
|
|
3896
|
+
* @param {Expression} node node to report the violation at
|
|
3897
|
+
*/
|
|
3898
|
+
_checkStrictModeArgumentsMember(name, node) {
|
|
3899
|
+
if ((name === "callee" || name === "caller") && !this.scope.isStrict) {
|
|
3900
|
+
this._reportStrictModeViolation(
|
|
3901
|
+
`Accessing "arguments.${name}" is not allowed`,
|
|
3902
|
+
node
|
|
3903
|
+
);
|
|
3904
|
+
}
|
|
3905
|
+
}
|
|
3906
|
+
|
|
3907
|
+
/**
|
|
3908
|
+
* Reports an assignment or update target that breaks in strict-mode ESM
|
|
3909
|
+
* output: `eval` / `arguments` are a SyntaxError, the read-only globals
|
|
3910
|
+
* (`undefined`, `NaN`, `Infinity`) a TypeError instead of a silent no-op.
|
|
3911
|
+
* @param {string} name target identifier name
|
|
3912
|
+
* @param {AssignmentExpression | UpdateExpression} node node to report the violation at
|
|
3913
|
+
*/
|
|
3914
|
+
_checkStrictModeAssignTarget(name, node) {
|
|
3915
|
+
if (name === "eval" || name === "arguments") {
|
|
3916
|
+
this._reportStrictModeViolation(
|
|
3917
|
+
`Assigning to "${name}" is not allowed`,
|
|
3918
|
+
node
|
|
3919
|
+
);
|
|
3920
|
+
} else if (
|
|
3921
|
+
(name === "undefined" || name === "NaN" || name === "Infinity") &&
|
|
3922
|
+
!this.scope.isStrict &&
|
|
3923
|
+
!this.isVariableDefined(name)
|
|
3924
|
+
) {
|
|
3925
|
+
this._reportStrictModeViolation(
|
|
3926
|
+
`Assigning to the read-only global "${name}" is not allowed`,
|
|
3927
|
+
node
|
|
3928
|
+
);
|
|
3929
|
+
}
|
|
3930
|
+
}
|
|
3931
|
+
|
|
3932
|
+
/**
|
|
3933
|
+
* Reports strict-mode-only errors in a function's parameter list: a duplicate
|
|
3934
|
+
* simple parameter, or a parameter named `eval` / `arguments`.
|
|
3935
|
+
* @param {(import("estree").Pattern)[]} params function parameters
|
|
3936
|
+
*/
|
|
3937
|
+
_checkStrictModeParams(params) {
|
|
3938
|
+
/** @type {Set<string> | undefined} */
|
|
3939
|
+
let seen;
|
|
3940
|
+
for (const param of params) {
|
|
3941
|
+
if (param.type !== "Identifier") continue;
|
|
3942
|
+
const name = param.name;
|
|
3943
|
+
if (name === "eval" || name === "arguments") {
|
|
3944
|
+
this._reportStrictModeViolation(
|
|
3945
|
+
`"${name}" is not allowed as a parameter name`,
|
|
3946
|
+
param
|
|
3947
|
+
);
|
|
3948
|
+
}
|
|
3949
|
+
if (seen === undefined) seen = new Set();
|
|
3950
|
+
if (seen.has(name)) {
|
|
3951
|
+
this._reportStrictModeViolation(
|
|
3952
|
+
`Duplicate parameter name "${name}" is not allowed`,
|
|
3953
|
+
param
|
|
3954
|
+
);
|
|
3955
|
+
} else {
|
|
3956
|
+
seen.add(name);
|
|
3957
|
+
}
|
|
3958
|
+
}
|
|
3959
|
+
}
|
|
3960
|
+
|
|
3790
3961
|
/**
|
|
3791
3962
|
* Walk unary expression.
|
|
3792
3963
|
* @param {UnaryExpression} expression the unary expression
|
|
@@ -3807,10 +3978,39 @@ class JavascriptParser extends Parser {
|
|
|
3807
3978
|
);
|
|
3808
3979
|
if (result === true) return;
|
|
3809
3980
|
}
|
|
3981
|
+
} else if (
|
|
3982
|
+
this._strictInModuleOutput &&
|
|
3983
|
+
expression.operator === "delete" &&
|
|
3984
|
+
expression.argument.type === "Identifier"
|
|
3985
|
+
) {
|
|
3986
|
+
this._reportStrictModeViolation(
|
|
3987
|
+
`Deleting the unqualified identifier "${expression.argument.name}" is not allowed`,
|
|
3988
|
+
expression
|
|
3989
|
+
);
|
|
3810
3990
|
}
|
|
3811
3991
|
this.walkExpression(expression.argument);
|
|
3812
3992
|
}
|
|
3813
3993
|
|
|
3994
|
+
/**
|
|
3995
|
+
* Reports a construct that a loose script allows but that breaks once the
|
|
3996
|
+
* module is emitted as strict-mode ESM output. Severity comes from the
|
|
3997
|
+
* `strictModeViolations` parser option (`false` disables the checks upfront).
|
|
3998
|
+
* The location is computed here, on the rare violation path only.
|
|
3999
|
+
* @param {string} reason what is not allowed
|
|
4000
|
+
* @param {Statement | Expression | Identifier} node node to report the violation at
|
|
4001
|
+
*/
|
|
4002
|
+
_reportStrictModeViolation(reason, node) {
|
|
4003
|
+
const diagnostic = new WebpackError(
|
|
4004
|
+
`${reason}. The output is an ES module, which runs in strict mode.`
|
|
4005
|
+
);
|
|
4006
|
+
diagnostic.loc = this.getLocation(node);
|
|
4007
|
+
if (this.options.strictModeViolations === "error") {
|
|
4008
|
+
this.state.module.addError(diagnostic);
|
|
4009
|
+
} else {
|
|
4010
|
+
this.state.module.addWarning(diagnostic);
|
|
4011
|
+
}
|
|
4012
|
+
}
|
|
4013
|
+
|
|
3814
4014
|
/**
|
|
3815
4015
|
* Walk left right expression.
|
|
3816
4016
|
* @param {LogicalExpression | BinaryExpression} expression the expression
|
|
@@ -3849,6 +4049,9 @@ class JavascriptParser extends Parser {
|
|
|
3849
4049
|
*/
|
|
3850
4050
|
walkAssignmentExpression(expression) {
|
|
3851
4051
|
if (expression.left.type === "Identifier") {
|
|
4052
|
+
if (this._strictInModuleOutput) {
|
|
4053
|
+
this._checkStrictModeAssignTarget(expression.left.name, expression);
|
|
4054
|
+
}
|
|
3852
4055
|
const renameIdentifier = this.getRenameIdentifier(expression.right);
|
|
3853
4056
|
if (
|
|
3854
4057
|
renameIdentifier &&
|
|
@@ -3950,38 +4153,6 @@ class JavascriptParser extends Parser {
|
|
|
3950
4153
|
* @param {NewExpression} expression new expression
|
|
3951
4154
|
*/
|
|
3952
4155
|
walkNewExpression(expression) {
|
|
3953
|
-
// TODO acorn-import-phases bug: it omits acorn's `!forNew` guard, so
|
|
3954
|
-
// `import.defer(...)`/`import.source(...)` are wrongly accepted as `new`
|
|
3955
|
-
// operands; drop once fixed. Parenthesized forms stay valid (check `(`).
|
|
3956
|
-
if (typeof this.state.source === "string") {
|
|
3957
|
-
let base = expression.callee;
|
|
3958
|
-
while (
|
|
3959
|
-
base.type === "MemberExpression" ||
|
|
3960
|
-
base.type === "CallExpression"
|
|
3961
|
-
) {
|
|
3962
|
-
base = base.type === "MemberExpression" ? base.object : base.callee;
|
|
3963
|
-
}
|
|
3964
|
-
if (base.type === "ImportExpression") {
|
|
3965
|
-
const newStart = /** @type {Range} */ (expression.range)[0];
|
|
3966
|
-
const importStart = /** @type {Range} */ (base.range)[0];
|
|
3967
|
-
const between = this.state.source
|
|
3968
|
-
.slice(newStart, importStart)
|
|
3969
|
-
.replace(/\/\*[\s\S]*?\*\//g, "")
|
|
3970
|
-
.replace(/\/\/[^\n]*/g, "");
|
|
3971
|
-
if (!between.includes("(")) {
|
|
3972
|
-
const err =
|
|
3973
|
-
/** @type {SyntaxError & { loc?: { line: number, column: number } }} */
|
|
3974
|
-
(new SyntaxError("import call cannot be the target of `new`"));
|
|
3975
|
-
if (expression.loc) {
|
|
3976
|
-
err.loc = {
|
|
3977
|
-
line: expression.loc.start.line,
|
|
3978
|
-
column: expression.loc.start.column
|
|
3979
|
-
};
|
|
3980
|
-
}
|
|
3981
|
-
throw err;
|
|
3982
|
-
}
|
|
3983
|
-
}
|
|
3984
|
-
}
|
|
3985
4156
|
const result = this.callHooksForExpression(
|
|
3986
4157
|
this.hooks.new,
|
|
3987
4158
|
expression.callee,
|
|
@@ -4223,19 +4394,33 @@ class JavascriptParser extends Parser {
|
|
|
4223
4394
|
if (result === true) return;
|
|
4224
4395
|
}
|
|
4225
4396
|
}
|
|
4397
|
+
if (
|
|
4398
|
+
expression.callee.type === "Identifier" &&
|
|
4399
|
+
this._evalIdentOwnTaps &&
|
|
4400
|
+
expression.callee.name !== "undefined" &&
|
|
4401
|
+
this._isDefinedPlainVariable(expression.callee.name)
|
|
4402
|
+
) {
|
|
4403
|
+
// a defined, untagged callee can only evaluate to the fallthrough
|
|
4404
|
+
// result, so no call hooks apply — walk callee and arguments
|
|
4405
|
+
// directly, skipping the hook dispatch and its result object
|
|
4406
|
+
this.walkExpression(expression.callee);
|
|
4407
|
+
if (expression.arguments) this.walkExpressions(expression.arguments);
|
|
4408
|
+
return;
|
|
4409
|
+
}
|
|
4226
4410
|
const callee = this.evaluateExpression(expression.callee);
|
|
4227
4411
|
if (callee.isIdentifier()) {
|
|
4412
|
+
const members =
|
|
4413
|
+
/** @type {NonNullable<BasicEvaluatedExpression["getMembers"]>} */
|
|
4414
|
+
(callee.getMembers)();
|
|
4228
4415
|
const result1 = this.callHooksForInfo(
|
|
4229
4416
|
this.hooks.callMemberChain,
|
|
4230
4417
|
/** @type {NonNullable<BasicEvaluatedExpression["rootInfo"]>} */
|
|
4231
4418
|
(callee.rootInfo),
|
|
4232
4419
|
expression,
|
|
4233
|
-
|
|
4234
|
-
(callee.getMembers)(),
|
|
4420
|
+
members,
|
|
4235
4421
|
callee.getMembersOptionals
|
|
4236
4422
|
? callee.getMembersOptionals()
|
|
4237
|
-
:
|
|
4238
|
-
(callee.getMembers)().map(() => false),
|
|
4423
|
+
: members.map(RETURN_FALSE),
|
|
4239
4424
|
callee.getMemberRanges ? callee.getMemberRanges() : []
|
|
4240
4425
|
);
|
|
4241
4426
|
if (result1 === true) return;
|
|
@@ -4739,22 +4924,14 @@ class JavascriptParser extends Parser {
|
|
|
4739
4924
|
*/
|
|
4740
4925
|
enterPattern(pattern, onIdent) {
|
|
4741
4926
|
if (!pattern) return;
|
|
4927
|
+
// plain identifiers dominate bindings, so match them first
|
|
4742
4928
|
switch (pattern.type) {
|
|
4743
|
-
case "ArrayPattern":
|
|
4744
|
-
this.enterArrayPattern(pattern, onIdent);
|
|
4745
|
-
break;
|
|
4746
|
-
case "AssignmentPattern":
|
|
4747
|
-
this.enterAssignmentPattern(pattern, onIdent);
|
|
4748
|
-
break;
|
|
4749
4929
|
case "Identifier":
|
|
4750
4930
|
this.enterIdentifier(pattern, onIdent);
|
|
4751
4931
|
break;
|
|
4752
4932
|
case "ObjectPattern":
|
|
4753
4933
|
this.enterObjectPattern(pattern, onIdent);
|
|
4754
4934
|
break;
|
|
4755
|
-
case "RestElement":
|
|
4756
|
-
this.enterRestElement(pattern, onIdent);
|
|
4757
|
-
break;
|
|
4758
4935
|
case "Property":
|
|
4759
4936
|
if (pattern.shorthand && pattern.value.type === "Identifier") {
|
|
4760
4937
|
this.scope.inShorthand = pattern.value.name;
|
|
@@ -4764,6 +4941,15 @@ class JavascriptParser extends Parser {
|
|
|
4764
4941
|
this.enterPattern(/** @type {Pattern} */ (pattern.value), onIdent);
|
|
4765
4942
|
}
|
|
4766
4943
|
break;
|
|
4944
|
+
case "ArrayPattern":
|
|
4945
|
+
this.enterArrayPattern(pattern, onIdent);
|
|
4946
|
+
break;
|
|
4947
|
+
case "AssignmentPattern":
|
|
4948
|
+
this.enterAssignmentPattern(pattern, onIdent);
|
|
4949
|
+
break;
|
|
4950
|
+
case "RestElement":
|
|
4951
|
+
this.enterRestElement(pattern, onIdent);
|
|
4952
|
+
break;
|
|
4767
4953
|
}
|
|
4768
4954
|
}
|
|
4769
4955
|
|
|
@@ -4851,9 +5037,9 @@ class JavascriptParser extends Parser {
|
|
|
4851
5037
|
console.warn(err);
|
|
4852
5038
|
// ignore error
|
|
4853
5039
|
}
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
5040
|
+
// no setRange: the range is served lazily from the expression on first
|
|
5041
|
+
// read, so plain results don't materialize the node's range array at all
|
|
5042
|
+
return new BasicEvaluatedExpression().setExpression(expression);
|
|
4857
5043
|
}
|
|
4858
5044
|
|
|
4859
5045
|
/**
|
|
@@ -4992,30 +5178,21 @@ class JavascriptParser extends Parser {
|
|
|
4992
5178
|
let ast;
|
|
4993
5179
|
/** @type {Comment[]} */
|
|
4994
5180
|
let comments;
|
|
4995
|
-
/** @type {Set<number>} */
|
|
4996
|
-
let semicolons;
|
|
4997
5181
|
|
|
4998
5182
|
if (typeof source === "object") {
|
|
4999
|
-
semicolons = new Set();
|
|
5000
|
-
|
|
5001
5183
|
ast = /** @type {Program} */ (source);
|
|
5002
5184
|
comments = source.comments;
|
|
5003
|
-
if (source.semicolons) {
|
|
5004
|
-
// Forward semicolon information from the preparsed AST if present
|
|
5005
|
-
// This ensures the output is consistent with that of a fresh AST
|
|
5006
|
-
for (const pos of source.semicolons) {
|
|
5007
|
-
semicolons.add(pos);
|
|
5008
|
-
}
|
|
5009
|
-
}
|
|
5010
5185
|
} else {
|
|
5011
|
-
({ ast, comments
|
|
5186
|
+
({ ast, comments } = JavascriptParser._parse(
|
|
5012
5187
|
source,
|
|
5013
5188
|
{
|
|
5014
5189
|
sourceType: this.sourceType,
|
|
5015
|
-
locations
|
|
5190
|
+
// line/column locations are derived from node offsets via
|
|
5191
|
+
// getLocation — parsers never need to track them
|
|
5192
|
+
locations: false,
|
|
5016
5193
|
ranges: true,
|
|
5017
5194
|
comments: true,
|
|
5018
|
-
|
|
5195
|
+
importPhases: this.options.importPhases === true
|
|
5019
5196
|
},
|
|
5020
5197
|
this.options.parse
|
|
5021
5198
|
));
|
|
@@ -5027,6 +5204,18 @@ class JavascriptParser extends Parser {
|
|
|
5027
5204
|
const oldSemicolons = this.semicolons;
|
|
5028
5205
|
const oldStatementPath = this.statementPath;
|
|
5029
5206
|
const oldPrevStatement = this.prevStatement;
|
|
5207
|
+
const oldStrictInModuleOutput = this._strictInModuleOutput;
|
|
5208
|
+
const oldSource = this._source;
|
|
5209
|
+
const oldLineStarts = this._lineStarts;
|
|
5210
|
+
// a preparsed AST carries no text, but the build passes the module
|
|
5211
|
+
// source in the state — offsets still map for it
|
|
5212
|
+
this._source =
|
|
5213
|
+
typeof source === "string"
|
|
5214
|
+
? source
|
|
5215
|
+
: typeof state.source === "string"
|
|
5216
|
+
? state.source
|
|
5217
|
+
: undefined;
|
|
5218
|
+
this._lineStarts = undefined;
|
|
5030
5219
|
this.scope = {
|
|
5031
5220
|
topLevelScope: true,
|
|
5032
5221
|
inTry: false,
|
|
@@ -5039,12 +5228,32 @@ class JavascriptParser extends Parser {
|
|
|
5039
5228
|
};
|
|
5040
5229
|
this.state = state;
|
|
5041
5230
|
this.comments = comments;
|
|
5042
|
-
this.semicolons =
|
|
5231
|
+
this.semicolons = undefined;
|
|
5232
|
+
// evaluating a defined, untagged identifier can only fall through when
|
|
5233
|
+
// every `evaluate.for("Identifier")` tap is the parser's own — plugins
|
|
5234
|
+
// tapping or intercepting it disable the callee/rename fast paths
|
|
5235
|
+
const identifierEvalHook = this.hooks.evaluate.get("Identifier");
|
|
5236
|
+
this._evalIdentOwnTaps =
|
|
5237
|
+
identifierEvalHook !== undefined &&
|
|
5238
|
+
identifierEvalHook.interceptors.length === 0 &&
|
|
5239
|
+
identifierEvalHook.taps.every((tap) => tap.name === CLASS_NAME);
|
|
5043
5240
|
this.statementPath = [];
|
|
5044
5241
|
this.prevStatement = undefined;
|
|
5242
|
+
// The output is emitted as strict-mode ESM, but this module was parsed as
|
|
5243
|
+
// a loose script — acorn skipped the strict early errors that will break
|
|
5244
|
+
// the bundle at runtime. Enables the strict-mode diagnostics below.
|
|
5245
|
+
this._strictInModuleOutput =
|
|
5246
|
+
this.options.strictModeViolations !== false &&
|
|
5247
|
+
state.compilation !== undefined &&
|
|
5248
|
+
state.compilation.runtimeTemplate.isModule();
|
|
5045
5249
|
if (this.hooks.program.call(ast, comments) === undefined) {
|
|
5046
5250
|
this.destructuringAssignmentProperties = new WeakMap();
|
|
5047
5251
|
this.detectMode(ast.body);
|
|
5252
|
+
// a strict program (ESM source, `"use strict"`) keeps its behavior in
|
|
5253
|
+
// strict output — drop the flag so the walk pays no per-node checks
|
|
5254
|
+
if (this._strictInModuleOutput && this.scope.isStrict) {
|
|
5255
|
+
this._strictInModuleOutput = false;
|
|
5256
|
+
}
|
|
5048
5257
|
this.modulePreWalkStatements(ast.body);
|
|
5049
5258
|
this.prevStatement = undefined;
|
|
5050
5259
|
this.preWalkStatements(ast.body);
|
|
@@ -5061,6 +5270,10 @@ class JavascriptParser extends Parser {
|
|
|
5061
5270
|
this.semicolons = oldSemicolons;
|
|
5062
5271
|
this.statementPath = oldStatementPath;
|
|
5063
5272
|
this.prevStatement = oldPrevStatement;
|
|
5273
|
+
this._strictInModuleOutput = oldStrictInModuleOutput;
|
|
5274
|
+
// release — these retain the whole source string and its line table
|
|
5275
|
+
this._source = oldSource;
|
|
5276
|
+
this._lineStarts = oldLineStarts;
|
|
5064
5277
|
return state;
|
|
5065
5278
|
}
|
|
5066
5279
|
|
|
@@ -5070,11 +5283,41 @@ class JavascriptParser extends Parser {
|
|
|
5070
5283
|
* @returns {BasicEvaluatedExpression} evaluation result
|
|
5071
5284
|
*/
|
|
5072
5285
|
evaluate(source) {
|
|
5073
|
-
const
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5286
|
+
const importPhases = this.options.importPhases === true;
|
|
5287
|
+
const compilation = this.state && this.state.compilation;
|
|
5288
|
+
/** @type {Map<string, Program> | undefined} */
|
|
5289
|
+
let cache;
|
|
5290
|
+
// custom parse functions are not necessarily pure, do not cache for them
|
|
5291
|
+
if (compilation !== undefined && typeof this.options.parse !== "function") {
|
|
5292
|
+
cache = evaluateAstCaches.get(compilation);
|
|
5293
|
+
if (cache === undefined) {
|
|
5294
|
+
cache = new Map();
|
|
5295
|
+
evaluateAstCaches.set(compilation, cache);
|
|
5296
|
+
}
|
|
5297
|
+
}
|
|
5298
|
+
const cacheKey =
|
|
5299
|
+
cache === undefined
|
|
5300
|
+
? undefined
|
|
5301
|
+
: `${this.sourceType}|${importPhases}|${source}`;
|
|
5302
|
+
let ast =
|
|
5303
|
+
cacheKey === undefined
|
|
5304
|
+
? undefined
|
|
5305
|
+
: /** @type {Map<string, Program>} */ (cache).get(cacheKey);
|
|
5306
|
+
if (ast === undefined) {
|
|
5307
|
+
({ ast } = JavascriptParser._parse(
|
|
5308
|
+
`(${source})`,
|
|
5309
|
+
{
|
|
5310
|
+
sourceType: this.sourceType,
|
|
5311
|
+
importPhases
|
|
5312
|
+
},
|
|
5313
|
+
this.options.parse
|
|
5314
|
+
));
|
|
5315
|
+
if (cacheKey !== undefined) {
|
|
5316
|
+
const map = /** @type {Map<string, Program>} */ (cache);
|
|
5317
|
+
if (map.size >= EVALUATE_AST_CACHE_LIMIT) map.clear();
|
|
5318
|
+
map.set(cacheKey, ast);
|
|
5319
|
+
}
|
|
5320
|
+
}
|
|
5078
5321
|
if (ast.body.length !== 1 || ast.body[0].type !== "ExpressionStatement") {
|
|
5079
5322
|
throw new Error("evaluate: Source is not a expression");
|
|
5080
5323
|
}
|
|
@@ -5333,34 +5576,127 @@ class JavascriptParser extends Parser {
|
|
|
5333
5576
|
return !evaluated.couldHaveSideEffects();
|
|
5334
5577
|
}
|
|
5335
5578
|
|
|
5579
|
+
/**
|
|
5580
|
+
* Returns the location of a node or comment, computed from its offsets so
|
|
5581
|
+
* ASTs from parsers without location support work too. Falls back to the
|
|
5582
|
+
* node's own `loc` only when no source text is available (preparsed ASTs).
|
|
5583
|
+
* Offsets can only be mapped while parsing — callbacks deferred past the
|
|
5584
|
+
* `parse()` call must take the location upfront.
|
|
5585
|
+
* @param {{ start?: number, end?: number, range?: Range, loc?: SourceLocation | null }} node node or comment
|
|
5586
|
+
* @returns {DependencyLocation} location of the node
|
|
5587
|
+
*/
|
|
5588
|
+
getLocation(node) {
|
|
5589
|
+
const source = this._source;
|
|
5590
|
+
if (source !== undefined) {
|
|
5591
|
+
const start =
|
|
5592
|
+
typeof node.start === "number"
|
|
5593
|
+
? node.start
|
|
5594
|
+
: node.range
|
|
5595
|
+
? node.range[0]
|
|
5596
|
+
: undefined;
|
|
5597
|
+
if (start !== undefined) {
|
|
5598
|
+
const end =
|
|
5599
|
+
typeof node.end === "number"
|
|
5600
|
+
? node.end
|
|
5601
|
+
: node.range
|
|
5602
|
+
? node.range[1]
|
|
5603
|
+
: start;
|
|
5604
|
+
const lineStarts =
|
|
5605
|
+
this._lineStarts || (this._lineStarts = buildLineStarts(source));
|
|
5606
|
+
return {
|
|
5607
|
+
start: positionAt(lineStarts, start),
|
|
5608
|
+
end: positionAt(lineStarts, end)
|
|
5609
|
+
};
|
|
5610
|
+
}
|
|
5611
|
+
}
|
|
5612
|
+
return /** @type {DependencyLocation} */ (node.loc);
|
|
5613
|
+
}
|
|
5614
|
+
|
|
5336
5615
|
/**
|
|
5337
5616
|
* Returns comments in the range.
|
|
5338
5617
|
* @param {Range} range range
|
|
5339
5618
|
* @returns {Comment[]} comments in the range
|
|
5340
5619
|
*/
|
|
5341
5620
|
getComments(range) {
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5621
|
+
return getCommentsInRange(
|
|
5622
|
+
/** @type {(Comment & { range: [number, number] })[]} */ (this.comments),
|
|
5623
|
+
range
|
|
5624
|
+
);
|
|
5625
|
+
}
|
|
5626
|
+
|
|
5627
|
+
/**
|
|
5628
|
+
* First significant char code at or after `pos`, skipping whitespace and
|
|
5629
|
+
* comments, or -1 at end of source.
|
|
5630
|
+
* @param {string} source source text
|
|
5631
|
+
* @param {number} pos start offset
|
|
5632
|
+
* @returns {number} char code of the next token, or -1
|
|
5633
|
+
*/
|
|
5634
|
+
_nextTokenCharCode(source, pos) {
|
|
5635
|
+
const len = source.length;
|
|
5636
|
+
for (let i = pos; i < len; i++) {
|
|
5637
|
+
const c = source.charCodeAt(i);
|
|
5638
|
+
// whitespace and line terminators acorn skips between tokens
|
|
5639
|
+
if (
|
|
5640
|
+
c === 32 ||
|
|
5641
|
+
c === 9 ||
|
|
5642
|
+
c === 10 ||
|
|
5643
|
+
c === 13 ||
|
|
5644
|
+
c === 11 ||
|
|
5645
|
+
c === 12 ||
|
|
5646
|
+
c === 0xa0 ||
|
|
5647
|
+
c === 0xfeff ||
|
|
5648
|
+
c === 0x2028 ||
|
|
5649
|
+
c === 0x2029
|
|
5650
|
+
) {
|
|
5651
|
+
continue;
|
|
5652
|
+
}
|
|
5653
|
+
if (c === 47 /* / */) {
|
|
5654
|
+
const n = source.charCodeAt(i + 1);
|
|
5655
|
+
if (n === 47 /* / */) {
|
|
5656
|
+
i += 2;
|
|
5657
|
+
while (i < len) {
|
|
5658
|
+
const cc = source.charCodeAt(i);
|
|
5659
|
+
if (cc === 10 || cc === 13 || cc === 0x2028 || cc === 0x2029) break;
|
|
5660
|
+
i++;
|
|
5661
|
+
}
|
|
5662
|
+
continue;
|
|
5663
|
+
}
|
|
5664
|
+
if (n === 42 /* * */) {
|
|
5665
|
+
i += 2;
|
|
5666
|
+
while (
|
|
5667
|
+
i < len &&
|
|
5668
|
+
!(source.charCodeAt(i) === 42 && source.charCodeAt(i + 1) === 47)
|
|
5669
|
+
) {
|
|
5670
|
+
i++;
|
|
5671
|
+
}
|
|
5672
|
+
i++;
|
|
5673
|
+
continue;
|
|
5674
|
+
}
|
|
5675
|
+
}
|
|
5676
|
+
return c;
|
|
5361
5677
|
}
|
|
5678
|
+
return -1;
|
|
5679
|
+
}
|
|
5362
5680
|
|
|
5363
|
-
|
|
5681
|
+
/**
|
|
5682
|
+
* Whether a statement ending at `pos` relies on ASI (no real separator).
|
|
5683
|
+
* Derived from the source text unless overridden by set/unsetAsiPosition.
|
|
5684
|
+
* A statement terminated by a real `;` or continued by a `,` (a sequence
|
|
5685
|
+
* element) is not an ASI position; anything else (newline, `}`, eof) is.
|
|
5686
|
+
* @param {number} pos statement end offset
|
|
5687
|
+
* @returns {boolean} true when ASI inserts a semicolon at this position
|
|
5688
|
+
*/
|
|
5689
|
+
_isAsiPosition(pos) {
|
|
5690
|
+
if (this.semicolons !== undefined) {
|
|
5691
|
+
const override = this.semicolons.get(pos);
|
|
5692
|
+
if (override !== undefined) return override;
|
|
5693
|
+
}
|
|
5694
|
+
const source = this._source;
|
|
5695
|
+
if (source === undefined) return true;
|
|
5696
|
+
// a real semicolon is the statement's last char (exclusive end at pos)
|
|
5697
|
+
if (source.charCodeAt(pos - 1) === 59 /* ; */) return false;
|
|
5698
|
+
const next = this._nextTokenCharCode(source, pos);
|
|
5699
|
+
return next !== 44 /* , */ && next !== 59; /* ; */
|
|
5364
5700
|
}
|
|
5365
5701
|
|
|
5366
5702
|
/**
|
|
@@ -5380,17 +5716,14 @@ class JavascriptParser extends Parser {
|
|
|
5380
5716
|
|
|
5381
5717
|
return (
|
|
5382
5718
|
// Either asking directly for the end position of the current statement
|
|
5383
|
-
(range[1] === pos &&
|
|
5384
|
-
/** @type {Set<number>} */ (this.semicolons).has(pos)) ||
|
|
5719
|
+
(range[1] === pos && this._isAsiPosition(pos)) ||
|
|
5385
5720
|
// Or asking for the start position of the current statement,
|
|
5386
5721
|
// here we have to check multiple things
|
|
5387
5722
|
(range[0] === pos &&
|
|
5388
5723
|
// is there a previous statement which might be relevant?
|
|
5389
5724
|
this.prevStatement !== undefined &&
|
|
5390
5725
|
// is the end position of the previous statement an ASI position?
|
|
5391
|
-
/** @type {
|
|
5392
|
-
/** @type {Range} */ (this.prevStatement.range)[1]
|
|
5393
|
-
))
|
|
5726
|
+
this._isAsiPosition(/** @type {Range} */ (this.prevStatement.range)[1]))
|
|
5394
5727
|
);
|
|
5395
5728
|
}
|
|
5396
5729
|
|
|
@@ -5400,7 +5733,7 @@ class JavascriptParser extends Parser {
|
|
|
5400
5733
|
* @returns {void}
|
|
5401
5734
|
*/
|
|
5402
5735
|
setAsiPosition(pos) {
|
|
5403
|
-
|
|
5736
|
+
(this.semicolons || (this.semicolons = new Map())).set(pos, true);
|
|
5404
5737
|
}
|
|
5405
5738
|
|
|
5406
5739
|
/**
|
|
@@ -5409,7 +5742,7 @@ class JavascriptParser extends Parser {
|
|
|
5409
5742
|
* @returns {void}
|
|
5410
5743
|
*/
|
|
5411
5744
|
unsetAsiPosition(pos) {
|
|
5412
|
-
|
|
5745
|
+
(this.semicolons || (this.semicolons = new Map())).set(pos, false);
|
|
5413
5746
|
}
|
|
5414
5747
|
|
|
5415
5748
|
/**
|
|
@@ -5524,6 +5857,22 @@ class JavascriptParser extends Parser {
|
|
|
5524
5857
|
return true;
|
|
5525
5858
|
}
|
|
5526
5859
|
|
|
5860
|
+
/**
|
|
5861
|
+
* Whether evaluating an identifier of this name can only fall through:
|
|
5862
|
+
* the exact negative of the identifier evaluator's `getInfo` — defined in
|
|
5863
|
+
* some scope and neither free nor tagged nor carrying tag info.
|
|
5864
|
+
* @param {string} name variable name
|
|
5865
|
+
* @returns {boolean} true when the identifier evaluates to nothing
|
|
5866
|
+
*/
|
|
5867
|
+
_isDefinedPlainVariable(name) {
|
|
5868
|
+
const info = this.scope.definitions.get(name);
|
|
5869
|
+
if (info === undefined) return false;
|
|
5870
|
+
if (info instanceof VariableInfo) {
|
|
5871
|
+
return !(info.isFree() || info.isTagged() || info.tagInfo !== undefined);
|
|
5872
|
+
}
|
|
5873
|
+
return true;
|
|
5874
|
+
}
|
|
5875
|
+
|
|
5527
5876
|
/**
|
|
5528
5877
|
* Gets variable info.
|
|
5529
5878
|
* @param {string} name variable name
|
|
@@ -5583,42 +5932,13 @@ class JavascriptParser extends Parser {
|
|
|
5583
5932
|
* @returns {{ options: Record<string, EXPECTED_ANY> | null, errors: (Error & { comment: Comment })[] | null }} result
|
|
5584
5933
|
*/
|
|
5585
5934
|
parseCommentOptions(range) {
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
const errors = [];
|
|
5594
|
-
for (const comment of comments) {
|
|
5595
|
-
const { value } = comment;
|
|
5596
|
-
if (value && webpackCommentRegExp.test(value)) {
|
|
5597
|
-
// try compile only if webpack options comment is present
|
|
5598
|
-
try {
|
|
5599
|
-
for (let [key, val] of Object.entries(
|
|
5600
|
-
vm.runInContext(
|
|
5601
|
-
`(function(){return {${value}};})()`,
|
|
5602
|
-
this.magicCommentContext
|
|
5603
|
-
)
|
|
5604
|
-
)) {
|
|
5605
|
-
if (typeof val === "object" && val !== null) {
|
|
5606
|
-
val =
|
|
5607
|
-
val.constructor.name === "RegExp"
|
|
5608
|
-
? new RegExp(val)
|
|
5609
|
-
: JSON.parse(JSON.stringify(val));
|
|
5610
|
-
}
|
|
5611
|
-
options[key] = val;
|
|
5612
|
-
}
|
|
5613
|
-
} catch (err) {
|
|
5614
|
-
const newErr = new Error(String(/** @type {Error} */ (err).message));
|
|
5615
|
-
newErr.stack = String(/** @type {Error} */ (err).stack);
|
|
5616
|
-
Object.assign(newErr, { comment });
|
|
5617
|
-
errors.push(/** @type {(Error & { comment: Comment })} */ (newErr));
|
|
5618
|
-
}
|
|
5619
|
-
}
|
|
5620
|
-
}
|
|
5621
|
-
return { options, errors };
|
|
5935
|
+
return parseCommentOptionsInRange(
|
|
5936
|
+
/** @type {(Comment & { range: [number, number], value: string })[]} */ (
|
|
5937
|
+
this.comments
|
|
5938
|
+
),
|
|
5939
|
+
range,
|
|
5940
|
+
this.magicCommentContext
|
|
5941
|
+
);
|
|
5622
5942
|
}
|
|
5623
5943
|
|
|
5624
5944
|
/**
|
|
@@ -5852,12 +6172,30 @@ class JavascriptParser extends Parser {
|
|
|
5852
6172
|
static _parse(code, options, customParse) {
|
|
5853
6173
|
const type = options ? options.sourceType : "module";
|
|
5854
6174
|
/** @type {ParseOptions} */
|
|
5855
|
-
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
6175
|
+
let parserOptions;
|
|
6176
|
+
if (typeof customParse === "function") {
|
|
6177
|
+
// a user parse function may retain the options object — keep it fresh
|
|
6178
|
+
parserOptions = {
|
|
6179
|
+
...defaultParserOptions,
|
|
6180
|
+
allowReturnOutsideFunction: type === "script",
|
|
6181
|
+
...options,
|
|
6182
|
+
sourceType: type === "auto" ? "module" : type
|
|
6183
|
+
};
|
|
6184
|
+
} else {
|
|
6185
|
+
// reuse one options object across parses (parsing is synchronous) to
|
|
6186
|
+
// skip re-materializing it per module; acorn copies it via getOptions.
|
|
6187
|
+
// Every non-default key a caller may pass must be reset here.
|
|
6188
|
+
parserOptions = REUSED_PARSER_OPTIONS;
|
|
6189
|
+
parserOptions.importPhases = false;
|
|
6190
|
+
Object.assign(parserOptions, defaultParserOptions);
|
|
6191
|
+
parserOptions.allowReturnOutsideFunction = type === "script";
|
|
6192
|
+
if (options) Object.assign(parserOptions, options);
|
|
6193
|
+
parserOptions.sourceType = type === "auto" ? "module" : type;
|
|
6194
|
+
// let WebpackParser downgrade module->script in place on script-only
|
|
6195
|
+
// syntax so `auto` avoids a second full parse in the common case
|
|
6196
|
+
parserOptions.moduleFallback = type === "auto";
|
|
6197
|
+
}
|
|
6198
|
+
const wantRanges = parserOptions.ranges === true;
|
|
5861
6199
|
/**
|
|
5862
6200
|
* Returns parse result.
|
|
5863
6201
|
* @param {string} code source code
|
|
@@ -5872,36 +6210,46 @@ class JavascriptParser extends Parser {
|
|
|
5872
6210
|
/** @type {Comment[]} */
|
|
5873
6211
|
const comments = [];
|
|
5874
6212
|
|
|
5875
|
-
|
|
5876
|
-
|
|
5877
|
-
|
|
6213
|
+
// Whenever ranges are wanted (the main parse path and the concatenation
|
|
6214
|
+
// re-parse), have the parser plugin serve `range` on demand instead of
|
|
6215
|
+
// eagerly. `wantRanges` is hoisted since the auto-fallback re-enters
|
|
6216
|
+
// with the same (mutated) options object.
|
|
6217
|
+
options.lazyNodes = wantRanges;
|
|
6218
|
+
if (wantRanges) {
|
|
6219
|
+
// the lazy plugin replaces acorn's native tracking — disabling it
|
|
6220
|
+
// here lets WebpackParser skip its defensive options copy
|
|
6221
|
+
options.locations = false;
|
|
6222
|
+
options.ranges = false;
|
|
5878
6223
|
}
|
|
5879
6224
|
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
6225
|
+
if (options.comments) {
|
|
6226
|
+
if (wantRanges) {
|
|
6227
|
+
// the parser plugin collects the comments itself, deferring the
|
|
6228
|
+
// text slice until some hook actually reads `value`
|
|
6229
|
+
options.lazyComments = comments;
|
|
6230
|
+
} else {
|
|
6231
|
+
/** @type {AcornOptions} */
|
|
6232
|
+
(options).onComment =
|
|
6233
|
+
/** @type {import("acorn").Comment[]} */
|
|
6234
|
+
(/** @type {unknown} */ (comments));
|
|
6235
|
+
}
|
|
5886
6236
|
}
|
|
5887
6237
|
|
|
5888
6238
|
const ast =
|
|
5889
6239
|
/** @type {Program} */
|
|
5890
6240
|
(parser.parse(code, /** @type {AcornOptions} */ (options)));
|
|
5891
6241
|
|
|
5892
|
-
return { ast, comments
|
|
6242
|
+
return { ast, comments };
|
|
5893
6243
|
};
|
|
5894
6244
|
|
|
5895
6245
|
/** @type {Program | undefined} */
|
|
5896
6246
|
let ast;
|
|
5897
6247
|
/** @type {Comment[] | undefined} */
|
|
5898
6248
|
let comments;
|
|
5899
|
-
/** @type {Set<number> | undefined} */
|
|
5900
|
-
let semicolons;
|
|
5901
6249
|
let error;
|
|
5902
6250
|
let threw = false;
|
|
5903
6251
|
try {
|
|
5904
|
-
({ ast, comments
|
|
6252
|
+
({ ast, comments } = internalParse(code, parserOptions));
|
|
5905
6253
|
} catch (err) {
|
|
5906
6254
|
error = err;
|
|
5907
6255
|
threw = true;
|
|
@@ -5910,9 +6258,11 @@ class JavascriptParser extends Parser {
|
|
|
5910
6258
|
if (threw && type === "auto") {
|
|
5911
6259
|
parserOptions.sourceType = "script";
|
|
5912
6260
|
parserOptions.allowReturnOutsideFunction = true;
|
|
6261
|
+
// the retry is already a full script parse — no in-place downgrade
|
|
6262
|
+
parserOptions.moduleFallback = false;
|
|
5913
6263
|
|
|
5914
6264
|
try {
|
|
5915
|
-
({ ast, comments
|
|
6265
|
+
({ ast, comments } = internalParse(code, parserOptions));
|
|
5916
6266
|
threw = false;
|
|
5917
6267
|
} catch (_err) {
|
|
5918
6268
|
// we use the error from first parse try
|
|
@@ -5920,16 +6270,22 @@ class JavascriptParser extends Parser {
|
|
|
5920
6270
|
}
|
|
5921
6271
|
}
|
|
5922
6272
|
|
|
6273
|
+
// release per-parse state retained on the (possibly reused) options
|
|
6274
|
+
// object — the comments array retains source text slices
|
|
6275
|
+
parserOptions.lazyComments = undefined;
|
|
6276
|
+
/** @type {AcornOptions} */
|
|
6277
|
+
(parserOptions).onComment = undefined;
|
|
6278
|
+
|
|
5923
6279
|
if (threw) {
|
|
5924
6280
|
throw error;
|
|
5925
6281
|
}
|
|
5926
6282
|
|
|
5927
|
-
return /** @type {ParseResult} */ ({ ast, comments
|
|
6283
|
+
return /** @type {ParseResult} */ ({ ast, comments });
|
|
5928
6284
|
}
|
|
5929
6285
|
|
|
5930
6286
|
/**
|
|
5931
6287
|
* Returns parser.
|
|
5932
|
-
* @param {((BaseParser:
|
|
6288
|
+
* @param {((BaseParser: AcornParser) => AcornParser)[]} plugins parser plugin
|
|
5933
6289
|
* @returns {typeof JavascriptParser} parser
|
|
5934
6290
|
*/
|
|
5935
6291
|
static extend(...plugins) {
|