webpack 5.108.4 → 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 +49 -4
- 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/HotModuleReplacementPlugin.js +18 -15
- 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 -401
- 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 +219 -29
- package/lib/config/normalization.js +26 -0
- package/lib/config/target.js +9 -1
- package/lib/css/CssGenerator.js +40 -31
- package/lib/css/CssLoadingRuntimeModule.js +5 -1
- package/lib/css/CssModulesPlugin.js +13 -0
- package/lib/css/CssParser.js +594 -263
- package/lib/css/syntax.js +875 -462
- 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 +162 -71
- 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 +11 -11
- 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 +80 -17
- 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 +887 -15
- package/lib/html/HtmlModule.js +2 -2
- package/lib/html/HtmlModulesPlugin.js +610 -166
- package/lib/html/HtmlParser.js +603 -247
- package/lib/html/favicon.svg +1 -0
- package/lib/html/syntax.js +1264 -661
- 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 +701 -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 +66 -13
- package/lib/util/AsyncQueue.js +122 -72
- package/lib/util/SetHelpers.js +1 -1
- 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 +13 -12
- 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 +1213 -96
|
@@ -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() {
|
|
@@ -1607,9 +1605,9 @@ class JavascriptParser extends Parser {
|
|
|
1607
1605
|
return {
|
|
1608
1606
|
name: info,
|
|
1609
1607
|
rootInfo: info,
|
|
1610
|
-
getMembers:
|
|
1611
|
-
getMembersOptionals:
|
|
1612
|
-
getMemberRanges:
|
|
1608
|
+
getMembers: RETURN_EMPTY_ARRAY,
|
|
1609
|
+
getMembersOptionals: RETURN_EMPTY_ARRAY,
|
|
1610
|
+
getMemberRanges: RETURN_EMPTY_ARRAY
|
|
1613
1611
|
};
|
|
1614
1612
|
}
|
|
1615
1613
|
});
|
|
@@ -1622,9 +1620,9 @@ class JavascriptParser extends Parser {
|
|
|
1622
1620
|
return {
|
|
1623
1621
|
name: info,
|
|
1624
1622
|
rootInfo: info,
|
|
1625
|
-
getMembers:
|
|
1626
|
-
getMembersOptionals:
|
|
1627
|
-
getMemberRanges:
|
|
1623
|
+
getMembers: RETURN_EMPTY_ARRAY,
|
|
1624
|
+
getMembersOptionals: RETURN_EMPTY_ARRAY,
|
|
1625
|
+
getMemberRanges: RETURN_EMPTY_ARRAY
|
|
1628
1626
|
};
|
|
1629
1627
|
}
|
|
1630
1628
|
});
|
|
@@ -2073,6 +2071,15 @@ class JavascriptParser extends Parser {
|
|
|
2073
2071
|
* @returns {string | VariableInfo | undefined} identifier
|
|
2074
2072
|
*/
|
|
2075
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
|
+
}
|
|
2076
2083
|
const result = this.evaluateExpression(expr);
|
|
2077
2084
|
if (result.isIdentifier()) {
|
|
2078
2085
|
return result.identifier;
|
|
@@ -2212,49 +2219,60 @@ class JavascriptParser extends Parser {
|
|
|
2212
2219
|
preWalkStatement(statement) {
|
|
2213
2220
|
/** @type {StatementPath} */
|
|
2214
2221
|
(this.statementPath).push(statement);
|
|
2215
|
-
|
|
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) {
|
|
2216
2232
|
this.prevStatement =
|
|
2217
2233
|
/** @type {StatementPath} */
|
|
2218
2234
|
(this.statementPath).pop();
|
|
2219
2235
|
return;
|
|
2220
2236
|
}
|
|
2237
|
+
// cases ordered by measured statement frequency; the commonest statements
|
|
2238
|
+
// (expressions, returns) intentionally match nothing here
|
|
2221
2239
|
switch (statement.type) {
|
|
2222
|
-
case "
|
|
2223
|
-
this.
|
|
2224
|
-
break;
|
|
2225
|
-
case "DoWhileStatement":
|
|
2226
|
-
this.preWalkDoWhileStatement(statement);
|
|
2227
|
-
break;
|
|
2228
|
-
case "ForInStatement":
|
|
2229
|
-
this.preWalkForInStatement(statement);
|
|
2240
|
+
case "VariableDeclaration":
|
|
2241
|
+
this.preWalkVariableDeclaration(statement);
|
|
2230
2242
|
break;
|
|
2231
|
-
case "
|
|
2232
|
-
this.
|
|
2243
|
+
case "IfStatement":
|
|
2244
|
+
this.preWalkIfStatement(statement);
|
|
2233
2245
|
break;
|
|
2234
|
-
case "
|
|
2235
|
-
this.
|
|
2246
|
+
case "BlockStatement":
|
|
2247
|
+
this.preWalkBlockStatement(statement);
|
|
2236
2248
|
break;
|
|
2237
2249
|
case "FunctionDeclaration":
|
|
2238
2250
|
this.preWalkFunctionDeclaration(statement);
|
|
2239
2251
|
break;
|
|
2240
|
-
case "
|
|
2241
|
-
this.
|
|
2242
|
-
break;
|
|
2243
|
-
case "LabeledStatement":
|
|
2244
|
-
this.preWalkLabeledStatement(statement);
|
|
2245
|
-
break;
|
|
2246
|
-
case "SwitchStatement":
|
|
2247
|
-
this.preWalkSwitchStatement(statement);
|
|
2252
|
+
case "ForStatement":
|
|
2253
|
+
this.preWalkForStatement(statement);
|
|
2248
2254
|
break;
|
|
2249
2255
|
case "TryStatement":
|
|
2250
2256
|
this.preWalkTryStatement(statement);
|
|
2251
2257
|
break;
|
|
2252
|
-
case "
|
|
2253
|
-
this.
|
|
2258
|
+
case "SwitchStatement":
|
|
2259
|
+
this.preWalkSwitchStatement(statement);
|
|
2254
2260
|
break;
|
|
2255
2261
|
case "WhileStatement":
|
|
2256
2262
|
this.preWalkWhileStatement(statement);
|
|
2257
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;
|
|
2258
2276
|
case "WithStatement":
|
|
2259
2277
|
this.preWalkWithStatement(statement);
|
|
2260
2278
|
break;
|
|
@@ -2271,27 +2289,37 @@ class JavascriptParser extends Parser {
|
|
|
2271
2289
|
blockPreWalkStatement(statement) {
|
|
2272
2290
|
/** @type {StatementPath} */
|
|
2273
2291
|
(this.statementPath).push(statement);
|
|
2274
|
-
|
|
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) {
|
|
2275
2302
|
this.prevStatement =
|
|
2276
2303
|
/** @type {StatementPath} */
|
|
2277
2304
|
(this.statementPath).pop();
|
|
2278
2305
|
return;
|
|
2279
2306
|
}
|
|
2307
|
+
// cases ordered by measured statement frequency
|
|
2280
2308
|
switch (statement.type) {
|
|
2281
|
-
case "ExportDefaultDeclaration":
|
|
2282
|
-
this.blockPreWalkExportDefaultDeclaration(statement);
|
|
2283
|
-
break;
|
|
2284
|
-
case "ExportNamedDeclaration":
|
|
2285
|
-
this.blockPreWalkExportNamedDeclaration(statement);
|
|
2286
|
-
break;
|
|
2287
2309
|
case "VariableDeclaration":
|
|
2288
2310
|
this.blockPreWalkVariableDeclaration(statement);
|
|
2289
2311
|
break;
|
|
2312
|
+
case "ExpressionStatement":
|
|
2313
|
+
this.blockPreWalkExpressionStatement(statement);
|
|
2314
|
+
break;
|
|
2290
2315
|
case "ClassDeclaration":
|
|
2291
2316
|
this.blockPreWalkClassDeclaration(statement);
|
|
2292
2317
|
break;
|
|
2293
|
-
case "
|
|
2294
|
-
this.
|
|
2318
|
+
case "ExportNamedDeclaration":
|
|
2319
|
+
this.blockPreWalkExportNamedDeclaration(statement);
|
|
2320
|
+
break;
|
|
2321
|
+
case "ExportDefaultDeclaration":
|
|
2322
|
+
this.blockPreWalkExportDefaultDeclaration(statement);
|
|
2295
2323
|
}
|
|
2296
2324
|
this.prevStatement =
|
|
2297
2325
|
/** @type {StatementPath} */
|
|
@@ -2305,51 +2333,42 @@ class JavascriptParser extends Parser {
|
|
|
2305
2333
|
walkStatement(statement) {
|
|
2306
2334
|
/** @type {StatementPath} */
|
|
2307
2335
|
(this.statementPath).push(statement);
|
|
2308
|
-
|
|
2336
|
+
const { statement: statementHook } = this.hooks;
|
|
2337
|
+
if (
|
|
2338
|
+
statementHook.taps.length !== 0 &&
|
|
2339
|
+
statementHook.call(statement) !== undefined
|
|
2340
|
+
) {
|
|
2309
2341
|
this.prevStatement =
|
|
2310
2342
|
/** @type {StatementPath} */
|
|
2311
2343
|
(this.statementPath).pop();
|
|
2312
2344
|
return;
|
|
2313
2345
|
}
|
|
2346
|
+
// cases ordered by measured statement frequency; V8 compiles this to
|
|
2347
|
+
// sequential compares, so hot types must come first
|
|
2314
2348
|
switch (statement.type) {
|
|
2315
|
-
case "BlockStatement":
|
|
2316
|
-
this.walkBlockStatement(statement);
|
|
2317
|
-
break;
|
|
2318
|
-
case "ClassDeclaration":
|
|
2319
|
-
this.walkClassDeclaration(statement);
|
|
2320
|
-
break;
|
|
2321
|
-
case "DoWhileStatement":
|
|
2322
|
-
this.walkDoWhileStatement(statement);
|
|
2323
|
-
break;
|
|
2324
|
-
case "ExportDefaultDeclaration":
|
|
2325
|
-
this.walkExportDefaultDeclaration(statement);
|
|
2326
|
-
break;
|
|
2327
|
-
case "ExportNamedDeclaration":
|
|
2328
|
-
this.walkExportNamedDeclaration(statement);
|
|
2329
|
-
break;
|
|
2330
2349
|
case "ExpressionStatement":
|
|
2331
2350
|
this.walkExpressionStatement(statement);
|
|
2332
2351
|
break;
|
|
2333
|
-
case "
|
|
2334
|
-
this.
|
|
2352
|
+
case "VariableDeclaration":
|
|
2353
|
+
this.walkVariableDeclaration(statement);
|
|
2335
2354
|
break;
|
|
2336
|
-
case "
|
|
2337
|
-
this.
|
|
2355
|
+
case "ReturnStatement":
|
|
2356
|
+
this.walkReturnStatement(statement);
|
|
2338
2357
|
break;
|
|
2339
|
-
case "
|
|
2340
|
-
this.
|
|
2358
|
+
case "IfStatement":
|
|
2359
|
+
this.walkIfStatement(statement);
|
|
2360
|
+
break;
|
|
2361
|
+
case "BlockStatement":
|
|
2362
|
+
this.walkBlockStatement(statement);
|
|
2341
2363
|
break;
|
|
2342
2364
|
case "FunctionDeclaration":
|
|
2343
2365
|
this.walkFunctionDeclaration(statement);
|
|
2344
2366
|
break;
|
|
2345
|
-
case "
|
|
2346
|
-
this.
|
|
2347
|
-
break;
|
|
2348
|
-
case "LabeledStatement":
|
|
2349
|
-
this.walkLabeledStatement(statement);
|
|
2367
|
+
case "ForStatement":
|
|
2368
|
+
this.walkForStatement(statement);
|
|
2350
2369
|
break;
|
|
2351
|
-
case "
|
|
2352
|
-
this.
|
|
2370
|
+
case "TryStatement":
|
|
2371
|
+
this.walkTryStatement(statement);
|
|
2353
2372
|
break;
|
|
2354
2373
|
case "SwitchStatement":
|
|
2355
2374
|
this.walkSwitchStatement(statement);
|
|
@@ -2357,15 +2376,30 @@ class JavascriptParser extends Parser {
|
|
|
2357
2376
|
case "ThrowStatement":
|
|
2358
2377
|
this.walkThrowStatement(statement);
|
|
2359
2378
|
break;
|
|
2360
|
-
case "TryStatement":
|
|
2361
|
-
this.walkTryStatement(statement);
|
|
2362
|
-
break;
|
|
2363
|
-
case "VariableDeclaration":
|
|
2364
|
-
this.walkVariableDeclaration(statement);
|
|
2365
|
-
break;
|
|
2366
2379
|
case "WhileStatement":
|
|
2367
2380
|
this.walkWhileStatement(statement);
|
|
2368
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;
|
|
2369
2403
|
case "WithStatement":
|
|
2370
2404
|
this.walkWithStatement(statement);
|
|
2371
2405
|
break;
|
|
@@ -2521,6 +2555,12 @@ class JavascriptParser extends Parser {
|
|
|
2521
2555
|
* @param {WithStatement} statement with statement
|
|
2522
2556
|
*/
|
|
2523
2557
|
walkWithStatement(statement) {
|
|
2558
|
+
if (this._strictInModuleOutput) {
|
|
2559
|
+
this._reportStrictModeViolation(
|
|
2560
|
+
"`with` statements are not allowed",
|
|
2561
|
+
statement
|
|
2562
|
+
);
|
|
2563
|
+
}
|
|
2524
2564
|
this.inBlockScope(() => {
|
|
2525
2565
|
this.walkExpression(statement.object);
|
|
2526
2566
|
this.walkNestedStatement(statement.body);
|
|
@@ -2809,6 +2849,9 @@ class JavascriptParser extends Parser {
|
|
|
2809
2849
|
walkFunctionDeclaration(statement) {
|
|
2810
2850
|
const wasTopLevel = this.scope.topLevelScope;
|
|
2811
2851
|
this.scope.topLevelScope = false;
|
|
2852
|
+
if (this._strictInModuleOutput) {
|
|
2853
|
+
this._checkStrictModeParams(statement.params);
|
|
2854
|
+
}
|
|
2812
2855
|
this.inFunctionScope(true, statement.params, () => {
|
|
2813
2856
|
for (const param of statement.params) {
|
|
2814
2857
|
this.walkPattern(param);
|
|
@@ -3253,7 +3296,6 @@ class JavascriptParser extends Parser {
|
|
|
3253
3296
|
props.add({
|
|
3254
3297
|
id: key.name,
|
|
3255
3298
|
range: /** @type {Range} */ (key.range),
|
|
3256
|
-
loc: /** @type {SourceLocation} */ (key.loc),
|
|
3257
3299
|
pattern,
|
|
3258
3300
|
shorthand: this.scope.inShorthand
|
|
3259
3301
|
});
|
|
@@ -3270,7 +3312,6 @@ class JavascriptParser extends Parser {
|
|
|
3270
3312
|
props.add({
|
|
3271
3313
|
id: str,
|
|
3272
3314
|
range: /** @type {Range} */ (key.range),
|
|
3273
|
-
loc: /** @type {SourceLocation} */ (key.loc),
|
|
3274
3315
|
pattern,
|
|
3275
3316
|
shorthand: this.scope.inShorthand
|
|
3276
3317
|
});
|
|
@@ -3307,7 +3348,6 @@ class JavascriptParser extends Parser {
|
|
|
3307
3348
|
props.add({
|
|
3308
3349
|
id: `${i}`,
|
|
3309
3350
|
range: /** @type {Range} */ (element.range),
|
|
3310
|
-
loc: /** @type {SourceLocation} */ (element.loc),
|
|
3311
3351
|
pattern,
|
|
3312
3352
|
shorthand: false
|
|
3313
3353
|
});
|
|
@@ -3467,6 +3507,12 @@ class JavascriptParser extends Parser {
|
|
|
3467
3507
|
*/
|
|
3468
3508
|
walkPattern(pattern) {
|
|
3469
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;
|
|
3470
3516
|
case "ArrayPattern":
|
|
3471
3517
|
this.walkArrayPattern(pattern);
|
|
3472
3518
|
break;
|
|
@@ -3476,9 +3522,6 @@ class JavascriptParser extends Parser {
|
|
|
3476
3522
|
case "MemberExpression":
|
|
3477
3523
|
this.walkMemberExpression(pattern);
|
|
3478
3524
|
break;
|
|
3479
|
-
case "ObjectPattern":
|
|
3480
|
-
this.walkObjectPattern(pattern);
|
|
3481
|
-
break;
|
|
3482
3525
|
case "RestElement":
|
|
3483
3526
|
this.walkRestElement(pattern);
|
|
3484
3527
|
break;
|
|
@@ -3548,78 +3591,86 @@ class JavascriptParser extends Parser {
|
|
|
3548
3591
|
* @param {Expression | SpreadElement | PrivateIdentifier | Super} expression expression
|
|
3549
3592
|
*/
|
|
3550
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
|
|
3551
3597
|
switch (expression.type) {
|
|
3552
|
-
case "
|
|
3553
|
-
this.
|
|
3598
|
+
case "Identifier":
|
|
3599
|
+
this.walkIdentifier(expression);
|
|
3554
3600
|
break;
|
|
3555
|
-
case "
|
|
3556
|
-
this.
|
|
3601
|
+
case "MemberExpression":
|
|
3602
|
+
this.walkMemberExpression(expression);
|
|
3557
3603
|
break;
|
|
3558
|
-
case "
|
|
3559
|
-
this.
|
|
3604
|
+
case "Literal":
|
|
3605
|
+
if (this._strictInModuleOutput) {
|
|
3606
|
+
this._checkStrictModeLiteral(expression);
|
|
3607
|
+
}
|
|
3560
3608
|
break;
|
|
3561
|
-
case "
|
|
3562
|
-
this.
|
|
3609
|
+
case "CallExpression":
|
|
3610
|
+
this.walkCallExpression(expression);
|
|
3563
3611
|
break;
|
|
3564
3612
|
case "BinaryExpression":
|
|
3565
3613
|
this.walkBinaryExpression(expression);
|
|
3566
3614
|
break;
|
|
3567
|
-
case "
|
|
3568
|
-
this.
|
|
3569
|
-
break;
|
|
3570
|
-
case "ChainExpression":
|
|
3571
|
-
this.walkChainExpression(expression);
|
|
3615
|
+
case "AssignmentExpression":
|
|
3616
|
+
this.walkAssignmentExpression(expression);
|
|
3572
3617
|
break;
|
|
3573
|
-
case "
|
|
3574
|
-
this.
|
|
3618
|
+
case "UnaryExpression":
|
|
3619
|
+
this.walkUnaryExpression(expression);
|
|
3575
3620
|
break;
|
|
3576
|
-
case "
|
|
3577
|
-
this.
|
|
3621
|
+
case "LogicalExpression":
|
|
3622
|
+
this.walkLogicalExpression(expression);
|
|
3578
3623
|
break;
|
|
3579
|
-
case "
|
|
3580
|
-
this.
|
|
3624
|
+
case "ArrowFunctionExpression":
|
|
3625
|
+
this.walkArrowFunctionExpression(expression);
|
|
3581
3626
|
break;
|
|
3582
|
-
case "
|
|
3583
|
-
this.
|
|
3627
|
+
case "ThisExpression":
|
|
3628
|
+
this.walkThisExpression(expression);
|
|
3584
3629
|
break;
|
|
3585
|
-
case "
|
|
3586
|
-
this.
|
|
3630
|
+
case "ConditionalExpression":
|
|
3631
|
+
this.walkConditionalExpression(expression);
|
|
3587
3632
|
break;
|
|
3588
|
-
case "
|
|
3589
|
-
this.
|
|
3633
|
+
case "ArrayExpression":
|
|
3634
|
+
this.walkArrayExpression(expression);
|
|
3590
3635
|
break;
|
|
3591
|
-
case "
|
|
3592
|
-
this.
|
|
3636
|
+
case "ObjectExpression":
|
|
3637
|
+
this.walkObjectExpression(expression);
|
|
3593
3638
|
break;
|
|
3594
|
-
case "
|
|
3595
|
-
this.
|
|
3639
|
+
case "FunctionExpression":
|
|
3640
|
+
this.walkFunctionExpression(expression);
|
|
3596
3641
|
break;
|
|
3597
3642
|
case "NewExpression":
|
|
3598
3643
|
this.walkNewExpression(expression);
|
|
3599
3644
|
break;
|
|
3600
|
-
case "
|
|
3601
|
-
this.
|
|
3645
|
+
case "TemplateLiteral":
|
|
3646
|
+
this.walkTemplateLiteral(expression);
|
|
3647
|
+
break;
|
|
3648
|
+
case "SpreadElement":
|
|
3649
|
+
this.walkSpreadElement(expression);
|
|
3602
3650
|
break;
|
|
3603
3651
|
case "SequenceExpression":
|
|
3604
3652
|
this.walkSequenceExpression(expression);
|
|
3605
3653
|
break;
|
|
3606
|
-
case "
|
|
3607
|
-
this.
|
|
3654
|
+
case "UpdateExpression":
|
|
3655
|
+
this.walkUpdateExpression(expression);
|
|
3608
3656
|
break;
|
|
3609
|
-
case "
|
|
3610
|
-
this.
|
|
3657
|
+
case "AwaitExpression":
|
|
3658
|
+
this.walkAwaitExpression(expression);
|
|
3611
3659
|
break;
|
|
3612
|
-
case "
|
|
3613
|
-
this.
|
|
3660
|
+
case "ChainExpression":
|
|
3661
|
+
this.walkChainExpression(expression);
|
|
3614
3662
|
break;
|
|
3615
|
-
case "
|
|
3616
|
-
this.
|
|
3663
|
+
case "ClassExpression":
|
|
3664
|
+
this.walkClassExpression(expression);
|
|
3617
3665
|
break;
|
|
3618
|
-
case "
|
|
3619
|
-
this.
|
|
3666
|
+
case "ImportExpression":
|
|
3667
|
+
this.walkImportExpression(expression);
|
|
3620
3668
|
break;
|
|
3621
|
-
case "
|
|
3622
|
-
this.
|
|
3669
|
+
case "MetaProperty":
|
|
3670
|
+
this.walkMetaProperty(expression);
|
|
3671
|
+
break;
|
|
3672
|
+
case "TaggedTemplateExpression":
|
|
3673
|
+
this.walkTaggedTemplateExpression(expression);
|
|
3623
3674
|
break;
|
|
3624
3675
|
case "YieldExpression":
|
|
3625
3676
|
this.walkYieldExpression(expression);
|
|
@@ -3627,6 +3678,35 @@ class JavascriptParser extends Parser {
|
|
|
3627
3678
|
}
|
|
3628
3679
|
}
|
|
3629
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
|
+
|
|
3630
3710
|
/**
|
|
3631
3711
|
* Walk await expression.
|
|
3632
3712
|
* @param {AwaitExpression} expression await expression
|
|
@@ -3710,6 +3790,9 @@ class JavascriptParser extends Parser {
|
|
|
3710
3790
|
? [...expression.params, expression.id]
|
|
3711
3791
|
: expression.params;
|
|
3712
3792
|
|
|
3793
|
+
if (this._strictInModuleOutput) {
|
|
3794
|
+
this._checkStrictModeParams(expression.params);
|
|
3795
|
+
}
|
|
3713
3796
|
this.inFunctionScope(true, scopeParams, () => {
|
|
3714
3797
|
for (const param of expression.params) {
|
|
3715
3798
|
this.walkPattern(param);
|
|
@@ -3733,6 +3816,9 @@ class JavascriptParser extends Parser {
|
|
|
3733
3816
|
walkArrowFunctionExpression(expression) {
|
|
3734
3817
|
const wasTopLevel = this.scope.topLevelScope;
|
|
3735
3818
|
this.scope.topLevelScope = wasTopLevel ? "arrow" : false;
|
|
3819
|
+
if (this._strictInModuleOutput) {
|
|
3820
|
+
this._checkStrictModeParams(expression.params);
|
|
3821
|
+
}
|
|
3736
3822
|
this.inFunctionScope(false, expression.params, () => {
|
|
3737
3823
|
for (const param of expression.params) {
|
|
3738
3824
|
this.walkPattern(param);
|
|
@@ -3794,9 +3880,84 @@ class JavascriptParser extends Parser {
|
|
|
3794
3880
|
* @param {UpdateExpression} expression the update expression
|
|
3795
3881
|
*/
|
|
3796
3882
|
walkUpdateExpression(expression) {
|
|
3883
|
+
if (
|
|
3884
|
+
this._strictInModuleOutput &&
|
|
3885
|
+
expression.argument.type === "Identifier"
|
|
3886
|
+
) {
|
|
3887
|
+
this._checkStrictModeAssignTarget(expression.argument.name, expression);
|
|
3888
|
+
}
|
|
3797
3889
|
this.walkExpression(expression.argument);
|
|
3798
3890
|
}
|
|
3799
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
|
+
|
|
3800
3961
|
/**
|
|
3801
3962
|
* Walk unary expression.
|
|
3802
3963
|
* @param {UnaryExpression} expression the unary expression
|
|
@@ -3817,10 +3978,39 @@ class JavascriptParser extends Parser {
|
|
|
3817
3978
|
);
|
|
3818
3979
|
if (result === true) return;
|
|
3819
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
|
+
);
|
|
3820
3990
|
}
|
|
3821
3991
|
this.walkExpression(expression.argument);
|
|
3822
3992
|
}
|
|
3823
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
|
+
|
|
3824
4014
|
/**
|
|
3825
4015
|
* Walk left right expression.
|
|
3826
4016
|
* @param {LogicalExpression | BinaryExpression} expression the expression
|
|
@@ -3859,6 +4049,9 @@ class JavascriptParser extends Parser {
|
|
|
3859
4049
|
*/
|
|
3860
4050
|
walkAssignmentExpression(expression) {
|
|
3861
4051
|
if (expression.left.type === "Identifier") {
|
|
4052
|
+
if (this._strictInModuleOutput) {
|
|
4053
|
+
this._checkStrictModeAssignTarget(expression.left.name, expression);
|
|
4054
|
+
}
|
|
3862
4055
|
const renameIdentifier = this.getRenameIdentifier(expression.right);
|
|
3863
4056
|
if (
|
|
3864
4057
|
renameIdentifier &&
|
|
@@ -3960,38 +4153,6 @@ class JavascriptParser extends Parser {
|
|
|
3960
4153
|
* @param {NewExpression} expression new expression
|
|
3961
4154
|
*/
|
|
3962
4155
|
walkNewExpression(expression) {
|
|
3963
|
-
// TODO acorn-import-phases bug: it omits acorn's `!forNew` guard, so
|
|
3964
|
-
// `import.defer(...)`/`import.source(...)` are wrongly accepted as `new`
|
|
3965
|
-
// operands; drop once fixed. Parenthesized forms stay valid (check `(`).
|
|
3966
|
-
if (typeof this.state.source === "string") {
|
|
3967
|
-
let base = expression.callee;
|
|
3968
|
-
while (
|
|
3969
|
-
base.type === "MemberExpression" ||
|
|
3970
|
-
base.type === "CallExpression"
|
|
3971
|
-
) {
|
|
3972
|
-
base = base.type === "MemberExpression" ? base.object : base.callee;
|
|
3973
|
-
}
|
|
3974
|
-
if (base.type === "ImportExpression") {
|
|
3975
|
-
const newStart = /** @type {Range} */ (expression.range)[0];
|
|
3976
|
-
const importStart = /** @type {Range} */ (base.range)[0];
|
|
3977
|
-
const between = this.state.source
|
|
3978
|
-
.slice(newStart, importStart)
|
|
3979
|
-
.replace(/\/\*[\s\S]*?\*\//g, "")
|
|
3980
|
-
.replace(/\/\/[^\n]*/g, "");
|
|
3981
|
-
if (!between.includes("(")) {
|
|
3982
|
-
const err =
|
|
3983
|
-
/** @type {SyntaxError & { loc?: { line: number, column: number } }} */
|
|
3984
|
-
(new SyntaxError("import call cannot be the target of `new`"));
|
|
3985
|
-
if (expression.loc) {
|
|
3986
|
-
err.loc = {
|
|
3987
|
-
line: expression.loc.start.line,
|
|
3988
|
-
column: expression.loc.start.column
|
|
3989
|
-
};
|
|
3990
|
-
}
|
|
3991
|
-
throw err;
|
|
3992
|
-
}
|
|
3993
|
-
}
|
|
3994
|
-
}
|
|
3995
4156
|
const result = this.callHooksForExpression(
|
|
3996
4157
|
this.hooks.new,
|
|
3997
4158
|
expression.callee,
|
|
@@ -4233,19 +4394,33 @@ class JavascriptParser extends Parser {
|
|
|
4233
4394
|
if (result === true) return;
|
|
4234
4395
|
}
|
|
4235
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
|
+
}
|
|
4236
4410
|
const callee = this.evaluateExpression(expression.callee);
|
|
4237
4411
|
if (callee.isIdentifier()) {
|
|
4412
|
+
const members =
|
|
4413
|
+
/** @type {NonNullable<BasicEvaluatedExpression["getMembers"]>} */
|
|
4414
|
+
(callee.getMembers)();
|
|
4238
4415
|
const result1 = this.callHooksForInfo(
|
|
4239
4416
|
this.hooks.callMemberChain,
|
|
4240
4417
|
/** @type {NonNullable<BasicEvaluatedExpression["rootInfo"]>} */
|
|
4241
4418
|
(callee.rootInfo),
|
|
4242
4419
|
expression,
|
|
4243
|
-
|
|
4244
|
-
(callee.getMembers)(),
|
|
4420
|
+
members,
|
|
4245
4421
|
callee.getMembersOptionals
|
|
4246
4422
|
? callee.getMembersOptionals()
|
|
4247
|
-
:
|
|
4248
|
-
(callee.getMembers)().map(() => false),
|
|
4423
|
+
: members.map(RETURN_FALSE),
|
|
4249
4424
|
callee.getMemberRanges ? callee.getMemberRanges() : []
|
|
4250
4425
|
);
|
|
4251
4426
|
if (result1 === true) return;
|
|
@@ -4749,22 +4924,14 @@ class JavascriptParser extends Parser {
|
|
|
4749
4924
|
*/
|
|
4750
4925
|
enterPattern(pattern, onIdent) {
|
|
4751
4926
|
if (!pattern) return;
|
|
4927
|
+
// plain identifiers dominate bindings, so match them first
|
|
4752
4928
|
switch (pattern.type) {
|
|
4753
|
-
case "ArrayPattern":
|
|
4754
|
-
this.enterArrayPattern(pattern, onIdent);
|
|
4755
|
-
break;
|
|
4756
|
-
case "AssignmentPattern":
|
|
4757
|
-
this.enterAssignmentPattern(pattern, onIdent);
|
|
4758
|
-
break;
|
|
4759
4929
|
case "Identifier":
|
|
4760
4930
|
this.enterIdentifier(pattern, onIdent);
|
|
4761
4931
|
break;
|
|
4762
4932
|
case "ObjectPattern":
|
|
4763
4933
|
this.enterObjectPattern(pattern, onIdent);
|
|
4764
4934
|
break;
|
|
4765
|
-
case "RestElement":
|
|
4766
|
-
this.enterRestElement(pattern, onIdent);
|
|
4767
|
-
break;
|
|
4768
4935
|
case "Property":
|
|
4769
4936
|
if (pattern.shorthand && pattern.value.type === "Identifier") {
|
|
4770
4937
|
this.scope.inShorthand = pattern.value.name;
|
|
@@ -4774,6 +4941,15 @@ class JavascriptParser extends Parser {
|
|
|
4774
4941
|
this.enterPattern(/** @type {Pattern} */ (pattern.value), onIdent);
|
|
4775
4942
|
}
|
|
4776
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;
|
|
4777
4953
|
}
|
|
4778
4954
|
}
|
|
4779
4955
|
|
|
@@ -4861,9 +5037,9 @@ class JavascriptParser extends Parser {
|
|
|
4861
5037
|
console.warn(err);
|
|
4862
5038
|
// ignore error
|
|
4863
5039
|
}
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
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);
|
|
4867
5043
|
}
|
|
4868
5044
|
|
|
4869
5045
|
/**
|
|
@@ -5002,30 +5178,21 @@ class JavascriptParser extends Parser {
|
|
|
5002
5178
|
let ast;
|
|
5003
5179
|
/** @type {Comment[]} */
|
|
5004
5180
|
let comments;
|
|
5005
|
-
/** @type {Set<number>} */
|
|
5006
|
-
let semicolons;
|
|
5007
5181
|
|
|
5008
5182
|
if (typeof source === "object") {
|
|
5009
|
-
semicolons = new Set();
|
|
5010
|
-
|
|
5011
5183
|
ast = /** @type {Program} */ (source);
|
|
5012
5184
|
comments = source.comments;
|
|
5013
|
-
if (source.semicolons) {
|
|
5014
|
-
// Forward semicolon information from the preparsed AST if present
|
|
5015
|
-
// This ensures the output is consistent with that of a fresh AST
|
|
5016
|
-
for (const pos of source.semicolons) {
|
|
5017
|
-
semicolons.add(pos);
|
|
5018
|
-
}
|
|
5019
|
-
}
|
|
5020
5185
|
} else {
|
|
5021
|
-
({ ast, comments
|
|
5186
|
+
({ ast, comments } = JavascriptParser._parse(
|
|
5022
5187
|
source,
|
|
5023
5188
|
{
|
|
5024
5189
|
sourceType: this.sourceType,
|
|
5025
|
-
locations
|
|
5190
|
+
// line/column locations are derived from node offsets via
|
|
5191
|
+
// getLocation — parsers never need to track them
|
|
5192
|
+
locations: false,
|
|
5026
5193
|
ranges: true,
|
|
5027
5194
|
comments: true,
|
|
5028
|
-
|
|
5195
|
+
importPhases: this.options.importPhases === true
|
|
5029
5196
|
},
|
|
5030
5197
|
this.options.parse
|
|
5031
5198
|
));
|
|
@@ -5037,6 +5204,18 @@ class JavascriptParser extends Parser {
|
|
|
5037
5204
|
const oldSemicolons = this.semicolons;
|
|
5038
5205
|
const oldStatementPath = this.statementPath;
|
|
5039
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;
|
|
5040
5219
|
this.scope = {
|
|
5041
5220
|
topLevelScope: true,
|
|
5042
5221
|
inTry: false,
|
|
@@ -5049,12 +5228,32 @@ class JavascriptParser extends Parser {
|
|
|
5049
5228
|
};
|
|
5050
5229
|
this.state = state;
|
|
5051
5230
|
this.comments = comments;
|
|
5052
|
-
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);
|
|
5053
5240
|
this.statementPath = [];
|
|
5054
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();
|
|
5055
5249
|
if (this.hooks.program.call(ast, comments) === undefined) {
|
|
5056
5250
|
this.destructuringAssignmentProperties = new WeakMap();
|
|
5057
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
|
+
}
|
|
5058
5257
|
this.modulePreWalkStatements(ast.body);
|
|
5059
5258
|
this.prevStatement = undefined;
|
|
5060
5259
|
this.preWalkStatements(ast.body);
|
|
@@ -5071,6 +5270,10 @@ class JavascriptParser extends Parser {
|
|
|
5071
5270
|
this.semicolons = oldSemicolons;
|
|
5072
5271
|
this.statementPath = oldStatementPath;
|
|
5073
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;
|
|
5074
5277
|
return state;
|
|
5075
5278
|
}
|
|
5076
5279
|
|
|
@@ -5080,11 +5283,41 @@ class JavascriptParser extends Parser {
|
|
|
5080
5283
|
* @returns {BasicEvaluatedExpression} evaluation result
|
|
5081
5284
|
*/
|
|
5082
5285
|
evaluate(source) {
|
|
5083
|
-
const
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
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
|
+
}
|
|
5088
5321
|
if (ast.body.length !== 1 || ast.body[0].type !== "ExpressionStatement") {
|
|
5089
5322
|
throw new Error("evaluate: Source is not a expression");
|
|
5090
5323
|
}
|
|
@@ -5343,34 +5576,127 @@ class JavascriptParser extends Parser {
|
|
|
5343
5576
|
return !evaluated.couldHaveSideEffects();
|
|
5344
5577
|
}
|
|
5345
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
|
+
|
|
5346
5615
|
/**
|
|
5347
5616
|
* Returns comments in the range.
|
|
5348
5617
|
* @param {Range} range range
|
|
5349
5618
|
* @returns {Comment[]} comments in the range
|
|
5350
5619
|
*/
|
|
5351
5620
|
getComments(range) {
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
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;
|
|
5371
5677
|
}
|
|
5678
|
+
return -1;
|
|
5679
|
+
}
|
|
5372
5680
|
|
|
5373
|
-
|
|
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; /* ; */
|
|
5374
5700
|
}
|
|
5375
5701
|
|
|
5376
5702
|
/**
|
|
@@ -5390,17 +5716,14 @@ class JavascriptParser extends Parser {
|
|
|
5390
5716
|
|
|
5391
5717
|
return (
|
|
5392
5718
|
// Either asking directly for the end position of the current statement
|
|
5393
|
-
(range[1] === pos &&
|
|
5394
|
-
/** @type {Set<number>} */ (this.semicolons).has(pos)) ||
|
|
5719
|
+
(range[1] === pos && this._isAsiPosition(pos)) ||
|
|
5395
5720
|
// Or asking for the start position of the current statement,
|
|
5396
5721
|
// here we have to check multiple things
|
|
5397
5722
|
(range[0] === pos &&
|
|
5398
5723
|
// is there a previous statement which might be relevant?
|
|
5399
5724
|
this.prevStatement !== undefined &&
|
|
5400
5725
|
// is the end position of the previous statement an ASI position?
|
|
5401
|
-
/** @type {
|
|
5402
|
-
/** @type {Range} */ (this.prevStatement.range)[1]
|
|
5403
|
-
))
|
|
5726
|
+
this._isAsiPosition(/** @type {Range} */ (this.prevStatement.range)[1]))
|
|
5404
5727
|
);
|
|
5405
5728
|
}
|
|
5406
5729
|
|
|
@@ -5410,7 +5733,7 @@ class JavascriptParser extends Parser {
|
|
|
5410
5733
|
* @returns {void}
|
|
5411
5734
|
*/
|
|
5412
5735
|
setAsiPosition(pos) {
|
|
5413
|
-
|
|
5736
|
+
(this.semicolons || (this.semicolons = new Map())).set(pos, true);
|
|
5414
5737
|
}
|
|
5415
5738
|
|
|
5416
5739
|
/**
|
|
@@ -5419,7 +5742,7 @@ class JavascriptParser extends Parser {
|
|
|
5419
5742
|
* @returns {void}
|
|
5420
5743
|
*/
|
|
5421
5744
|
unsetAsiPosition(pos) {
|
|
5422
|
-
|
|
5745
|
+
(this.semicolons || (this.semicolons = new Map())).set(pos, false);
|
|
5423
5746
|
}
|
|
5424
5747
|
|
|
5425
5748
|
/**
|
|
@@ -5534,6 +5857,22 @@ class JavascriptParser extends Parser {
|
|
|
5534
5857
|
return true;
|
|
5535
5858
|
}
|
|
5536
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
|
+
|
|
5537
5876
|
/**
|
|
5538
5877
|
* Gets variable info.
|
|
5539
5878
|
* @param {string} name variable name
|
|
@@ -5593,42 +5932,13 @@ class JavascriptParser extends Parser {
|
|
|
5593
5932
|
* @returns {{ options: Record<string, EXPECTED_ANY> | null, errors: (Error & { comment: Comment })[] | null }} result
|
|
5594
5933
|
*/
|
|
5595
5934
|
parseCommentOptions(range) {
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
const errors = [];
|
|
5604
|
-
for (const comment of comments) {
|
|
5605
|
-
const { value } = comment;
|
|
5606
|
-
if (value && webpackCommentRegExp.test(value)) {
|
|
5607
|
-
// try compile only if webpack options comment is present
|
|
5608
|
-
try {
|
|
5609
|
-
for (let [key, val] of Object.entries(
|
|
5610
|
-
vm.runInContext(
|
|
5611
|
-
`(function(){return {${value}};})()`,
|
|
5612
|
-
this.magicCommentContext
|
|
5613
|
-
)
|
|
5614
|
-
)) {
|
|
5615
|
-
if (typeof val === "object" && val !== null) {
|
|
5616
|
-
val =
|
|
5617
|
-
val.constructor.name === "RegExp"
|
|
5618
|
-
? new RegExp(val)
|
|
5619
|
-
: JSON.parse(JSON.stringify(val));
|
|
5620
|
-
}
|
|
5621
|
-
options[key] = val;
|
|
5622
|
-
}
|
|
5623
|
-
} catch (err) {
|
|
5624
|
-
const newErr = new Error(String(/** @type {Error} */ (err).message));
|
|
5625
|
-
newErr.stack = String(/** @type {Error} */ (err).stack);
|
|
5626
|
-
Object.assign(newErr, { comment });
|
|
5627
|
-
errors.push(/** @type {(Error & { comment: Comment })} */ (newErr));
|
|
5628
|
-
}
|
|
5629
|
-
}
|
|
5630
|
-
}
|
|
5631
|
-
return { options, errors };
|
|
5935
|
+
return parseCommentOptionsInRange(
|
|
5936
|
+
/** @type {(Comment & { range: [number, number], value: string })[]} */ (
|
|
5937
|
+
this.comments
|
|
5938
|
+
),
|
|
5939
|
+
range,
|
|
5940
|
+
this.magicCommentContext
|
|
5941
|
+
);
|
|
5632
5942
|
}
|
|
5633
5943
|
|
|
5634
5944
|
/**
|
|
@@ -5862,12 +6172,30 @@ class JavascriptParser extends Parser {
|
|
|
5862
6172
|
static _parse(code, options, customParse) {
|
|
5863
6173
|
const type = options ? options.sourceType : "module";
|
|
5864
6174
|
/** @type {ParseOptions} */
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
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;
|
|
5871
6199
|
/**
|
|
5872
6200
|
* Returns parse result.
|
|
5873
6201
|
* @param {string} code source code
|
|
@@ -5882,36 +6210,46 @@ class JavascriptParser extends Parser {
|
|
|
5882
6210
|
/** @type {Comment[]} */
|
|
5883
6211
|
const comments = [];
|
|
5884
6212
|
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
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;
|
|
5888
6223
|
}
|
|
5889
6224
|
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
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
|
+
}
|
|
5896
6236
|
}
|
|
5897
6237
|
|
|
5898
6238
|
const ast =
|
|
5899
6239
|
/** @type {Program} */
|
|
5900
6240
|
(parser.parse(code, /** @type {AcornOptions} */ (options)));
|
|
5901
6241
|
|
|
5902
|
-
return { ast, comments
|
|
6242
|
+
return { ast, comments };
|
|
5903
6243
|
};
|
|
5904
6244
|
|
|
5905
6245
|
/** @type {Program | undefined} */
|
|
5906
6246
|
let ast;
|
|
5907
6247
|
/** @type {Comment[] | undefined} */
|
|
5908
6248
|
let comments;
|
|
5909
|
-
/** @type {Set<number> | undefined} */
|
|
5910
|
-
let semicolons;
|
|
5911
6249
|
let error;
|
|
5912
6250
|
let threw = false;
|
|
5913
6251
|
try {
|
|
5914
|
-
({ ast, comments
|
|
6252
|
+
({ ast, comments } = internalParse(code, parserOptions));
|
|
5915
6253
|
} catch (err) {
|
|
5916
6254
|
error = err;
|
|
5917
6255
|
threw = true;
|
|
@@ -5920,9 +6258,11 @@ class JavascriptParser extends Parser {
|
|
|
5920
6258
|
if (threw && type === "auto") {
|
|
5921
6259
|
parserOptions.sourceType = "script";
|
|
5922
6260
|
parserOptions.allowReturnOutsideFunction = true;
|
|
6261
|
+
// the retry is already a full script parse — no in-place downgrade
|
|
6262
|
+
parserOptions.moduleFallback = false;
|
|
5923
6263
|
|
|
5924
6264
|
try {
|
|
5925
|
-
({ ast, comments
|
|
6265
|
+
({ ast, comments } = internalParse(code, parserOptions));
|
|
5926
6266
|
threw = false;
|
|
5927
6267
|
} catch (_err) {
|
|
5928
6268
|
// we use the error from first parse try
|
|
@@ -5930,16 +6270,22 @@ class JavascriptParser extends Parser {
|
|
|
5930
6270
|
}
|
|
5931
6271
|
}
|
|
5932
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
|
+
|
|
5933
6279
|
if (threw) {
|
|
5934
6280
|
throw error;
|
|
5935
6281
|
}
|
|
5936
6282
|
|
|
5937
|
-
return /** @type {ParseResult} */ ({ ast, comments
|
|
6283
|
+
return /** @type {ParseResult} */ ({ ast, comments });
|
|
5938
6284
|
}
|
|
5939
6285
|
|
|
5940
6286
|
/**
|
|
5941
6287
|
* Returns parser.
|
|
5942
|
-
* @param {((BaseParser:
|
|
6288
|
+
* @param {((BaseParser: AcornParser) => AcornParser)[]} plugins parser plugin
|
|
5943
6289
|
* @returns {typeof JavascriptParser} parser
|
|
5944
6290
|
*/
|
|
5945
6291
|
static extend(...plugins) {
|