webpack 5.110.2 → 5.111.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/README.md +5 -2
- package/lib/APIPlugin.js +23 -7
- package/lib/AutomaticPrefetchPlugin.js +1 -1
- package/lib/Cache.js +8 -3
- package/lib/CacheFacade.js +1 -1
- package/lib/ChunkGraph.js +20 -18
- package/lib/CircularModulesPlugin.js +157 -55
- package/lib/CleanPlugin.js +2 -2
- package/lib/Compilation.js +321 -303
- package/lib/Compiler.js +209 -46
- package/lib/ConcatenationScope.js +25 -35
- package/lib/ContextModule.js +17 -81
- package/lib/ContextModuleFactory.js +1 -1
- package/lib/CopyPlugin.js +1054 -0
- package/lib/DefinePlugin.js +24 -8
- package/lib/DotenvPlugin.js +41 -13
- package/lib/ExternalModule.js +41 -14
- package/lib/FileSystemInfo.js +17 -14
- package/lib/FlagDependencyExportsPlugin.js +45 -21
- package/lib/FlagDependencyUsagePlugin.js +8 -2
- package/lib/HotModuleReplacementPlugin.js +53 -7
- package/lib/JavascriptMetaInfoPlugin.js +5 -3
- package/lib/MainTemplate.js +5 -1
- package/lib/Module.js +16 -7
- package/lib/MultiCompiler.js +1 -1
- package/lib/MultiWatching.js +1 -1
- package/lib/NormalModule.js +58 -32
- package/lib/NormalModuleFactory.js +1 -1
- package/lib/RuntimeGlobals.js +21 -7
- package/lib/RuntimeModule.js +28 -12
- package/lib/RuntimePlugin.js +33 -3
- package/lib/RuntimeTemplate.js +794 -477
- package/lib/SourceMapDevToolPlugin.js +1 -1
- package/lib/Watching.js +9 -0
- package/lib/WebpackOptionsApply.js +84 -91
- package/lib/asset/AssetGenerator.js +25 -8
- package/lib/asset/AssetModule.js +3 -0
- package/lib/asset/WebManifestParser.js +7 -5
- package/lib/async-modules/AsyncModuleHelpers.js +10 -4
- package/lib/cache/AddBuildDependenciesPlugin.js +33 -4
- package/lib/cache/IdleFileCachePlugin.js +2 -2
- package/lib/cache/PackFileCacheStrategy.js +14 -1
- package/lib/config/browserslistTargetHandler.js +19 -0
- package/lib/config/defaults.js +110 -64
- package/lib/config/normalization.js +100 -20
- package/lib/config/target.js +10 -0
- package/lib/container/ContainerReferencePlugin.js +6 -0
- package/lib/container/RemoteRuntimeModule.js +9 -0
- package/lib/container/declaredRemotes.js +39 -0
- package/lib/css/CssGenerator.js +8 -0
- package/lib/css/CssInjectStyleRuntimeModule.js +9 -0
- package/lib/css/CssLoadingRuntimeModule.js +94 -36
- package/lib/css/CssModule.js +1 -1
- package/lib/css/CssModulesPlugin.js +7 -6
- package/lib/css/CssParser.js +144 -11
- package/lib/css/CssServerStylesRuntimeModule.js +9 -0
- package/lib/css/cssMinify.js +11 -3
- package/lib/css/data.js +2814 -678
- package/lib/css/syntax.js +4082 -248
- package/lib/debug/ProfilingPlugin.js +4 -0
- package/lib/dependencies/AMDDefineDependencyParserPlugin.js +6 -3
- package/lib/dependencies/AMDRuntimeModules.js +18 -0
- package/lib/dependencies/CommonJsExportRequireDependency.js +3 -1
- package/lib/dependencies/CommonJsExportsParserPlugin.js +12 -13
- package/lib/dependencies/CommonJsImportsParserPlugin.js +1 -0
- package/lib/dependencies/CommonJsPlugin.js +19 -3
- package/lib/dependencies/CommonJsRequireDependency.js +32 -9
- package/lib/dependencies/ContextDependencyTemplateAsRequireCall.js +20 -7
- package/lib/dependencies/CssIcssExportDependency.js +7 -1
- package/lib/dependencies/HarmonyCompatibilityDependency.js +58 -4
- package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +8 -3
- package/lib/dependencies/HarmonyExportExpressionDependency.js +44 -29
- package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +171 -32
- package/lib/dependencies/HarmonyExportInitFragment.js +99 -19
- package/lib/dependencies/HarmonyExportSpecifierDependency.js +18 -30
- package/lib/dependencies/HarmonyImportBareSideEffectDependency.js +59 -0
- package/lib/dependencies/HarmonyImportDependency.js +99 -41
- package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +20 -3
- package/lib/dependencies/HarmonyImportSpecifierDependency.js +24 -1
- package/lib/dependencies/HarmonyModulesPlugin.js +20 -0
- package/lib/dependencies/HtmlEntryDependency.js +62 -2
- package/lib/dependencies/ImportContextDependency.js +43 -3
- package/lib/dependencies/ImportDependency.js +8 -29
- package/lib/dependencies/ImportMetaMainDependency.js +104 -0
- package/lib/dependencies/ImportMetaPlugin.js +59 -15
- package/lib/dependencies/ImportParserPlugin.js +24 -14
- package/lib/dependencies/RequireHeaderDependency.js +20 -21
- package/lib/dependencies/SystemRuntimeModule.js +9 -0
- package/lib/dependencies/WorkerDependency.js +1 -2
- package/lib/dependencies/WorkletDependency.js +1 -2
- package/lib/dependencies/importOptionsCheck.js +47 -0
- package/lib/dll/DelegatedModule.js +18 -1
- package/lib/dll/DllReferencePlugin.js +11 -8
- package/lib/dll/LibManifestPlugin.js +1 -1
- package/lib/errors/AnalyzableBailoutsWarning.js +41 -0
- package/lib/errors/DotenvFileError.js +29 -0
- package/lib/errors/DuplicateModulesWarning.js +12 -7
- package/lib/errors/EmptyCopyPatternWarning.js +26 -0
- package/lib/errors/ExternalStarReexportError.js +44 -0
- package/lib/errors/ImportedBindingAssignmentError.js +30 -0
- package/lib/errors/MissingSourceMapsWarning.js +36 -0
- package/lib/errors/ModuleParseError.js +2 -1
- package/lib/errors/UnusedAssetsWarning.js +36 -0
- package/lib/errors/UnusedFederationWarning.js +35 -0
- package/lib/errors/UnusedModulesWarning.js +38 -0
- package/lib/esm/ExportWebpackRequireRuntimeModule.js +9 -0
- package/lib/esm/ModuleChunkFormatPlugin.js +28 -3
- package/lib/esm/ModuleChunkLoadingPlugin.js +30 -11
- package/lib/esm/ModuleChunkLoadingRuntimeModule.js +92 -60
- package/lib/hmr/HotModuleReplacement.runtime.js +8 -2
- package/lib/hmr/HotModuleReplacementRuntimeModule.js +9 -0
- package/lib/html/HtmlGenerator.js +11 -5
- package/lib/html/HtmlModulesPlugin.js +360 -84
- package/lib/html/HtmlParser.js +13 -6
- package/lib/html/builtinEmbeddedRenderer.js +107 -0
- package/lib/html/data.js +121 -7
- package/lib/html/htmlMinify.js +84 -113
- package/lib/html/syntax.js +1067 -569
- package/lib/ids/HashedModuleIdsPlugin.js +2 -1
- package/lib/index.js +3 -0
- package/lib/javascript/JavascriptModule.js +1 -0
- package/lib/javascript/JavascriptModulesPlugin.js +52 -22
- package/lib/javascript/JavascriptParser.js +1255 -728
- package/lib/javascript/StartupHelpers.js +27 -3
- package/lib/javascript/data.js +172 -0
- package/lib/javascript/grammar.js +5546 -0
- package/lib/javascript/parser.js +1494 -0
- package/lib/javascript/regexp.js +1762 -0
- package/lib/javascript/regexpData.js +51 -0
- package/lib/javascript/syntax.js +8696 -5225
- package/lib/library/ModuleLibraryPlugin.js +116 -5
- package/lib/node/ReadFileChunkLoadingRuntimeModule.js +22 -0
- package/lib/node/RequireChunkLoadingRuntimeModule.js +22 -0
- package/lib/optimize/ConcatenatedModule.js +133 -25
- package/lib/optimize/ConstExportsPlugin.js +50 -39
- package/lib/optimize/InlineExports.js +20 -123
- package/lib/optimize/MangleExportsPlugin.js +10 -0
- package/lib/optimize/ModuleConcatenationPlugin.js +24 -1
- package/lib/optimize/RealContentHashPlugin.js +68 -9
- package/lib/optimize/SideEffectsFlagPlugin.js +17 -9
- package/lib/performance/AnalyzableBailoutsPlugin.js +115 -0
- package/lib/performance/CacheEffectivenessPlugin.js +4 -3
- package/lib/performance/DuplicateModulesPlugin.js +57 -13
- package/lib/performance/EvalUsagePlugin.js +5 -2
- package/lib/performance/MissingSourceMapsPlugin.js +115 -0
- package/lib/performance/PureAnnotationsPlugin.js +6 -3
- package/lib/performance/TopLevelThisPlugin.js +5 -4
- package/lib/performance/UnusedAssetsPlugin.js +109 -0
- package/lib/performance/UnusedFederationPlugin.js +147 -0
- package/lib/performance/UnusedModulesPlugin.js +141 -0
- package/lib/performance/UnusedReexportsPlugin.js +1 -55
- package/lib/performance/isOnlyReexported.js +65 -0
- package/lib/prefetch/ChunkPrefetchFunctionRuntimeModule.js +25 -5
- package/lib/prefetch/ChunkPrefetchPreloadPlugin.js +2 -0
- package/lib/prefetch/ChunkPrefetchStartupRuntimeModule.js +9 -0
- package/lib/prefetch/ChunkPrefetchTriggerRuntimeModule.js +9 -0
- package/lib/prefetch/ChunkPreloadTriggerRuntimeModule.js +9 -0
- package/lib/prefetch/ResourceHintPlugin.js +7 -3
- package/lib/prefetch/ResourceHintRuntimeModule.js +9 -0
- package/lib/prefetch/StartupAssetHintRuntimeModule.js +9 -0
- package/lib/rules/RuleSetCompiler.js +211 -4
- package/lib/runtime/AsyncModuleRuntimeModule.js +105 -67
- package/lib/runtime/AutoPublicPathRuntimeModule.js +9 -0
- package/lib/runtime/BaseUriRuntimeModule.js +9 -0
- package/lib/runtime/ChunkNameRuntimeModule.js +9 -0
- package/lib/runtime/EnsureChunkRuntimeModule.js +35 -16
- package/lib/runtime/GetChunkFilenameRuntimeModule.js +9 -0
- package/lib/runtime/GetFullHashRuntimeModule.js +9 -0
- package/lib/runtime/GetMainFilenameRuntimeModule.js +9 -0
- package/lib/runtime/GetWorkletBootstrapRuntimeModule.js +9 -0
- package/lib/runtime/GlobalRuntimeModule.js +9 -0
- package/lib/runtime/HasOwnPropertyRuntimeModule.js +9 -0
- package/lib/runtime/HelperRuntimeModule.js +10 -0
- package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +338 -217
- package/lib/runtime/NonceRuntimeModule.js +9 -0
- package/lib/runtime/OnChunksLoadedRuntimeModule.js +67 -20
- package/lib/runtime/PublicPathRuntimeModule.js +9 -0
- package/lib/runtime/RuntimeIdRuntimeModule.js +9 -0
- package/lib/runtime/SpecNamespaceObjectRuntimeModule.js +90 -0
- package/lib/runtime/StartupChunkDependenciesRuntimeModule.js +9 -0
- package/lib/runtime/StartupEntrypointRuntimeModule.js +9 -0
- package/lib/runtime/SystemContextRuntimeModule.js +9 -0
- package/lib/runtime/ToBinaryRuntimeModule.js +9 -0
- package/lib/schemes/HttpUriPlugin.js +22 -5
- package/lib/serialization/FileMiddleware.js +15 -2
- package/lib/serialization/ObjectMiddleware.js +138 -106
- package/lib/sharing/ConsumeSharedPlugin.js +12 -0
- package/lib/sharing/ConsumeSharedRuntimeModule.js +11 -0
- package/lib/sharing/ShareRuntimeModule.js +9 -0
- package/lib/sharing/declaredShared.js +47 -0
- package/lib/stats/DefaultStatsFactoryPlugin.js +3 -1
- package/lib/stats/DefaultStatsPrinterPlugin.js +3 -0
- package/lib/util/ArrayQueue.js +3 -3
- package/lib/util/SourceProcessor.js +76 -69
- package/lib/util/URLAbsoluteSpecifier.js +3 -1
- package/lib/util/async.js +292 -0
- package/lib/util/buildDiagnostics.js +69 -0
- package/lib/util/conventions.js +5 -1
- package/lib/util/fs.js +27 -1
- package/lib/util/handlerKeys.js +40 -0
- package/lib/util/identifier.js +20 -0
- package/lib/util/internalSerializables.js +6 -0
- package/lib/util/registerExternalSerializer.js +6 -45
- package/lib/wasm-async/AsyncWasmCompileRuntimeModule.js +9 -0
- package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +9 -0
- package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +9 -0
- package/lib/web/JsonpChunkLoadingRuntimeModule.js +36 -0
- package/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js +19 -0
- package/package.json +22 -16
- package/schemas/WebpackOptions.check.js +1 -1
- package/schemas/WebpackOptions.json +388 -76
- package/schemas/plugins/LoaderOptionsPlugin.check.js +1 -1
- package/schemas/plugins/ManifestPlugin.check.js +1 -1
- package/schemas/plugins/SourceMapDevToolPlugin.check.js +1 -1
- package/schemas/plugins/asset/AssetGeneratorOptions.check.js +1 -1
- package/schemas/plugins/asset/AssetResourceGeneratorOptions.check.js +1 -1
- package/schemas/plugins/container/ContainerPlugin.check.js +1 -1
- package/schemas/plugins/container/ModuleFederationPlugin.check.js +1 -1
- package/schemas/plugins/debug/ProfilingPlugin.check.js +1 -1
- package/schemas/plugins/dll/DllReferencePlugin.check.js +1 -1
- package/schemas/plugins/ids/HashedModuleIdsPlugin.check.js +1 -1
- package/schemas/plugins/schemes/HttpUriPlugin.check.js +1 -1
- package/types.d.ts +1440 -331
- package/lib/dependencies/ExportBindingInitFragment.js +0 -191
- package/lib/errors/EntrypointOverlapWarning.js +0 -45
- package/lib/performance/EntrypointOverlapPlugin.js +0 -122
|
@@ -26,13 +26,7 @@ const {
|
|
|
26
26
|
positionAt
|
|
27
27
|
} = require("./syntax");
|
|
28
28
|
|
|
29
|
-
/** @
|
|
30
|
-
/**
|
|
31
|
-
* @import {
|
|
32
|
-
* Options as AcornOptions,
|
|
33
|
-
* ecmaVersion as EcmaVersion
|
|
34
|
-
* } from "acorn"
|
|
35
|
-
*/
|
|
29
|
+
/** @import { EcmaVersion, ParserOptions, ParserPlugin } from "./syntax" */
|
|
36
30
|
/**
|
|
37
31
|
* @import {
|
|
38
32
|
* AssignmentExpression,
|
|
@@ -151,25 +145,8 @@ const {
|
|
|
151
145
|
|
|
152
146
|
/** @type {string[]} */
|
|
153
147
|
const EMPTY_ARRAY = [];
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
* Getter that reverses `arr` in place on first access and caches it. Lighter
|
|
157
|
-
* than `memoize(() => arr.reverse())` (one closure instead of two) and called
|
|
158
|
-
* per member expression on hot parse paths.
|
|
159
|
-
* @template T
|
|
160
|
-
* @param {T[]} arr array reversed lazily on first access
|
|
161
|
-
* @returns {() => T[]} getter returning the reversed array
|
|
162
|
-
*/
|
|
163
|
-
const lazyReverse = (arr) => {
|
|
164
|
-
let reversed = false;
|
|
165
|
-
return () => {
|
|
166
|
-
if (!reversed) {
|
|
167
|
-
arr.reverse();
|
|
168
|
-
reversed = true;
|
|
169
|
-
}
|
|
170
|
-
return arr;
|
|
171
|
-
};
|
|
172
|
-
};
|
|
148
|
+
/** @type {MembersOptionals} */
|
|
149
|
+
const EMPTY_MEMBERS_OPTIONALS = [];
|
|
173
150
|
|
|
174
151
|
const ALLOWED_MEMBER_TYPES_CALL_EXPRESSION = 0b01;
|
|
175
152
|
const ALLOWED_MEMBER_TYPES_EXPRESSION = 0b10;
|
|
@@ -183,8 +160,11 @@ const RETURN_FALSE = () => false;
|
|
|
183
160
|
// replacing three fresh closures per evaluated free variable.
|
|
184
161
|
const RETURN_EMPTY_ARRAY = () => [];
|
|
185
162
|
|
|
163
|
+
// Shared no-result fallback for the identifier evaluators.
|
|
164
|
+
const RETURN_UNDEFINED = () => undefined;
|
|
165
|
+
|
|
186
166
|
// Syntax: https://developer.mozilla.org/en/SpiderMonkey/Parser_API
|
|
187
|
-
let parser =
|
|
167
|
+
let parser = WebpackParser;
|
|
188
168
|
|
|
189
169
|
/** @typedef {Record<string, string> & { _isLegacyAssert?: boolean }} ImportAttributes */
|
|
190
170
|
|
|
@@ -327,7 +307,7 @@ class VariableInfo {
|
|
|
327
307
|
* @property {boolean=} ranges
|
|
328
308
|
* @property {boolean=} allowHashBang
|
|
329
309
|
* @property {boolean=} allowReturnOutsideFunction
|
|
330
|
-
* @property {boolean=} lazyNodes internal: serve `range` lazily and skip
|
|
310
|
+
* @property {boolean=} lazyNodes internal: serve `range` lazily and skip the parser's location/range tracking
|
|
331
311
|
* @property {Comment[]=} lazyComments internal: collect comments here without slicing their text eagerly
|
|
332
312
|
* @property {boolean=} importPhases enable parsing of the import phase proposals (import defer / import source)
|
|
333
313
|
* @property {boolean=} moduleFallback internal: for `auto`, let the parser downgrade module->script in place instead of re-parsing
|
|
@@ -430,24 +410,455 @@ const joinRanges = (startRange, endRange) => {
|
|
|
430
410
|
* Helper function used to generate a string representation of a
|
|
431
411
|
* [member expression](https://github.com/estree/estree/blob/master/es5.md#memberexpression).
|
|
432
412
|
* @param {string} object object to name
|
|
433
|
-
* @param {Members}
|
|
413
|
+
* @param {Members} members members in source order
|
|
434
414
|
* @returns {string} member expression as a string
|
|
435
415
|
* @example
|
|
436
416
|
* ```js
|
|
437
|
-
* const
|
|
438
|
-
* const name = objectAndMembersToName("myObject",
|
|
417
|
+
* const members = ["property1", "property2", "property3"]; // Members parsed from the AST
|
|
418
|
+
* const name = objectAndMembersToName("myObject", members);
|
|
439
419
|
*
|
|
440
420
|
* console.log(name); // "myObject.property1.property2.property3"
|
|
441
421
|
* ```
|
|
442
422
|
*/
|
|
443
|
-
const objectAndMembersToName = (object,
|
|
423
|
+
const objectAndMembersToName = (object, members) => {
|
|
444
424
|
let name = object;
|
|
445
|
-
for (let i =
|
|
446
|
-
name = `${name}.${
|
|
425
|
+
for (let i = 0; i < members.length; i++) {
|
|
426
|
+
name = `${name}.${members[i]}`;
|
|
447
427
|
}
|
|
448
428
|
return name;
|
|
449
429
|
};
|
|
450
430
|
|
|
431
|
+
/**
|
|
432
|
+
* The range of the object below each of the first `count` members of a chain,
|
|
433
|
+
* in source order: what `extractMemberExpressionChain` reports as memberRanges.
|
|
434
|
+
* @param {Expression | Super} expression a member expression
|
|
435
|
+
* @param {number} count how many members the chain has
|
|
436
|
+
* @returns {MemberRanges} the ranges
|
|
437
|
+
*/
|
|
438
|
+
const memberRangesOf = (expression, count) => {
|
|
439
|
+
/** @type {MemberRanges} */
|
|
440
|
+
const ranges = [];
|
|
441
|
+
let expr = /** @type {MemberExpression} */ (expression);
|
|
442
|
+
for (let i = 0; i < count; i++) {
|
|
443
|
+
const object = expr.object;
|
|
444
|
+
ranges.push(/** @type {Range} */ (object.range));
|
|
445
|
+
expr = /** @type {MemberExpression} */ (object);
|
|
446
|
+
}
|
|
447
|
+
if (count > 1) ranges.reverse();
|
|
448
|
+
return ranges;
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* In simple logical cases, we can use valueAsExpression to assist us in evaluating the expression on
|
|
453
|
+
* either side of a [BinaryExpression](https://github.com/estree/estree/blob/master/es5.md#binaryexpression).
|
|
454
|
+
* This supports scenarios in webpack like conditionally `import()`'ing modules based on some simple evaluation:
|
|
455
|
+
*
|
|
456
|
+
* ```js
|
|
457
|
+
* if (1 === 3) {
|
|
458
|
+
* import("./moduleA"); // webpack will auto evaluate this and not import the modules
|
|
459
|
+
* }
|
|
460
|
+
* ```
|
|
461
|
+
*
|
|
462
|
+
* Additional scenarios include evaluation of strings inside of dynamic import statements:
|
|
463
|
+
*
|
|
464
|
+
* ```js
|
|
465
|
+
* const foo = "foo";
|
|
466
|
+
* const bar = "bar";
|
|
467
|
+
*
|
|
468
|
+
* import("./" + foo + bar); // webpack will auto evaluate this into import("./foobar")
|
|
469
|
+
* ```
|
|
470
|
+
* @param {boolean | number | bigint | string} value the value to convert to an expression
|
|
471
|
+
* @param {BinaryExpression | UnaryExpression} expr the expression being evaluated
|
|
472
|
+
* @param {boolean} sideEffects whether the expression has side effects
|
|
473
|
+
* @returns {BasicEvaluatedExpression | undefined} the evaluated expression
|
|
474
|
+
* @example
|
|
475
|
+
*
|
|
476
|
+
* ```js
|
|
477
|
+
* const binaryExpr = new BinaryExpression("+",
|
|
478
|
+
* { type: "Literal", value: 2 },
|
|
479
|
+
* { type: "Literal", value: 3 }
|
|
480
|
+
* );
|
|
481
|
+
*
|
|
482
|
+
* const leftValue = 2;
|
|
483
|
+
* const rightValue = 3;
|
|
484
|
+
*
|
|
485
|
+
* const leftExpr = valueAsExpression(leftValue, binaryExpr.left, false);
|
|
486
|
+
* const rightExpr = valueAsExpression(rightValue, binaryExpr.right, false);
|
|
487
|
+
* const result = new BasicEvaluatedExpression()
|
|
488
|
+
* .setNumber(leftExpr.number + rightExpr.number)
|
|
489
|
+
* .setRange(binaryExpr.range);
|
|
490
|
+
*
|
|
491
|
+
* console.log(result.number); // Output: 5
|
|
492
|
+
* ```
|
|
493
|
+
*/
|
|
494
|
+
const valueAsExpression = (value, expr, sideEffects) => {
|
|
495
|
+
switch (typeof value) {
|
|
496
|
+
case "boolean":
|
|
497
|
+
return new BasicEvaluatedExpression()
|
|
498
|
+
.setBoolean(value)
|
|
499
|
+
.setSideEffects(sideEffects)
|
|
500
|
+
.setRange(/** @type {Range} */ (expr.range));
|
|
501
|
+
case "number":
|
|
502
|
+
return new BasicEvaluatedExpression()
|
|
503
|
+
.setNumber(value)
|
|
504
|
+
.setSideEffects(sideEffects)
|
|
505
|
+
.setRange(/** @type {Range} */ (expr.range));
|
|
506
|
+
case "bigint":
|
|
507
|
+
return new BasicEvaluatedExpression()
|
|
508
|
+
.setBigInt(value)
|
|
509
|
+
.setSideEffects(sideEffects)
|
|
510
|
+
.setRange(/** @type {Range} */ (expr.range));
|
|
511
|
+
case "string":
|
|
512
|
+
return new BasicEvaluatedExpression()
|
|
513
|
+
.setString(value)
|
|
514
|
+
.setSideEffects(sideEffects)
|
|
515
|
+
.setRange(/** @type {Range} */ (expr.range));
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
// The constant operators, shared so evaluating `a - b` allocates no handler.
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* @param {EXPECTED_ANY} l left operand
|
|
523
|
+
* @param {EXPECTED_ANY} r right operand
|
|
524
|
+
* @returns {EXPECTED_ANY} the result
|
|
525
|
+
*/
|
|
526
|
+
const SUBTRACT = (l, r) => l - r;
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* @param {EXPECTED_ANY} l left operand
|
|
530
|
+
* @param {EXPECTED_ANY} r right operand
|
|
531
|
+
* @returns {EXPECTED_ANY} the result
|
|
532
|
+
*/
|
|
533
|
+
const MULTIPLY = (l, r) => l * r;
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* @param {EXPECTED_ANY} l left operand
|
|
537
|
+
* @param {EXPECTED_ANY} r right operand
|
|
538
|
+
* @returns {EXPECTED_ANY} the result
|
|
539
|
+
*/
|
|
540
|
+
const DIVIDE = (l, r) => l / r;
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* @param {EXPECTED_ANY} l left operand
|
|
544
|
+
* @param {EXPECTED_ANY} r right operand
|
|
545
|
+
* @returns {EXPECTED_ANY} the result
|
|
546
|
+
*/
|
|
547
|
+
const POWER = (l, r) => l ** r;
|
|
548
|
+
|
|
549
|
+
/**
|
|
550
|
+
* @param {EXPECTED_ANY} l left operand
|
|
551
|
+
* @param {EXPECTED_ANY} r right operand
|
|
552
|
+
* @returns {EXPECTED_ANY} the result
|
|
553
|
+
*/
|
|
554
|
+
const BITWISE_AND = (l, r) => l & r;
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* @param {EXPECTED_ANY} l left operand
|
|
558
|
+
* @param {EXPECTED_ANY} r right operand
|
|
559
|
+
* @returns {EXPECTED_ANY} the result
|
|
560
|
+
*/
|
|
561
|
+
const BITWISE_OR = (l, r) => l | r;
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* @param {EXPECTED_ANY} l left operand
|
|
565
|
+
* @param {EXPECTED_ANY} r right operand
|
|
566
|
+
* @returns {EXPECTED_ANY} the result
|
|
567
|
+
*/
|
|
568
|
+
const BITWISE_XOR = (l, r) => l ^ r;
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* @param {EXPECTED_ANY} l left operand
|
|
572
|
+
* @param {EXPECTED_ANY} r right operand
|
|
573
|
+
* @returns {EXPECTED_ANY} the result
|
|
574
|
+
*/
|
|
575
|
+
const UNSIGNED_SHIFT_RIGHT = (l, r) => l >>> r;
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* @param {EXPECTED_ANY} l left operand
|
|
579
|
+
* @param {EXPECTED_ANY} r right operand
|
|
580
|
+
* @returns {EXPECTED_ANY} the result
|
|
581
|
+
*/
|
|
582
|
+
const SHIFT_RIGHT = (l, r) => l >> r;
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* @param {EXPECTED_ANY} l left operand
|
|
586
|
+
* @param {EXPECTED_ANY} r right operand
|
|
587
|
+
* @returns {EXPECTED_ANY} the result
|
|
588
|
+
*/
|
|
589
|
+
const SHIFT_LEFT = (l, r) => l << r;
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* @param {EXPECTED_ANY} l left operand
|
|
593
|
+
* @param {EXPECTED_ANY} r right operand
|
|
594
|
+
* @returns {EXPECTED_ANY} the result
|
|
595
|
+
*/
|
|
596
|
+
const LESS_THAN = (l, r) => l < r;
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* @param {EXPECTED_ANY} l left operand
|
|
600
|
+
* @param {EXPECTED_ANY} r right operand
|
|
601
|
+
* @returns {EXPECTED_ANY} the result
|
|
602
|
+
*/
|
|
603
|
+
const GREATER_THAN = (l, r) => l > r;
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* @param {EXPECTED_ANY} l left operand
|
|
607
|
+
* @param {EXPECTED_ANY} r right operand
|
|
608
|
+
* @returns {EXPECTED_ANY} the result
|
|
609
|
+
*/
|
|
610
|
+
const LESS_THAN_OR_EQUAL = (l, r) => l <= r;
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* @param {EXPECTED_ANY} l left operand
|
|
614
|
+
* @param {EXPECTED_ANY} r right operand
|
|
615
|
+
* @returns {EXPECTED_ANY} the result
|
|
616
|
+
*/
|
|
617
|
+
const GREATER_THAN_OR_EQUAL = (l, r) => l >= r;
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* @param {EXPECTED_ANY} v operand
|
|
621
|
+
* @returns {EXPECTED_ANY} the result
|
|
622
|
+
*/
|
|
623
|
+
const BITWISE_NOT = (v) => ~v;
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* @param {EXPECTED_ANY} v operand
|
|
627
|
+
* @returns {EXPECTED_ANY} the result
|
|
628
|
+
*/
|
|
629
|
+
// eslint-disable-next-line no-implicit-coercion
|
|
630
|
+
const TO_NUMBER = (v) => +v;
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* @param {EXPECTED_ANY} v operand
|
|
634
|
+
* @returns {EXPECTED_ANY} the result
|
|
635
|
+
*/
|
|
636
|
+
const NEGATE = (v) => -v;
|
|
637
|
+
|
|
638
|
+
/**
|
|
639
|
+
* Evaluates a binary expression if and only if it is a const operation (e.g. 1 + 2, "a" + "b", etc.).
|
|
640
|
+
* @template T
|
|
641
|
+
* @param {JavascriptParser} parser the parser evaluating the expression
|
|
642
|
+
* @param {BinaryExpression} expr the binary expression
|
|
643
|
+
* @param {(leftOperand: T, rightOperand: T) => boolean | number | bigint | string} operandHandler the handler for the operation (e.g. (a, b) => a + b)
|
|
644
|
+
* @returns {BasicEvaluatedExpression | undefined} the evaluated expression
|
|
645
|
+
*/
|
|
646
|
+
const handleConstOperation = (parser, expr, operandHandler) => {
|
|
647
|
+
const left = parser.evaluateExpression(expr.left);
|
|
648
|
+
if (!left.isCompileTimeValue()) return;
|
|
649
|
+
|
|
650
|
+
const right = parser.evaluateExpression(expr.right);
|
|
651
|
+
if (!right.isCompileTimeValue()) return;
|
|
652
|
+
|
|
653
|
+
const result = operandHandler(
|
|
654
|
+
/** @type {T} */ (left.asCompileTimeValue()),
|
|
655
|
+
/** @type {T} */ (right.asCompileTimeValue())
|
|
656
|
+
);
|
|
657
|
+
return valueAsExpression(
|
|
658
|
+
result,
|
|
659
|
+
expr,
|
|
660
|
+
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
661
|
+
);
|
|
662
|
+
};
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* Helper function to determine if two booleans are always different. This is used in `handleStrictEqualityComparison`
|
|
666
|
+
* to determine if an expressions boolean or nullish conversion is equal or not.
|
|
667
|
+
* @param {boolean} a first boolean to compare
|
|
668
|
+
* @param {boolean} b second boolean to compare
|
|
669
|
+
* @returns {boolean} true if the two booleans are always different, false otherwise
|
|
670
|
+
*/
|
|
671
|
+
const isAlwaysDifferent = (a, b) =>
|
|
672
|
+
(a === true && b === false) || (a === false && b === true);
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* Handle template string compare.
|
|
676
|
+
* @param {BasicEvaluatedExpression} left left
|
|
677
|
+
* @param {BasicEvaluatedExpression} right right
|
|
678
|
+
* @param {BinaryExpression} expr the comparison, for its range
|
|
679
|
+
* @param {boolean} eql true for "===" and false for "!=="
|
|
680
|
+
* @returns {BasicEvaluatedExpression | undefined} result
|
|
681
|
+
*/
|
|
682
|
+
const handleTemplateStringCompare = (left, right, expr, eql) => {
|
|
683
|
+
/**
|
|
684
|
+
* Returns value.
|
|
685
|
+
* @param {BasicEvaluatedExpression[]} parts parts
|
|
686
|
+
* @returns {string} value
|
|
687
|
+
*/
|
|
688
|
+
const getPrefix = (parts) => {
|
|
689
|
+
let value = "";
|
|
690
|
+
for (const p of parts) {
|
|
691
|
+
const v = p.asString();
|
|
692
|
+
if (v !== undefined) value += v;
|
|
693
|
+
else break;
|
|
694
|
+
}
|
|
695
|
+
return value;
|
|
696
|
+
};
|
|
697
|
+
/**
|
|
698
|
+
* Returns value.
|
|
699
|
+
* @param {BasicEvaluatedExpression[]} parts parts
|
|
700
|
+
* @returns {string} value
|
|
701
|
+
*/
|
|
702
|
+
const getSuffix = (parts) => {
|
|
703
|
+
let value = "";
|
|
704
|
+
for (let i = parts.length - 1; i >= 0; i--) {
|
|
705
|
+
const v = parts[i].asString();
|
|
706
|
+
if (v !== undefined) value = v + value;
|
|
707
|
+
else break;
|
|
708
|
+
}
|
|
709
|
+
return value;
|
|
710
|
+
};
|
|
711
|
+
const leftPrefix = getPrefix(
|
|
712
|
+
/** @type {BasicEvaluatedExpression[]} */ (left.parts)
|
|
713
|
+
);
|
|
714
|
+
const rightPrefix = getPrefix(
|
|
715
|
+
/** @type {BasicEvaluatedExpression[]} */ (right.parts)
|
|
716
|
+
);
|
|
717
|
+
const leftSuffix = getSuffix(
|
|
718
|
+
/** @type {BasicEvaluatedExpression[]} */ (left.parts)
|
|
719
|
+
);
|
|
720
|
+
const rightSuffix = getSuffix(
|
|
721
|
+
/** @type {BasicEvaluatedExpression[]} */ (right.parts)
|
|
722
|
+
);
|
|
723
|
+
const lenPrefix = Math.min(leftPrefix.length, rightPrefix.length);
|
|
724
|
+
const lenSuffix = Math.min(leftSuffix.length, rightSuffix.length);
|
|
725
|
+
const prefixMismatch =
|
|
726
|
+
lenPrefix > 0 &&
|
|
727
|
+
leftPrefix.slice(0, lenPrefix) !== rightPrefix.slice(0, lenPrefix);
|
|
728
|
+
const suffixMismatch =
|
|
729
|
+
lenSuffix > 0 &&
|
|
730
|
+
leftSuffix.slice(-lenSuffix) !== rightSuffix.slice(-lenSuffix);
|
|
731
|
+
if (prefixMismatch || suffixMismatch) {
|
|
732
|
+
return new BasicEvaluatedExpression()
|
|
733
|
+
.setRange(/** @type {Range} */ (expr.range))
|
|
734
|
+
.setBoolean(!eql)
|
|
735
|
+
.setSideEffects(
|
|
736
|
+
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
737
|
+
);
|
|
738
|
+
}
|
|
739
|
+
};
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* Helper function to handle BinaryExpressions using strict equality comparisons (e.g. "===" and "!==").
|
|
743
|
+
* @param {JavascriptParser} parser the parser evaluating the expression
|
|
744
|
+
* @param {BinaryExpression} expr the binary expression
|
|
745
|
+
* @param {boolean} eql true for "===" and false for "!=="
|
|
746
|
+
* @returns {BasicEvaluatedExpression | undefined} the evaluated expression
|
|
747
|
+
*/
|
|
748
|
+
const handleStrictEqualityComparison = (parser, expr, eql) => {
|
|
749
|
+
const left = parser.evaluateExpression(expr.left);
|
|
750
|
+
const right = parser.evaluateExpression(expr.right);
|
|
751
|
+
|
|
752
|
+
const leftConst = left.isCompileTimeValue();
|
|
753
|
+
const rightConst = right.isCompileTimeValue();
|
|
754
|
+
|
|
755
|
+
if (leftConst && rightConst) {
|
|
756
|
+
return new BasicEvaluatedExpression()
|
|
757
|
+
.setRange(/** @type {Range} */ (expr.range))
|
|
758
|
+
.setBoolean(
|
|
759
|
+
eql === (left.asCompileTimeValue() === right.asCompileTimeValue())
|
|
760
|
+
)
|
|
761
|
+
.setSideEffects(
|
|
762
|
+
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
if (left.isArray() && right.isArray()) {
|
|
767
|
+
return new BasicEvaluatedExpression()
|
|
768
|
+
.setRange(/** @type {Range} */ (expr.range))
|
|
769
|
+
.setBoolean(!eql)
|
|
770
|
+
.setSideEffects(
|
|
771
|
+
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
772
|
+
);
|
|
773
|
+
}
|
|
774
|
+
if (left.isTemplateString() && right.isTemplateString()) {
|
|
775
|
+
return handleTemplateStringCompare(left, right, expr, eql);
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
const leftPrimitive = left.isPrimitiveType();
|
|
779
|
+
const rightPrimitive = right.isPrimitiveType();
|
|
780
|
+
|
|
781
|
+
if (
|
|
782
|
+
// Primitive !== Object or
|
|
783
|
+
// compile-time object types are never equal to something at runtime
|
|
784
|
+
(leftPrimitive === false && (leftConst || rightPrimitive === true)) ||
|
|
785
|
+
(rightPrimitive === false && (rightConst || leftPrimitive === true)) ||
|
|
786
|
+
// Different nullish or boolish status also means not equal
|
|
787
|
+
isAlwaysDifferent(
|
|
788
|
+
/** @type {boolean} */ (left.asBool()),
|
|
789
|
+
/** @type {boolean} */ (right.asBool())
|
|
790
|
+
) ||
|
|
791
|
+
isAlwaysDifferent(
|
|
792
|
+
/** @type {boolean} */ (left.asNullish()),
|
|
793
|
+
/** @type {boolean} */ (right.asNullish())
|
|
794
|
+
)
|
|
795
|
+
) {
|
|
796
|
+
return new BasicEvaluatedExpression()
|
|
797
|
+
.setRange(/** @type {Range} */ (expr.range))
|
|
798
|
+
.setBoolean(!eql)
|
|
799
|
+
.setSideEffects(
|
|
800
|
+
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
801
|
+
);
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* Helper function to handle BinaryExpressions using abstract equality comparisons (e.g. "==" and "!=").
|
|
807
|
+
* @param {JavascriptParser} parser the parser evaluating the expression
|
|
808
|
+
* @param {BinaryExpression} expr the binary expression
|
|
809
|
+
* @param {boolean} eql true for "==" and false for "!="
|
|
810
|
+
* @returns {BasicEvaluatedExpression | undefined} the evaluated expression
|
|
811
|
+
*/
|
|
812
|
+
const handleAbstractEqualityComparison = (parser, expr, eql) => {
|
|
813
|
+
const left = parser.evaluateExpression(expr.left);
|
|
814
|
+
const right = parser.evaluateExpression(expr.right);
|
|
815
|
+
|
|
816
|
+
const leftConst = left.isCompileTimeValue();
|
|
817
|
+
const rightConst = right.isCompileTimeValue();
|
|
818
|
+
|
|
819
|
+
if (leftConst && rightConst) {
|
|
820
|
+
return new BasicEvaluatedExpression()
|
|
821
|
+
.setRange(/** @type {Range} */ (expr.range))
|
|
822
|
+
.setBoolean(
|
|
823
|
+
eql ===
|
|
824
|
+
// eslint-disable-next-line eqeqeq
|
|
825
|
+
(left.asCompileTimeValue() == right.asCompileTimeValue())
|
|
826
|
+
)
|
|
827
|
+
.setSideEffects(
|
|
828
|
+
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
829
|
+
);
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
if (left.isArray() && right.isArray()) {
|
|
833
|
+
return new BasicEvaluatedExpression()
|
|
834
|
+
.setRange(/** @type {Range} */ (expr.range))
|
|
835
|
+
.setBoolean(!eql)
|
|
836
|
+
.setSideEffects(
|
|
837
|
+
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
838
|
+
);
|
|
839
|
+
}
|
|
840
|
+
if (left.isTemplateString() && right.isTemplateString()) {
|
|
841
|
+
return handleTemplateStringCompare(left, right, expr, eql);
|
|
842
|
+
}
|
|
843
|
+
};
|
|
844
|
+
|
|
845
|
+
/**
|
|
846
|
+
* Evaluates a UnaryExpression if and only if it is a basic const operator (e.g. +a, -a, ~a).
|
|
847
|
+
* @template T
|
|
848
|
+
* @param {JavascriptParser} parser the parser evaluating the expression
|
|
849
|
+
* @param {UnaryExpression} expr the unary expression
|
|
850
|
+
* @param {(operand: T) => boolean | number | bigint | string} operandHandler handler for the operand
|
|
851
|
+
* @returns {BasicEvaluatedExpression | undefined} evaluated expression
|
|
852
|
+
*/
|
|
853
|
+
const handleUnaryConstOperation = (parser, expr, operandHandler) => {
|
|
854
|
+
const argument = parser.evaluateExpression(expr.argument);
|
|
855
|
+
if (!argument.isCompileTimeValue()) return;
|
|
856
|
+
const result = operandHandler(
|
|
857
|
+
/** @type {T} */ (argument.asCompileTimeValue())
|
|
858
|
+
);
|
|
859
|
+
return valueAsExpression(result, expr, argument.couldHaveSideEffects());
|
|
860
|
+
};
|
|
861
|
+
|
|
451
862
|
/**
|
|
452
863
|
* Grabs the name of a given expression and returns it as a string or undefined. Has particular
|
|
453
864
|
* handling for [Identifiers](https://github.com/estree/estree/blob/master/es5.md#identifier),
|
|
@@ -802,6 +1213,32 @@ class JavascriptParser extends Parser {
|
|
|
802
1213
|
// Offset of each line's first character, built on first getLocation use.
|
|
803
1214
|
/** @type {number[] | undefined} */
|
|
804
1215
|
this._lineStarts = undefined;
|
|
1216
|
+
// The last member expression resolved, kept while the node and the scope
|
|
1217
|
+
// it resolved in stay the same: the walk and an evaluate of one node meet
|
|
1218
|
+
/** @type {Expression | Super | undefined} */
|
|
1219
|
+
this._memberExpression = undefined;
|
|
1220
|
+
/** @type {ScopeInfo | undefined} */
|
|
1221
|
+
this._memberScope = undefined;
|
|
1222
|
+
/** @type {number} */
|
|
1223
|
+
this._memberMask = 0;
|
|
1224
|
+
/** @type {0 | 1 | 2} */
|
|
1225
|
+
this._memberType = 0;
|
|
1226
|
+
/** @type {string} */
|
|
1227
|
+
this._memberName = "";
|
|
1228
|
+
/** @type {string | VariableInfo | undefined} */
|
|
1229
|
+
this._memberRootInfo = undefined;
|
|
1230
|
+
/** @type {Members} */
|
|
1231
|
+
this._members = EMPTY_ARRAY;
|
|
1232
|
+
/** @type {MembersOptionals} */
|
|
1233
|
+
this._membersOptionals = EMPTY_MEMBERS_OPTIONALS;
|
|
1234
|
+
/** @type {CallExpression | undefined} */
|
|
1235
|
+
this._memberCall = undefined;
|
|
1236
|
+
/** @type {string} */
|
|
1237
|
+
this._memberCalleeName = "";
|
|
1238
|
+
/** @type {CalleeMembers} */
|
|
1239
|
+
this._memberCalleeMembers = EMPTY_ARRAY;
|
|
1240
|
+
/** @type {CallExpressionInfo | ExpressionExpressionInfo | undefined} */
|
|
1241
|
+
this._memberInfo = undefined;
|
|
805
1242
|
// True while only the parser's own taps sit on evaluate.for("Identifier");
|
|
806
1243
|
// recomputed per parse, gates the defined-identifier fast paths.
|
|
807
1244
|
this._evalIdentOwnTaps = false;
|
|
@@ -809,6 +1246,22 @@ class JavascriptParser extends Parser {
|
|
|
809
1246
|
// Reused for enterPatterns on every scope entry to avoid per-scope closures.
|
|
810
1247
|
/** @type {OnIdentString} */
|
|
811
1248
|
this._defineVariable = (ident) => this.defineVariable(ident);
|
|
1249
|
+
// The expression an identifier evaluator is running for, read by the
|
|
1250
|
+
// shared `_evaluateDefinedIdentifier` instead of a closure per evaluation
|
|
1251
|
+
/** @type {Identifier | ThisExpression | MemberExpression | undefined} */
|
|
1252
|
+
this._evaluatingExpression = undefined;
|
|
1253
|
+
/** @type {(name?: string) => BasicEvaluatedExpression | null | undefined} */
|
|
1254
|
+
this._evaluateDefinedIdentifier = (name) => {
|
|
1255
|
+
const hook = this.hooks.evaluateDefinedIdentifier.get(
|
|
1256
|
+
/** @type {string} */ (name)
|
|
1257
|
+
);
|
|
1258
|
+
if (hook !== undefined) {
|
|
1259
|
+
return hook.call(
|
|
1260
|
+
/** @type {Identifier | ThisExpression | MemberExpression} */
|
|
1261
|
+
(this._evaluatingExpression)
|
|
1262
|
+
);
|
|
1263
|
+
}
|
|
1264
|
+
};
|
|
812
1265
|
this._initializeEvaluating();
|
|
813
1266
|
// keyed taps are free for every other member chain, and a shadowed
|
|
814
1267
|
// `arguments` binding never dispatches the free-variable hooks
|
|
@@ -867,7 +1320,7 @@ class JavascriptParser extends Parser {
|
|
|
867
1320
|
const callee = expr.callee;
|
|
868
1321
|
if (callee.type !== "Identifier") return;
|
|
869
1322
|
if (callee.name !== "RegExp") {
|
|
870
|
-
return this.
|
|
1323
|
+
return this._callHooksForName1(
|
|
871
1324
|
this.hooks.evaluateNewExpression,
|
|
872
1325
|
callee.name,
|
|
873
1326
|
expr
|
|
@@ -979,277 +1432,9 @@ class JavascriptParser extends Parser {
|
|
|
979
1432
|
}
|
|
980
1433
|
});
|
|
981
1434
|
|
|
982
|
-
/**
|
|
983
|
-
* In simple logical cases, we can use valueAsExpression to assist us in evaluating the expression on
|
|
984
|
-
* either side of a [BinaryExpression](https://github.com/estree/estree/blob/master/es5.md#binaryexpression).
|
|
985
|
-
* This supports scenarios in webpack like conditionally `import()`'ing modules based on some simple evaluation:
|
|
986
|
-
*
|
|
987
|
-
* ```js
|
|
988
|
-
* if (1 === 3) {
|
|
989
|
-
* import("./moduleA"); // webpack will auto evaluate this and not import the modules
|
|
990
|
-
* }
|
|
991
|
-
* ```
|
|
992
|
-
*
|
|
993
|
-
* Additional scenarios include evaluation of strings inside of dynamic import statements:
|
|
994
|
-
*
|
|
995
|
-
* ```js
|
|
996
|
-
* const foo = "foo";
|
|
997
|
-
* const bar = "bar";
|
|
998
|
-
*
|
|
999
|
-
* import("./" + foo + bar); // webpack will auto evaluate this into import("./foobar")
|
|
1000
|
-
* ```
|
|
1001
|
-
* @param {boolean | number | bigint | string} value the value to convert to an expression
|
|
1002
|
-
* @param {BinaryExpression | UnaryExpression} expr the expression being evaluated
|
|
1003
|
-
* @param {boolean} sideEffects whether the expression has side effects
|
|
1004
|
-
* @returns {BasicEvaluatedExpression | undefined} the evaluated expression
|
|
1005
|
-
* @example
|
|
1006
|
-
*
|
|
1007
|
-
* ```js
|
|
1008
|
-
* const binaryExpr = new BinaryExpression("+",
|
|
1009
|
-
* { type: "Literal", value: 2 },
|
|
1010
|
-
* { type: "Literal", value: 3 }
|
|
1011
|
-
* );
|
|
1012
|
-
*
|
|
1013
|
-
* const leftValue = 2;
|
|
1014
|
-
* const rightValue = 3;
|
|
1015
|
-
*
|
|
1016
|
-
* const leftExpr = valueAsExpression(leftValue, binaryExpr.left, false);
|
|
1017
|
-
* const rightExpr = valueAsExpression(rightValue, binaryExpr.right, false);
|
|
1018
|
-
* const result = new BasicEvaluatedExpression()
|
|
1019
|
-
* .setNumber(leftExpr.number + rightExpr.number)
|
|
1020
|
-
* .setRange(binaryExpr.range);
|
|
1021
|
-
*
|
|
1022
|
-
* console.log(result.number); // Output: 5
|
|
1023
|
-
* ```
|
|
1024
|
-
*/
|
|
1025
|
-
const valueAsExpression = (value, expr, sideEffects) => {
|
|
1026
|
-
switch (typeof value) {
|
|
1027
|
-
case "boolean":
|
|
1028
|
-
return new BasicEvaluatedExpression()
|
|
1029
|
-
.setBoolean(value)
|
|
1030
|
-
.setSideEffects(sideEffects)
|
|
1031
|
-
.setRange(/** @type {Range} */ (expr.range));
|
|
1032
|
-
case "number":
|
|
1033
|
-
return new BasicEvaluatedExpression()
|
|
1034
|
-
.setNumber(value)
|
|
1035
|
-
.setSideEffects(sideEffects)
|
|
1036
|
-
.setRange(/** @type {Range} */ (expr.range));
|
|
1037
|
-
case "bigint":
|
|
1038
|
-
return new BasicEvaluatedExpression()
|
|
1039
|
-
.setBigInt(value)
|
|
1040
|
-
.setSideEffects(sideEffects)
|
|
1041
|
-
.setRange(/** @type {Range} */ (expr.range));
|
|
1042
|
-
case "string":
|
|
1043
|
-
return new BasicEvaluatedExpression()
|
|
1044
|
-
.setString(value)
|
|
1045
|
-
.setSideEffects(sideEffects)
|
|
1046
|
-
.setRange(/** @type {Range} */ (expr.range));
|
|
1047
|
-
}
|
|
1048
|
-
};
|
|
1049
|
-
|
|
1050
1435
|
this.hooks.evaluate.for("BinaryExpression").tap(CLASS_NAME, (_expr) => {
|
|
1051
1436
|
const expr = /** @type {BinaryExpression} */ (_expr);
|
|
1052
1437
|
|
|
1053
|
-
/**
|
|
1054
|
-
* Evaluates a binary expression if and only if it is a const operation (e.g. 1 + 2, "a" + "b", etc.).
|
|
1055
|
-
* @template T
|
|
1056
|
-
* @param {(leftOperand: T, rightOperand: T) => boolean | number | bigint | string} operandHandler the handler for the operation (e.g. (a, b) => a + b)
|
|
1057
|
-
* @returns {BasicEvaluatedExpression | undefined} the evaluated expression
|
|
1058
|
-
*/
|
|
1059
|
-
const handleConstOperation = (operandHandler) => {
|
|
1060
|
-
const left = this.evaluateExpression(expr.left);
|
|
1061
|
-
if (!left.isCompileTimeValue()) return;
|
|
1062
|
-
|
|
1063
|
-
const right = this.evaluateExpression(expr.right);
|
|
1064
|
-
if (!right.isCompileTimeValue()) return;
|
|
1065
|
-
|
|
1066
|
-
const result = operandHandler(
|
|
1067
|
-
/** @type {T} */ (left.asCompileTimeValue()),
|
|
1068
|
-
/** @type {T} */ (right.asCompileTimeValue())
|
|
1069
|
-
);
|
|
1070
|
-
return valueAsExpression(
|
|
1071
|
-
result,
|
|
1072
|
-
expr,
|
|
1073
|
-
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
1074
|
-
);
|
|
1075
|
-
};
|
|
1076
|
-
|
|
1077
|
-
/**
|
|
1078
|
-
* Helper function to determine if two booleans are always different. This is used in `handleStrictEqualityComparison`
|
|
1079
|
-
* to determine if an expressions boolean or nullish conversion is equal or not.
|
|
1080
|
-
* @param {boolean} a first boolean to compare
|
|
1081
|
-
* @param {boolean} b second boolean to compare
|
|
1082
|
-
* @returns {boolean} true if the two booleans are always different, false otherwise
|
|
1083
|
-
*/
|
|
1084
|
-
const isAlwaysDifferent = (a, b) =>
|
|
1085
|
-
(a === true && b === false) || (a === false && b === true);
|
|
1086
|
-
|
|
1087
|
-
/**
|
|
1088
|
-
* Handle template string compare.
|
|
1089
|
-
* @param {BasicEvaluatedExpression} left left
|
|
1090
|
-
* @param {BasicEvaluatedExpression} right right
|
|
1091
|
-
* @param {BasicEvaluatedExpression} res res
|
|
1092
|
-
* @param {boolean} eql true for "===" and false for "!=="
|
|
1093
|
-
* @returns {BasicEvaluatedExpression | undefined} result
|
|
1094
|
-
*/
|
|
1095
|
-
const handleTemplateStringCompare = (left, right, res, eql) => {
|
|
1096
|
-
/**
|
|
1097
|
-
* Returns value.
|
|
1098
|
-
* @param {BasicEvaluatedExpression[]} parts parts
|
|
1099
|
-
* @returns {string} value
|
|
1100
|
-
*/
|
|
1101
|
-
const getPrefix = (parts) => {
|
|
1102
|
-
let value = "";
|
|
1103
|
-
for (const p of parts) {
|
|
1104
|
-
const v = p.asString();
|
|
1105
|
-
if (v !== undefined) value += v;
|
|
1106
|
-
else break;
|
|
1107
|
-
}
|
|
1108
|
-
return value;
|
|
1109
|
-
};
|
|
1110
|
-
/**
|
|
1111
|
-
* Returns value.
|
|
1112
|
-
* @param {BasicEvaluatedExpression[]} parts parts
|
|
1113
|
-
* @returns {string} value
|
|
1114
|
-
*/
|
|
1115
|
-
const getSuffix = (parts) => {
|
|
1116
|
-
let value = "";
|
|
1117
|
-
for (let i = parts.length - 1; i >= 0; i--) {
|
|
1118
|
-
const v = parts[i].asString();
|
|
1119
|
-
if (v !== undefined) value = v + value;
|
|
1120
|
-
else break;
|
|
1121
|
-
}
|
|
1122
|
-
return value;
|
|
1123
|
-
};
|
|
1124
|
-
const leftPrefix = getPrefix(
|
|
1125
|
-
/** @type {BasicEvaluatedExpression[]} */ (left.parts)
|
|
1126
|
-
);
|
|
1127
|
-
const rightPrefix = getPrefix(
|
|
1128
|
-
/** @type {BasicEvaluatedExpression[]} */ (right.parts)
|
|
1129
|
-
);
|
|
1130
|
-
const leftSuffix = getSuffix(
|
|
1131
|
-
/** @type {BasicEvaluatedExpression[]} */ (left.parts)
|
|
1132
|
-
);
|
|
1133
|
-
const rightSuffix = getSuffix(
|
|
1134
|
-
/** @type {BasicEvaluatedExpression[]} */ (right.parts)
|
|
1135
|
-
);
|
|
1136
|
-
const lenPrefix = Math.min(leftPrefix.length, rightPrefix.length);
|
|
1137
|
-
const lenSuffix = Math.min(leftSuffix.length, rightSuffix.length);
|
|
1138
|
-
const prefixMismatch =
|
|
1139
|
-
lenPrefix > 0 &&
|
|
1140
|
-
leftPrefix.slice(0, lenPrefix) !== rightPrefix.slice(0, lenPrefix);
|
|
1141
|
-
const suffixMismatch =
|
|
1142
|
-
lenSuffix > 0 &&
|
|
1143
|
-
leftSuffix.slice(-lenSuffix) !== rightSuffix.slice(-lenSuffix);
|
|
1144
|
-
if (prefixMismatch || suffixMismatch) {
|
|
1145
|
-
return res
|
|
1146
|
-
.setBoolean(!eql)
|
|
1147
|
-
.setSideEffects(
|
|
1148
|
-
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
1149
|
-
);
|
|
1150
|
-
}
|
|
1151
|
-
};
|
|
1152
|
-
|
|
1153
|
-
/**
|
|
1154
|
-
* Helper function to handle BinaryExpressions using strict equality comparisons (e.g. "===" and "!==").
|
|
1155
|
-
* @param {boolean} eql true for "===" and false for "!=="
|
|
1156
|
-
* @returns {BasicEvaluatedExpression | undefined} the evaluated expression
|
|
1157
|
-
*/
|
|
1158
|
-
const handleStrictEqualityComparison = (eql) => {
|
|
1159
|
-
const left = this.evaluateExpression(expr.left);
|
|
1160
|
-
const right = this.evaluateExpression(expr.right);
|
|
1161
|
-
const res = new BasicEvaluatedExpression();
|
|
1162
|
-
res.setRange(/** @type {Range} */ (expr.range));
|
|
1163
|
-
|
|
1164
|
-
const leftConst = left.isCompileTimeValue();
|
|
1165
|
-
const rightConst = right.isCompileTimeValue();
|
|
1166
|
-
|
|
1167
|
-
if (leftConst && rightConst) {
|
|
1168
|
-
return res
|
|
1169
|
-
.setBoolean(
|
|
1170
|
-
eql === (left.asCompileTimeValue() === right.asCompileTimeValue())
|
|
1171
|
-
)
|
|
1172
|
-
.setSideEffects(
|
|
1173
|
-
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
1174
|
-
);
|
|
1175
|
-
}
|
|
1176
|
-
|
|
1177
|
-
if (left.isArray() && right.isArray()) {
|
|
1178
|
-
return res
|
|
1179
|
-
.setBoolean(!eql)
|
|
1180
|
-
.setSideEffects(
|
|
1181
|
-
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
1182
|
-
);
|
|
1183
|
-
}
|
|
1184
|
-
if (left.isTemplateString() && right.isTemplateString()) {
|
|
1185
|
-
return handleTemplateStringCompare(left, right, res, eql);
|
|
1186
|
-
}
|
|
1187
|
-
|
|
1188
|
-
const leftPrimitive = left.isPrimitiveType();
|
|
1189
|
-
const rightPrimitive = right.isPrimitiveType();
|
|
1190
|
-
|
|
1191
|
-
if (
|
|
1192
|
-
// Primitive !== Object or
|
|
1193
|
-
// compile-time object types are never equal to something at runtime
|
|
1194
|
-
(leftPrimitive === false && (leftConst || rightPrimitive === true)) ||
|
|
1195
|
-
(rightPrimitive === false &&
|
|
1196
|
-
(rightConst || leftPrimitive === true)) ||
|
|
1197
|
-
// Different nullish or boolish status also means not equal
|
|
1198
|
-
isAlwaysDifferent(
|
|
1199
|
-
/** @type {boolean} */ (left.asBool()),
|
|
1200
|
-
/** @type {boolean} */ (right.asBool())
|
|
1201
|
-
) ||
|
|
1202
|
-
isAlwaysDifferent(
|
|
1203
|
-
/** @type {boolean} */ (left.asNullish()),
|
|
1204
|
-
/** @type {boolean} */ (right.asNullish())
|
|
1205
|
-
)
|
|
1206
|
-
) {
|
|
1207
|
-
return res
|
|
1208
|
-
.setBoolean(!eql)
|
|
1209
|
-
.setSideEffects(
|
|
1210
|
-
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
1211
|
-
);
|
|
1212
|
-
}
|
|
1213
|
-
};
|
|
1214
|
-
|
|
1215
|
-
/**
|
|
1216
|
-
* Helper function to handle BinaryExpressions using abstract equality comparisons (e.g. "==" and "!=").
|
|
1217
|
-
* @param {boolean} eql true for "==" and false for "!="
|
|
1218
|
-
* @returns {BasicEvaluatedExpression | undefined} the evaluated expression
|
|
1219
|
-
*/
|
|
1220
|
-
const handleAbstractEqualityComparison = (eql) => {
|
|
1221
|
-
const left = this.evaluateExpression(expr.left);
|
|
1222
|
-
const right = this.evaluateExpression(expr.right);
|
|
1223
|
-
const res = new BasicEvaluatedExpression();
|
|
1224
|
-
res.setRange(/** @type {Range} */ (expr.range));
|
|
1225
|
-
|
|
1226
|
-
const leftConst = left.isCompileTimeValue();
|
|
1227
|
-
const rightConst = right.isCompileTimeValue();
|
|
1228
|
-
|
|
1229
|
-
if (leftConst && rightConst) {
|
|
1230
|
-
return res
|
|
1231
|
-
.setBoolean(
|
|
1232
|
-
eql ===
|
|
1233
|
-
// eslint-disable-next-line eqeqeq
|
|
1234
|
-
(left.asCompileTimeValue() == right.asCompileTimeValue())
|
|
1235
|
-
)
|
|
1236
|
-
.setSideEffects(
|
|
1237
|
-
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
1238
|
-
);
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
|
-
if (left.isArray() && right.isArray()) {
|
|
1242
|
-
return res
|
|
1243
|
-
.setBoolean(!eql)
|
|
1244
|
-
.setSideEffects(
|
|
1245
|
-
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
1246
|
-
);
|
|
1247
|
-
}
|
|
1248
|
-
if (left.isTemplateString() && right.isTemplateString()) {
|
|
1249
|
-
return handleTemplateStringCompare(left, right, res, eql);
|
|
1250
|
-
}
|
|
1251
|
-
};
|
|
1252
|
-
|
|
1253
1438
|
if (expr.operator === "+") {
|
|
1254
1439
|
const left = this.evaluateExpression(expr.left);
|
|
1255
1440
|
const right = this.evaluateExpression(expr.right);
|
|
@@ -1416,41 +1601,41 @@ class JavascriptParser extends Parser {
|
|
|
1416
1601
|
res.setRange(/** @type {Range} */ (expr.range));
|
|
1417
1602
|
return res;
|
|
1418
1603
|
} else if (expr.operator === "-") {
|
|
1419
|
-
return handleConstOperation(
|
|
1604
|
+
return handleConstOperation(this, expr, SUBTRACT);
|
|
1420
1605
|
} else if (expr.operator === "*") {
|
|
1421
|
-
return handleConstOperation(
|
|
1606
|
+
return handleConstOperation(this, expr, MULTIPLY);
|
|
1422
1607
|
} else if (expr.operator === "/") {
|
|
1423
|
-
return handleConstOperation(
|
|
1608
|
+
return handleConstOperation(this, expr, DIVIDE);
|
|
1424
1609
|
} else if (expr.operator === "**") {
|
|
1425
|
-
return handleConstOperation(
|
|
1610
|
+
return handleConstOperation(this, expr, POWER);
|
|
1426
1611
|
} else if (expr.operator === "===") {
|
|
1427
|
-
return handleStrictEqualityComparison(true);
|
|
1612
|
+
return handleStrictEqualityComparison(this, expr, true);
|
|
1428
1613
|
} else if (expr.operator === "==") {
|
|
1429
|
-
return handleAbstractEqualityComparison(true);
|
|
1614
|
+
return handleAbstractEqualityComparison(this, expr, true);
|
|
1430
1615
|
} else if (expr.operator === "!==") {
|
|
1431
|
-
return handleStrictEqualityComparison(false);
|
|
1616
|
+
return handleStrictEqualityComparison(this, expr, false);
|
|
1432
1617
|
} else if (expr.operator === "!=") {
|
|
1433
|
-
return handleAbstractEqualityComparison(false);
|
|
1618
|
+
return handleAbstractEqualityComparison(this, expr, false);
|
|
1434
1619
|
} else if (expr.operator === "&") {
|
|
1435
|
-
return handleConstOperation(
|
|
1620
|
+
return handleConstOperation(this, expr, BITWISE_AND);
|
|
1436
1621
|
} else if (expr.operator === "|") {
|
|
1437
|
-
return handleConstOperation(
|
|
1622
|
+
return handleConstOperation(this, expr, BITWISE_OR);
|
|
1438
1623
|
} else if (expr.operator === "^") {
|
|
1439
|
-
return handleConstOperation(
|
|
1624
|
+
return handleConstOperation(this, expr, BITWISE_XOR);
|
|
1440
1625
|
} else if (expr.operator === ">>>") {
|
|
1441
|
-
return handleConstOperation(
|
|
1626
|
+
return handleConstOperation(this, expr, UNSIGNED_SHIFT_RIGHT);
|
|
1442
1627
|
} else if (expr.operator === ">>") {
|
|
1443
|
-
return handleConstOperation(
|
|
1628
|
+
return handleConstOperation(this, expr, SHIFT_RIGHT);
|
|
1444
1629
|
} else if (expr.operator === "<<") {
|
|
1445
|
-
return handleConstOperation(
|
|
1630
|
+
return handleConstOperation(this, expr, SHIFT_LEFT);
|
|
1446
1631
|
} else if (expr.operator === "<") {
|
|
1447
|
-
return handleConstOperation(
|
|
1632
|
+
return handleConstOperation(this, expr, LESS_THAN);
|
|
1448
1633
|
} else if (expr.operator === ">") {
|
|
1449
|
-
return handleConstOperation(
|
|
1634
|
+
return handleConstOperation(this, expr, GREATER_THAN);
|
|
1450
1635
|
} else if (expr.operator === "<=") {
|
|
1451
|
-
return handleConstOperation(
|
|
1636
|
+
return handleConstOperation(this, expr, LESS_THAN_OR_EQUAL);
|
|
1452
1637
|
} else if (expr.operator === ">=") {
|
|
1453
|
-
return handleConstOperation(
|
|
1638
|
+
return handleConstOperation(this, expr, GREATER_THAN_OR_EQUAL);
|
|
1454
1639
|
} else if (expr.operator === "in") {
|
|
1455
1640
|
// `x in y` always evaluates to a boolean, so it is never nullish
|
|
1456
1641
|
const left = this.evaluateExpression(expr.left);
|
|
@@ -1466,25 +1651,10 @@ class JavascriptParser extends Parser {
|
|
|
1466
1651
|
this.hooks.evaluate.for("UnaryExpression").tap(CLASS_NAME, (_expr) => {
|
|
1467
1652
|
const expr = /** @type {UnaryExpression} */ (_expr);
|
|
1468
1653
|
|
|
1469
|
-
/**
|
|
1470
|
-
* Evaluates a UnaryExpression if and only if it is a basic const operator (e.g. +a, -a, ~a).
|
|
1471
|
-
* @template T
|
|
1472
|
-
* @param {(operand: T) => boolean | number | bigint | string} operandHandler handler for the operand
|
|
1473
|
-
* @returns {BasicEvaluatedExpression | undefined} evaluated expression
|
|
1474
|
-
*/
|
|
1475
|
-
const handleConstOperation = (operandHandler) => {
|
|
1476
|
-
const argument = this.evaluateExpression(expr.argument);
|
|
1477
|
-
if (!argument.isCompileTimeValue()) return;
|
|
1478
|
-
const result = operandHandler(
|
|
1479
|
-
/** @type {T} */ (argument.asCompileTimeValue())
|
|
1480
|
-
);
|
|
1481
|
-
return valueAsExpression(result, expr, argument.couldHaveSideEffects());
|
|
1482
|
-
};
|
|
1483
|
-
|
|
1484
1654
|
if (expr.operator === "typeof") {
|
|
1485
1655
|
switch (expr.argument.type) {
|
|
1486
1656
|
case "Identifier": {
|
|
1487
|
-
const res = this.
|
|
1657
|
+
const res = this._callHooksForName1(
|
|
1488
1658
|
this.hooks.evaluateTypeof,
|
|
1489
1659
|
expr.argument.name,
|
|
1490
1660
|
expr
|
|
@@ -1493,7 +1663,7 @@ class JavascriptParser extends Parser {
|
|
|
1493
1663
|
break;
|
|
1494
1664
|
}
|
|
1495
1665
|
case "MetaProperty": {
|
|
1496
|
-
const res = this.
|
|
1666
|
+
const res = this._callHooksForName1(
|
|
1497
1667
|
this.hooks.evaluateTypeof,
|
|
1498
1668
|
/** @type {string} */
|
|
1499
1669
|
(getRootName(expr.argument)),
|
|
@@ -1579,12 +1749,11 @@ class JavascriptParser extends Parser {
|
|
|
1579
1749
|
.setSideEffects(argument.couldHaveSideEffects())
|
|
1580
1750
|
.setRange(/** @type {Range} */ (expr.range));
|
|
1581
1751
|
} else if (expr.operator === "~") {
|
|
1582
|
-
return
|
|
1752
|
+
return handleUnaryConstOperation(this, expr, BITWISE_NOT);
|
|
1583
1753
|
} else if (expr.operator === "+") {
|
|
1584
|
-
|
|
1585
|
-
return handleConstOperation((v) => +v);
|
|
1754
|
+
return handleUnaryConstOperation(this, expr, TO_NUMBER);
|
|
1586
1755
|
} else if (expr.operator === "-") {
|
|
1587
|
-
return
|
|
1756
|
+
return handleUnaryConstOperation(this, expr, NEGATE);
|
|
1588
1757
|
}
|
|
1589
1758
|
});
|
|
1590
1759
|
this.hooks.evaluateTypeof
|
|
@@ -1623,18 +1792,18 @@ class JavascriptParser extends Parser {
|
|
|
1623
1792
|
cachedExpression = expression;
|
|
1624
1793
|
cachedInfo = info;
|
|
1625
1794
|
if (info !== undefined) {
|
|
1626
|
-
|
|
1795
|
+
// saved around the call: a hook may evaluate another identifier
|
|
1796
|
+
const outer = this._evaluatingExpression;
|
|
1797
|
+
this._evaluatingExpression = expression;
|
|
1798
|
+
const result = this.callHooksForInfoWithFallback(
|
|
1627
1799
|
this.hooks.evaluateIdentifier,
|
|
1628
1800
|
info.name,
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
const hook = this.hooks.evaluateDefinedIdentifier.get(name);
|
|
1632
|
-
if (hook !== undefined) {
|
|
1633
|
-
return hook.call(expression);
|
|
1634
|
-
}
|
|
1635
|
-
},
|
|
1801
|
+
RETURN_UNDEFINED,
|
|
1802
|
+
this._evaluateDefinedIdentifier,
|
|
1636
1803
|
expression
|
|
1637
1804
|
);
|
|
1805
|
+
this._evaluatingExpression = outer;
|
|
1806
|
+
return result;
|
|
1638
1807
|
}
|
|
1639
1808
|
});
|
|
1640
1809
|
this.hooks.evaluate
|
|
@@ -1699,7 +1868,7 @@ class JavascriptParser extends Parser {
|
|
|
1699
1868
|
this.hooks.evaluate.for("MetaProperty").tap(CLASS_NAME, (expr) => {
|
|
1700
1869
|
const metaProperty = /** @type {MetaProperty} */ (expr);
|
|
1701
1870
|
|
|
1702
|
-
return this.
|
|
1871
|
+
return this._callHooksForName1(
|
|
1703
1872
|
this.hooks.evaluateIdentifier,
|
|
1704
1873
|
/** @type {string} */
|
|
1705
1874
|
(getRootName(metaProperty)),
|
|
@@ -1733,7 +1902,7 @@ class JavascriptParser extends Parser {
|
|
|
1733
1902
|
return hook.call(expr, param);
|
|
1734
1903
|
}
|
|
1735
1904
|
} else if (expr.callee.type === "Identifier") {
|
|
1736
|
-
return this.
|
|
1905
|
+
return this._callHooksForName1(
|
|
1737
1906
|
this.hooks.evaluateCallExpression,
|
|
1738
1907
|
expr.callee.name,
|
|
1739
1908
|
expr
|
|
@@ -2504,13 +2673,14 @@ class JavascriptParser extends Parser {
|
|
|
2504
2673
|
* @param {BlockStatement | StaticBlock} statement block statement
|
|
2505
2674
|
*/
|
|
2506
2675
|
walkBlockStatement(statement) {
|
|
2507
|
-
this.
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2676
|
+
const oldScope = this._enterBlockScope();
|
|
2677
|
+
const body = statement.body;
|
|
2678
|
+
const prev = this.prevStatement;
|
|
2679
|
+
this.blockPreWalkStatements(body);
|
|
2680
|
+
this.prevStatement = prev;
|
|
2681
|
+
this.walkStatements(body);
|
|
2682
|
+
|
|
2683
|
+
this._exitBlockScope(oldScope, true);
|
|
2514
2684
|
}
|
|
2515
2685
|
|
|
2516
2686
|
/**
|
|
@@ -2562,18 +2732,27 @@ class JavascriptParser extends Parser {
|
|
|
2562
2732
|
if (result === undefined) {
|
|
2563
2733
|
const guard = this.hooks.collectGuards.call(statement.test);
|
|
2564
2734
|
this.walkExpression(statement.test);
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2735
|
+
// allocate the branch closure only when a guard frame needs pushing
|
|
2736
|
+
if (guard && guard.consequent) {
|
|
2737
|
+
this.walkGuardedBranch(guard.consequent, () =>
|
|
2738
|
+
this.walkNestedStatement(statement.consequent)
|
|
2739
|
+
);
|
|
2740
|
+
} else {
|
|
2741
|
+
this.walkNestedStatement(statement.consequent);
|
|
2742
|
+
}
|
|
2568
2743
|
|
|
2569
2744
|
const consequentTerminated = this.scope.terminated;
|
|
2570
2745
|
this.scope.terminated = undefined;
|
|
2571
2746
|
|
|
2572
2747
|
if (statement.alternate) {
|
|
2573
2748
|
const alternate = statement.alternate;
|
|
2574
|
-
|
|
2575
|
-
this.
|
|
2576
|
-
|
|
2749
|
+
if (guard && guard.alternate) {
|
|
2750
|
+
this.walkGuardedBranch(guard.alternate, () =>
|
|
2751
|
+
this.walkNestedStatement(alternate)
|
|
2752
|
+
);
|
|
2753
|
+
} else {
|
|
2754
|
+
this.walkNestedStatement(alternate);
|
|
2755
|
+
}
|
|
2577
2756
|
}
|
|
2578
2757
|
|
|
2579
2758
|
const alternateTerminated = this.scope.terminated;
|
|
@@ -2607,9 +2786,10 @@ class JavascriptParser extends Parser {
|
|
|
2607
2786
|
const result = hook.call(statement);
|
|
2608
2787
|
if (result === true) return;
|
|
2609
2788
|
}
|
|
2610
|
-
this.
|
|
2611
|
-
|
|
2612
|
-
|
|
2789
|
+
const oldScope = this._enterBlockScope();
|
|
2790
|
+
this.walkNestedStatement(statement.body);
|
|
2791
|
+
|
|
2792
|
+
this._exitBlockScope(oldScope, false);
|
|
2613
2793
|
}
|
|
2614
2794
|
|
|
2615
2795
|
/**
|
|
@@ -2631,10 +2811,11 @@ class JavascriptParser extends Parser {
|
|
|
2631
2811
|
statement
|
|
2632
2812
|
);
|
|
2633
2813
|
}
|
|
2634
|
-
this.
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2814
|
+
const oldScope = this._enterBlockScope();
|
|
2815
|
+
this.walkExpression(statement.object);
|
|
2816
|
+
this.walkNestedStatement(statement.body);
|
|
2817
|
+
|
|
2818
|
+
this._exitBlockScope(oldScope, false);
|
|
2638
2819
|
}
|
|
2639
2820
|
|
|
2640
2821
|
/**
|
|
@@ -2747,10 +2928,11 @@ class JavascriptParser extends Parser {
|
|
|
2747
2928
|
* @param {WhileStatement} statement while statement
|
|
2748
2929
|
*/
|
|
2749
2930
|
walkWhileStatement(statement) {
|
|
2750
|
-
this.
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2931
|
+
const oldScope = this._enterBlockScope();
|
|
2932
|
+
this.walkExpression(statement.test);
|
|
2933
|
+
this.walkNestedStatement(statement.body);
|
|
2934
|
+
|
|
2935
|
+
this._exitBlockScope(oldScope, false);
|
|
2754
2936
|
}
|
|
2755
2937
|
|
|
2756
2938
|
/**
|
|
@@ -2766,10 +2948,11 @@ class JavascriptParser extends Parser {
|
|
|
2766
2948
|
* @param {DoWhileStatement} statement do while statement
|
|
2767
2949
|
*/
|
|
2768
2950
|
walkDoWhileStatement(statement) {
|
|
2769
|
-
this.
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2951
|
+
const oldScope = this._enterBlockScope();
|
|
2952
|
+
this.walkNestedStatement(statement.body);
|
|
2953
|
+
this.walkExpression(statement.test);
|
|
2954
|
+
|
|
2955
|
+
this._exitBlockScope(oldScope, false);
|
|
2773
2956
|
}
|
|
2774
2957
|
|
|
2775
2958
|
/**
|
|
@@ -2788,35 +2971,36 @@ class JavascriptParser extends Parser {
|
|
|
2788
2971
|
* @param {ForStatement} statement for statement
|
|
2789
2972
|
*/
|
|
2790
2973
|
walkForStatement(statement) {
|
|
2791
|
-
this.
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
}
|
|
2800
|
-
}
|
|
2801
|
-
if (statement.test) {
|
|
2802
|
-
this.walkExpression(statement.test);
|
|
2803
|
-
}
|
|
2804
|
-
if (statement.update) {
|
|
2805
|
-
this.walkExpression(statement.update);
|
|
2974
|
+
const oldScope = this._enterBlockScope();
|
|
2975
|
+
if (statement.init) {
|
|
2976
|
+
if (statement.init.type === "VariableDeclaration") {
|
|
2977
|
+
this.blockPreWalkVariableDeclaration(statement.init);
|
|
2978
|
+
this.prevStatement = undefined;
|
|
2979
|
+
this.walkStatement(statement.init);
|
|
2980
|
+
} else {
|
|
2981
|
+
this.walkExpression(statement.init);
|
|
2806
2982
|
}
|
|
2983
|
+
}
|
|
2984
|
+
if (statement.test) {
|
|
2985
|
+
this.walkExpression(statement.test);
|
|
2986
|
+
}
|
|
2987
|
+
if (statement.update) {
|
|
2988
|
+
this.walkExpression(statement.update);
|
|
2989
|
+
}
|
|
2807
2990
|
|
|
2808
|
-
|
|
2991
|
+
const body = statement.body;
|
|
2809
2992
|
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2993
|
+
if (body.type === "BlockStatement") {
|
|
2994
|
+
// no need to add additional scope
|
|
2995
|
+
const prev = this.prevStatement;
|
|
2996
|
+
this.blockPreWalkStatements(body.body);
|
|
2997
|
+
this.prevStatement = prev;
|
|
2998
|
+
this.walkStatements(body.body);
|
|
2999
|
+
} else {
|
|
3000
|
+
this.walkNestedStatement(body);
|
|
3001
|
+
}
|
|
3002
|
+
|
|
3003
|
+
this._exitBlockScope(oldScope, false);
|
|
2820
3004
|
}
|
|
2821
3005
|
|
|
2822
3006
|
/**
|
|
@@ -2835,28 +3019,29 @@ class JavascriptParser extends Parser {
|
|
|
2835
3019
|
* @param {ForInStatement} statement for statement
|
|
2836
3020
|
*/
|
|
2837
3021
|
walkForInStatement(statement) {
|
|
2838
|
-
this.
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
3022
|
+
const oldScope = this._enterBlockScope();
|
|
3023
|
+
if (statement.left.type === "VariableDeclaration") {
|
|
3024
|
+
this.blockPreWalkVariableDeclaration(statement.left);
|
|
3025
|
+
this.walkVariableDeclaration(statement.left);
|
|
3026
|
+
} else {
|
|
3027
|
+
this.walkPattern(statement.left);
|
|
3028
|
+
}
|
|
2845
3029
|
|
|
2846
|
-
|
|
3030
|
+
this.walkExpression(statement.right);
|
|
2847
3031
|
|
|
2848
|
-
|
|
3032
|
+
const body = statement.body;
|
|
2849
3033
|
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
3034
|
+
if (body.type === "BlockStatement") {
|
|
3035
|
+
// no need to add additional scope
|
|
3036
|
+
const prev = this.prevStatement;
|
|
3037
|
+
this.blockPreWalkStatements(body.body);
|
|
3038
|
+
this.prevStatement = prev;
|
|
3039
|
+
this.walkStatements(body.body);
|
|
3040
|
+
} else {
|
|
3041
|
+
this.walkNestedStatement(body);
|
|
3042
|
+
}
|
|
3043
|
+
|
|
3044
|
+
this._exitBlockScope(oldScope, false);
|
|
2860
3045
|
}
|
|
2861
3046
|
|
|
2862
3047
|
/**
|
|
@@ -2878,28 +3063,29 @@ class JavascriptParser extends Parser {
|
|
|
2878
3063
|
* @param {ForOfStatement} statement for statement
|
|
2879
3064
|
*/
|
|
2880
3065
|
walkForOfStatement(statement) {
|
|
2881
|
-
this.
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
3066
|
+
const oldScope = this._enterBlockScope();
|
|
3067
|
+
if (statement.left.type === "VariableDeclaration") {
|
|
3068
|
+
this.blockPreWalkVariableDeclaration(statement.left);
|
|
3069
|
+
this.walkVariableDeclaration(statement.left);
|
|
3070
|
+
} else {
|
|
3071
|
+
this.walkPattern(statement.left);
|
|
3072
|
+
}
|
|
2888
3073
|
|
|
2889
|
-
|
|
3074
|
+
this.walkExpression(statement.right);
|
|
2890
3075
|
|
|
2891
|
-
|
|
3076
|
+
const body = statement.body;
|
|
2892
3077
|
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
3078
|
+
if (body.type === "BlockStatement") {
|
|
3079
|
+
// no need to add additional scope
|
|
3080
|
+
const prev = this.prevStatement;
|
|
3081
|
+
this.blockPreWalkStatements(body.body);
|
|
3082
|
+
this.prevStatement = prev;
|
|
3083
|
+
this.walkStatements(body.body);
|
|
3084
|
+
} else {
|
|
3085
|
+
this.walkNestedStatement(body);
|
|
3086
|
+
}
|
|
3087
|
+
|
|
3088
|
+
this._exitBlockScope(oldScope, false);
|
|
2903
3089
|
}
|
|
2904
3090
|
|
|
2905
3091
|
/**
|
|
@@ -2925,19 +3111,20 @@ class JavascriptParser extends Parser {
|
|
|
2925
3111
|
if (this._strictInModuleOutput) {
|
|
2926
3112
|
this._checkStrictModeParams(statement.params);
|
|
2927
3113
|
}
|
|
2928
|
-
this.
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
3114
|
+
const oldScope = this._enterFunctionScope(true, statement.params);
|
|
3115
|
+
for (const param of statement.params) {
|
|
3116
|
+
this.walkPattern(param);
|
|
3117
|
+
}
|
|
2932
3118
|
|
|
2933
|
-
|
|
3119
|
+
this.detectMode(statement.body.body);
|
|
2934
3120
|
|
|
2935
|
-
|
|
3121
|
+
const prev = this.prevStatement;
|
|
2936
3122
|
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
3123
|
+
this.preWalkStatement(statement.body);
|
|
3124
|
+
this.prevStatement = prev;
|
|
3125
|
+
this.walkStatement(statement.body);
|
|
3126
|
+
|
|
3127
|
+
this.scope = oldScope;
|
|
2941
3128
|
this.scope.topLevelScope = wasTopLevel;
|
|
2942
3129
|
}
|
|
2943
3130
|
|
|
@@ -3303,7 +3490,9 @@ class JavascriptParser extends Parser {
|
|
|
3303
3490
|
/** @type {OnIdent | undefined} */
|
|
3304
3491
|
let onIdent;
|
|
3305
3492
|
const checkStrictBindings = this._strictInModuleOutput;
|
|
3306
|
-
|
|
3493
|
+
const declarations = statement.declarations;
|
|
3494
|
+
for (let i = 0, len = declarations.length; i < len; i++) {
|
|
3495
|
+
const declarator = declarations[i];
|
|
3307
3496
|
if (declarator.type !== "VariableDeclarator") continue;
|
|
3308
3497
|
this.preWalkVariableDeclarator(declarator);
|
|
3309
3498
|
if (this.hooks.preDeclarator.call(declarator, statement)) continue;
|
|
@@ -3312,7 +3501,7 @@ class JavascriptParser extends Parser {
|
|
|
3312
3501
|
if (checkStrictBindings) this._checkStrictModeBinding(id.name, id);
|
|
3313
3502
|
// fast path: plain `const x =` skips the enterPattern dispatch and
|
|
3314
3503
|
// the per-declaration onIdent closure (only patterns need it)
|
|
3315
|
-
if (!this.
|
|
3504
|
+
if (!this._callHooksForName1(this.hooks.pattern, id.name, id)) {
|
|
3316
3505
|
this._defineVariableForDeclaration(id.name, id, hookMap);
|
|
3317
3506
|
}
|
|
3318
3507
|
} else {
|
|
@@ -3452,7 +3641,9 @@ class JavascriptParser extends Parser {
|
|
|
3452
3641
|
* @param {VariableDeclaration} statement variable declaration
|
|
3453
3642
|
*/
|
|
3454
3643
|
walkVariableDeclaration(statement) {
|
|
3455
|
-
|
|
3644
|
+
const declarations = statement.declarations;
|
|
3645
|
+
for (let i = 0, len = declarations.length; i < len; i++) {
|
|
3646
|
+
const declarator = declarations[i];
|
|
3456
3647
|
switch (declarator.type) {
|
|
3457
3648
|
case "VariableDeclarator": {
|
|
3458
3649
|
const renameIdentifier =
|
|
@@ -3523,40 +3714,35 @@ class JavascriptParser extends Parser {
|
|
|
3523
3714
|
* @param {SwitchCase[]} switchCases switch statement
|
|
3524
3715
|
*/
|
|
3525
3716
|
walkSwitchCases(switchCases) {
|
|
3526
|
-
this.
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
|
|
3538
|
-
const switchCase = switchCases[index];
|
|
3539
|
-
|
|
3540
|
-
if (switchCase.consequent.length > 0) {
|
|
3541
|
-
const prev = this.prevStatement;
|
|
3542
|
-
this.blockPreWalkStatements(switchCase.consequent);
|
|
3543
|
-
this.prevStatement = prev;
|
|
3544
|
-
}
|
|
3717
|
+
const oldScope = this._enterBlockScope();
|
|
3718
|
+
const len = switchCases.length;
|
|
3719
|
+
|
|
3720
|
+
// pre-walk every case first: a `const` declared in a later case is already
|
|
3721
|
+
// in scope for an earlier case that reads it (and fails at runtime)
|
|
3722
|
+
for (let index = 0; index < len; index++) {
|
|
3723
|
+
const switchCase = switchCases[index];
|
|
3724
|
+
|
|
3725
|
+
if (switchCase.consequent.length > 0) {
|
|
3726
|
+
const prev = this.prevStatement;
|
|
3727
|
+
this.blockPreWalkStatements(switchCase.consequent);
|
|
3728
|
+
this.prevStatement = prev;
|
|
3545
3729
|
}
|
|
3730
|
+
}
|
|
3546
3731
|
|
|
3547
|
-
|
|
3548
|
-
|
|
3732
|
+
for (let index = 0; index < len; index++) {
|
|
3733
|
+
const switchCase = switchCases[index];
|
|
3549
3734
|
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3735
|
+
if (switchCase.test) {
|
|
3736
|
+
this.walkExpression(switchCase.test);
|
|
3737
|
+
}
|
|
3553
3738
|
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
}
|
|
3739
|
+
if (switchCase.consequent.length > 0) {
|
|
3740
|
+
this.walkStatements(switchCase.consequent);
|
|
3741
|
+
this.scope.terminated = undefined;
|
|
3558
3742
|
}
|
|
3559
|
-
}
|
|
3743
|
+
}
|
|
3744
|
+
|
|
3745
|
+
this._exitBlockScope(oldScope, false);
|
|
3560
3746
|
}
|
|
3561
3747
|
|
|
3562
3748
|
/**
|
|
@@ -3572,22 +3758,23 @@ class JavascriptParser extends Parser {
|
|
|
3572
3758
|
* @param {CatchClause} catchClause catch clause
|
|
3573
3759
|
*/
|
|
3574
3760
|
walkCatchClause(catchClause) {
|
|
3575
|
-
this.
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3761
|
+
const oldScope = this._enterBlockScope();
|
|
3762
|
+
// Error binding is optional in catch clause since ECMAScript 2019
|
|
3763
|
+
if (catchClause.param !== null) {
|
|
3764
|
+
this.enterPattern(catchClause.param, (ident, identifier) => {
|
|
3765
|
+
if (this._strictInModuleOutput) {
|
|
3766
|
+
this._checkStrictModeBinding(ident, identifier);
|
|
3767
|
+
}
|
|
3768
|
+
this.defineVariable(ident);
|
|
3769
|
+
});
|
|
3770
|
+
this.walkPattern(catchClause.param);
|
|
3771
|
+
}
|
|
3772
|
+
const prev = this.prevStatement;
|
|
3773
|
+
this.blockPreWalkStatement(catchClause.body);
|
|
3774
|
+
this.prevStatement = prev;
|
|
3775
|
+
this.walkStatement(catchClause.body);
|
|
3776
|
+
|
|
3777
|
+
this._exitBlockScope(oldScope, true);
|
|
3591
3778
|
}
|
|
3592
3779
|
|
|
3593
3780
|
/**
|
|
@@ -3885,19 +4072,20 @@ class JavascriptParser extends Parser {
|
|
|
3885
4072
|
this._checkStrictModeBinding(expression.id.name, expression.id);
|
|
3886
4073
|
}
|
|
3887
4074
|
}
|
|
3888
|
-
this.
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
4075
|
+
const oldScope = this._enterFunctionScope(true, scopeParams);
|
|
4076
|
+
for (const param of expression.params) {
|
|
4077
|
+
this.walkPattern(param);
|
|
4078
|
+
}
|
|
3892
4079
|
|
|
3893
|
-
|
|
4080
|
+
this.detectMode(expression.body.body);
|
|
3894
4081
|
|
|
3895
|
-
|
|
4082
|
+
const prev = this.prevStatement;
|
|
3896
4083
|
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
4084
|
+
this.preWalkStatement(expression.body);
|
|
4085
|
+
this.prevStatement = prev;
|
|
4086
|
+
this.walkStatement(expression.body);
|
|
4087
|
+
|
|
4088
|
+
this.scope = oldScope;
|
|
3901
4089
|
this.scope.topLevelScope = wasTopLevel;
|
|
3902
4090
|
}
|
|
3903
4091
|
|
|
@@ -3911,20 +4099,21 @@ class JavascriptParser extends Parser {
|
|
|
3911
4099
|
if (this._strictInModuleOutput) {
|
|
3912
4100
|
this._checkStrictModeParams(expression.params);
|
|
3913
4101
|
}
|
|
3914
|
-
this.
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
4102
|
+
const oldScope = this._enterFunctionScope(false, expression.params);
|
|
4103
|
+
for (const param of expression.params) {
|
|
4104
|
+
this.walkPattern(param);
|
|
4105
|
+
}
|
|
4106
|
+
if (expression.body.type === "BlockStatement") {
|
|
4107
|
+
this.detectMode(expression.body.body);
|
|
4108
|
+
const prev = this.prevStatement;
|
|
4109
|
+
this.preWalkStatement(expression.body);
|
|
4110
|
+
this.prevStatement = prev;
|
|
4111
|
+
this.walkStatement(expression.body);
|
|
4112
|
+
} else {
|
|
4113
|
+
this.walkExpression(expression.body);
|
|
4114
|
+
}
|
|
4115
|
+
|
|
4116
|
+
this.scope = oldScope;
|
|
3928
4117
|
this.scope.topLevelScope = wasTopLevel;
|
|
3929
4118
|
}
|
|
3930
4119
|
|
|
@@ -4185,7 +4374,7 @@ class JavascriptParser extends Parser {
|
|
|
4185
4374
|
const renameIdentifier = this.getRenameIdentifier(expression.right);
|
|
4186
4375
|
if (
|
|
4187
4376
|
renameIdentifier &&
|
|
4188
|
-
this.
|
|
4377
|
+
this._callHooksForInfo1(
|
|
4189
4378
|
this.hooks.canRename,
|
|
4190
4379
|
renameIdentifier,
|
|
4191
4380
|
expression.right
|
|
@@ -4193,7 +4382,7 @@ class JavascriptParser extends Parser {
|
|
|
4193
4382
|
) {
|
|
4194
4383
|
// renaming "a = b;"
|
|
4195
4384
|
if (
|
|
4196
|
-
!this.
|
|
4385
|
+
!this._callHooksForInfo1(
|
|
4197
4386
|
this.hooks.rename,
|
|
4198
4387
|
renameIdentifier,
|
|
4199
4388
|
expression.right
|
|
@@ -4209,34 +4398,42 @@ class JavascriptParser extends Parser {
|
|
|
4209
4398
|
return;
|
|
4210
4399
|
}
|
|
4211
4400
|
this.walkExpression(expression.right);
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4401
|
+
// inlined enterPattern → enterIdentifier for the Identifier left side:
|
|
4402
|
+
// same hook sequence without the per-assignment closure
|
|
4403
|
+
const leftName = expression.left.name;
|
|
4404
|
+
if (
|
|
4405
|
+
!this._callHooksForName1(
|
|
4406
|
+
this.hooks.pattern,
|
|
4407
|
+
leftName,
|
|
4408
|
+
expression.left
|
|
4409
|
+
) &&
|
|
4410
|
+
!this._callHooksForName1(this.hooks.assign, leftName, expression)
|
|
4411
|
+
) {
|
|
4412
|
+
this.walkExpression(expression.left);
|
|
4413
|
+
}
|
|
4220
4414
|
} else if (expression.left.type.endsWith("Pattern")) {
|
|
4221
4415
|
this.walkExpression(expression.right);
|
|
4222
4416
|
this.enterPattern(expression.left, (name, _decl) => {
|
|
4223
|
-
if (!this.
|
|
4417
|
+
if (!this._callHooksForName1(this.hooks.assign, name, expression)) {
|
|
4224
4418
|
this.defineVariable(name);
|
|
4225
4419
|
}
|
|
4226
4420
|
});
|
|
4227
4421
|
this.walkPattern(expression.left);
|
|
4228
4422
|
} else if (expression.left.type === "MemberExpression") {
|
|
4229
|
-
const exprName = this.getMemberExpressionInfo(
|
|
4230
|
-
expression.left,
|
|
4231
|
-
ALLOWED_MEMBER_TYPES_EXPRESSION
|
|
4232
|
-
);
|
|
4233
4423
|
if (
|
|
4234
|
-
|
|
4424
|
+
this._resolveMemberExpression(
|
|
4425
|
+
expression.left,
|
|
4426
|
+
ALLOWED_MEMBER_TYPES_EXPRESSION
|
|
4427
|
+
) === 1 &&
|
|
4428
|
+
this._hasHooksForInfo(
|
|
4429
|
+
this.hooks.assignMemberChain,
|
|
4430
|
+
/** @type {string | VariableInfo} */ (this._memberRootInfo)
|
|
4431
|
+
) &&
|
|
4235
4432
|
this.callHooksForInfo(
|
|
4236
4433
|
this.hooks.assignMemberChain,
|
|
4237
|
-
|
|
4434
|
+
/** @type {string | VariableInfo} */ (this._memberRootInfo),
|
|
4238
4435
|
expression,
|
|
4239
|
-
|
|
4436
|
+
this._members
|
|
4240
4437
|
)
|
|
4241
4438
|
) {
|
|
4242
4439
|
return;
|
|
@@ -4261,15 +4458,24 @@ class JavascriptParser extends Parser {
|
|
|
4261
4458
|
if (result === undefined) {
|
|
4262
4459
|
const guard = this.hooks.collectGuards.call(expression.test);
|
|
4263
4460
|
this.walkExpression(expression.test);
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4461
|
+
// allocate the branch closure only when a guard frame needs pushing
|
|
4462
|
+
if (guard && guard.consequent) {
|
|
4463
|
+
this.walkGuardedBranch(guard.consequent, () =>
|
|
4464
|
+
this.walkExpression(expression.consequent)
|
|
4465
|
+
);
|
|
4466
|
+
} else {
|
|
4467
|
+
this.walkExpression(expression.consequent);
|
|
4468
|
+
}
|
|
4267
4469
|
|
|
4268
4470
|
if (expression.alternate) {
|
|
4269
4471
|
const alternate = expression.alternate;
|
|
4270
|
-
|
|
4271
|
-
this.
|
|
4272
|
-
|
|
4472
|
+
if (guard && guard.alternate) {
|
|
4473
|
+
this.walkGuardedBranch(guard.alternate, () =>
|
|
4474
|
+
this.walkExpression(alternate)
|
|
4475
|
+
);
|
|
4476
|
+
} else {
|
|
4477
|
+
this.walkExpression(alternate);
|
|
4478
|
+
}
|
|
4273
4479
|
}
|
|
4274
4480
|
} else if (result) {
|
|
4275
4481
|
this.walkExpression(expression.consequent);
|
|
@@ -4375,13 +4581,13 @@ class JavascriptParser extends Parser {
|
|
|
4375
4581
|
const renameIdentifier = this.getRenameIdentifier(argOrThis);
|
|
4376
4582
|
if (
|
|
4377
4583
|
renameIdentifier &&
|
|
4378
|
-
this.
|
|
4584
|
+
this._callHooksForInfo1(
|
|
4379
4585
|
this.hooks.canRename,
|
|
4380
4586
|
renameIdentifier,
|
|
4381
4587
|
/** @type {Expression} */
|
|
4382
4588
|
(argOrThis)
|
|
4383
4589
|
) &&
|
|
4384
|
-
!this.
|
|
4590
|
+
!this._callHooksForInfo1(
|
|
4385
4591
|
this.hooks.rename,
|
|
4386
4592
|
renameIdentifier,
|
|
4387
4593
|
/** @type {Expression} */
|
|
@@ -4422,26 +4628,27 @@ class JavascriptParser extends Parser {
|
|
|
4422
4628
|
scopeParams.push(functionExpression.id.name);
|
|
4423
4629
|
}
|
|
4424
4630
|
|
|
4425
|
-
this.
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4631
|
+
const oldScope = this._enterFunctionScope(true, scopeParams);
|
|
4632
|
+
if (renameThis && !arrow) {
|
|
4633
|
+
this.setVariable("this", renameThis);
|
|
4634
|
+
}
|
|
4635
|
+
for (let i = 0; i < varInfoForArgs.length; i++) {
|
|
4636
|
+
const varInfo = varInfoForArgs[i];
|
|
4637
|
+
if (!varInfo) continue;
|
|
4638
|
+
if (!params[i] || params[i].type !== "Identifier") continue;
|
|
4639
|
+
this.setVariable(/** @type {Identifier} */ (params[i]).name, varInfo);
|
|
4640
|
+
}
|
|
4641
|
+
if (functionExpression.body.type === "BlockStatement") {
|
|
4642
|
+
this.detectMode(functionExpression.body.body);
|
|
4643
|
+
const prev = this.prevStatement;
|
|
4644
|
+
this.preWalkStatement(functionExpression.body);
|
|
4645
|
+
this.prevStatement = prev;
|
|
4646
|
+
this.walkStatement(functionExpression.body);
|
|
4647
|
+
} else {
|
|
4648
|
+
this.walkExpression(functionExpression.body);
|
|
4649
|
+
}
|
|
4650
|
+
|
|
4651
|
+
this.scope = oldScope;
|
|
4445
4652
|
this.scope.topLevelScope = wasTopLevel;
|
|
4446
4653
|
}
|
|
4447
4654
|
|
|
@@ -4553,22 +4760,26 @@ class JavascriptParser extends Parser {
|
|
|
4553
4760
|
}
|
|
4554
4761
|
const callee = this.evaluateExpression(expression.callee);
|
|
4555
4762
|
if (callee.isIdentifier()) {
|
|
4556
|
-
const
|
|
4557
|
-
/** @type {NonNullable<BasicEvaluatedExpression["getMembers"]>} */
|
|
4558
|
-
(callee.getMembers)();
|
|
4559
|
-
const result1 = this.callHooksForInfo(
|
|
4560
|
-
this.hooks.callMemberChain,
|
|
4763
|
+
const rootInfo =
|
|
4561
4764
|
/** @type {NonNullable<BasicEvaluatedExpression["rootInfo"]>} */
|
|
4562
|
-
(callee.rootInfo)
|
|
4563
|
-
|
|
4564
|
-
members
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4765
|
+
(callee.rootInfo);
|
|
4766
|
+
if (this._hasHooksForInfo(this.hooks.callMemberChain, rootInfo)) {
|
|
4767
|
+
const members =
|
|
4768
|
+
/** @type {NonNullable<BasicEvaluatedExpression["getMembers"]>} */
|
|
4769
|
+
(callee.getMembers)();
|
|
4770
|
+
const result1 = this.callHooksForInfo(
|
|
4771
|
+
this.hooks.callMemberChain,
|
|
4772
|
+
rootInfo,
|
|
4773
|
+
expression,
|
|
4774
|
+
members,
|
|
4775
|
+
callee.getMembersOptionals
|
|
4776
|
+
? callee.getMembersOptionals()
|
|
4777
|
+
: members.map(RETURN_FALSE),
|
|
4778
|
+
callee.getMemberRanges ? callee.getMemberRanges() : []
|
|
4779
|
+
);
|
|
4780
|
+
if (result1 === true) return;
|
|
4781
|
+
}
|
|
4782
|
+
const result2 = this._callHooksForInfo1(
|
|
4572
4783
|
this.hooks.call,
|
|
4573
4784
|
/** @type {NonNullable<BasicEvaluatedExpression["identifier"]>} */
|
|
4574
4785
|
(callee.identifier),
|
|
@@ -4597,68 +4808,112 @@ class JavascriptParser extends Parser {
|
|
|
4597
4808
|
* @param {MemberExpression} expression member expression
|
|
4598
4809
|
*/
|
|
4599
4810
|
walkMemberExpression(expression) {
|
|
4600
|
-
const
|
|
4811
|
+
const type = this._resolveMemberExpression(
|
|
4601
4812
|
expression,
|
|
4602
4813
|
ALLOWED_MEMBER_TYPES_ALL
|
|
4603
4814
|
);
|
|
4604
|
-
if (
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
exprInfo.rootInfo,
|
|
4629
|
-
[...members],
|
|
4630
|
-
() =>
|
|
4631
|
-
this.callHooksForInfo(
|
|
4632
|
-
this.hooks.unhandledExpressionMemberChain,
|
|
4633
|
-
exprInfo.rootInfo,
|
|
4634
|
-
expression,
|
|
4635
|
-
members
|
|
4636
|
-
)
|
|
4637
|
-
);
|
|
4638
|
-
return;
|
|
4639
|
-
}
|
|
4640
|
-
case "call": {
|
|
4641
|
-
const result = this.callHooksForInfo(
|
|
4642
|
-
this.hooks.memberChainOfCallMemberChain,
|
|
4643
|
-
exprInfo.rootInfo,
|
|
4644
|
-
expression,
|
|
4645
|
-
exprInfo.getCalleeMembers(),
|
|
4646
|
-
exprInfo.call,
|
|
4647
|
-
exprInfo.getMembers(),
|
|
4648
|
-
exprInfo.getMemberRanges()
|
|
4649
|
-
);
|
|
4650
|
-
if (result === true) return;
|
|
4651
|
-
// Fast skip over the member chain as we already called memberChainOfCallMemberChain
|
|
4652
|
-
// and call computed property are literals anyway
|
|
4653
|
-
this.walkExpression(exprInfo.call);
|
|
4654
|
-
return;
|
|
4655
|
-
}
|
|
4815
|
+
if (type === 1) {
|
|
4816
|
+
// copied out first: a hook may resolve another chain and reuse the slots
|
|
4817
|
+
const name = this._memberName;
|
|
4818
|
+
const rootInfo = /** @type {string | VariableInfo} */ (
|
|
4819
|
+
this._memberRootInfo
|
|
4820
|
+
);
|
|
4821
|
+
const members = this._members;
|
|
4822
|
+
const membersOptionals = this._membersOptionals;
|
|
4823
|
+
const result1 = this._callHooksForInfo1(
|
|
4824
|
+
this.hooks.expression,
|
|
4825
|
+
name,
|
|
4826
|
+
expression
|
|
4827
|
+
);
|
|
4828
|
+
if (result1 === true) return;
|
|
4829
|
+
if (this._hasHooksForInfo(this.hooks.expressionMemberChain, rootInfo)) {
|
|
4830
|
+
const result2 = this.callHooksForInfo(
|
|
4831
|
+
this.hooks.expressionMemberChain,
|
|
4832
|
+
rootInfo,
|
|
4833
|
+
expression,
|
|
4834
|
+
members,
|
|
4835
|
+
membersOptionals,
|
|
4836
|
+
memberRangesOf(expression, members.length)
|
|
4837
|
+
);
|
|
4838
|
+
if (result2 === true) return;
|
|
4656
4839
|
}
|
|
4840
|
+
this._walkMemberChain(
|
|
4841
|
+
expression,
|
|
4842
|
+
expression,
|
|
4843
|
+
name,
|
|
4844
|
+
rootInfo,
|
|
4845
|
+
members,
|
|
4846
|
+
members.length
|
|
4847
|
+
);
|
|
4848
|
+
return;
|
|
4849
|
+
}
|
|
4850
|
+
if (type === 2) {
|
|
4851
|
+
const call = /** @type {CallExpression} */ (this._memberCall);
|
|
4852
|
+
const result = this.callHooksForInfo(
|
|
4853
|
+
this.hooks.memberChainOfCallMemberChain,
|
|
4854
|
+
/** @type {string | VariableInfo} */ (this._memberRootInfo),
|
|
4855
|
+
expression,
|
|
4856
|
+
this._memberCalleeMembers,
|
|
4857
|
+
call,
|
|
4858
|
+
this._members,
|
|
4859
|
+
memberRangesOf(expression, this._members.length)
|
|
4860
|
+
);
|
|
4861
|
+
if (result === true) return;
|
|
4862
|
+
// Fast skip over the member chain as we already called memberChainOfCallMemberChain
|
|
4863
|
+
// and call computed property are literals anyway
|
|
4864
|
+
this.walkExpression(call);
|
|
4865
|
+
return;
|
|
4657
4866
|
}
|
|
4658
4867
|
this.walkExpression(expression.object);
|
|
4659
4868
|
if (expression.computed === true) this.walkExpression(expression.property);
|
|
4660
4869
|
}
|
|
4661
4870
|
|
|
4871
|
+
/**
|
|
4872
|
+
* The walk `walkMemberExpressionWithExpressionName` does over a resolved
|
|
4873
|
+
* chain, reading `members` up to `end` instead of popping a copy of it.
|
|
4874
|
+
* @param {MemberExpression} outer the whole chain, for the unhandled hook
|
|
4875
|
+
* @param {MemberExpression} expression the chain from here inwards
|
|
4876
|
+
* @param {string} name name of `expression`
|
|
4877
|
+
* @param {string | VariableInfo} rootInfo root info
|
|
4878
|
+
* @param {Members} members members of the whole chain, in source order
|
|
4879
|
+
* @param {number} end how many of `members` are inside `expression`
|
|
4880
|
+
* @returns {void}
|
|
4881
|
+
*/
|
|
4882
|
+
_walkMemberChain(outer, expression, name, rootInfo, members, end) {
|
|
4883
|
+
if (expression.object.type === "MemberExpression") {
|
|
4884
|
+
const property = members[end - 1];
|
|
4885
|
+
name = name.slice(0, -property.length - 1);
|
|
4886
|
+
const result = this._callHooksForInfo1(
|
|
4887
|
+
this.hooks.expression,
|
|
4888
|
+
name,
|
|
4889
|
+
expression.object
|
|
4890
|
+
);
|
|
4891
|
+
if (result === true) return;
|
|
4892
|
+
this._walkMemberChain(
|
|
4893
|
+
outer,
|
|
4894
|
+
expression.object,
|
|
4895
|
+
name,
|
|
4896
|
+
rootInfo,
|
|
4897
|
+
members,
|
|
4898
|
+
end - 1
|
|
4899
|
+
);
|
|
4900
|
+
} else if (
|
|
4901
|
+
!this._hasHooksForInfo(
|
|
4902
|
+
this.hooks.unhandledExpressionMemberChain,
|
|
4903
|
+
rootInfo
|
|
4904
|
+
) ||
|
|
4905
|
+
!this.callHooksForInfo(
|
|
4906
|
+
this.hooks.unhandledExpressionMemberChain,
|
|
4907
|
+
rootInfo,
|
|
4908
|
+
outer,
|
|
4909
|
+
members
|
|
4910
|
+
)
|
|
4911
|
+
) {
|
|
4912
|
+
this.walkExpression(expression.object);
|
|
4913
|
+
}
|
|
4914
|
+
if (expression.computed === true) this.walkExpression(expression.property);
|
|
4915
|
+
}
|
|
4916
|
+
|
|
4662
4917
|
/**
|
|
4663
4918
|
* Walk member expression with expression name.
|
|
4664
4919
|
* @template R
|
|
@@ -4684,7 +4939,7 @@ class JavascriptParser extends Parser {
|
|
|
4684
4939
|
const property = members[members.length - 1];
|
|
4685
4940
|
name = name.slice(0, -property.length - 1);
|
|
4686
4941
|
members.pop();
|
|
4687
|
-
const result = this.
|
|
4942
|
+
const result = this._callHooksForInfo1(
|
|
4688
4943
|
this.hooks.expression,
|
|
4689
4944
|
name,
|
|
4690
4945
|
expression.object
|
|
@@ -4708,7 +4963,7 @@ class JavascriptParser extends Parser {
|
|
|
4708
4963
|
* @param {ThisExpression} expression this expression
|
|
4709
4964
|
*/
|
|
4710
4965
|
walkThisExpression(expression) {
|
|
4711
|
-
this.
|
|
4966
|
+
this._callHooksForName1(this.hooks.expression, "this", expression);
|
|
4712
4967
|
}
|
|
4713
4968
|
|
|
4714
4969
|
/**
|
|
@@ -4716,7 +4971,7 @@ class JavascriptParser extends Parser {
|
|
|
4716
4971
|
* @param {Identifier} expression identifier
|
|
4717
4972
|
*/
|
|
4718
4973
|
walkIdentifier(expression) {
|
|
4719
|
-
this.
|
|
4974
|
+
this._callHooksForName1(this.hooks.expression, expression.name, expression);
|
|
4720
4975
|
}
|
|
4721
4976
|
|
|
4722
4977
|
/**
|
|
@@ -4882,6 +5137,27 @@ class JavascriptParser extends Parser {
|
|
|
4882
5137
|
}
|
|
4883
5138
|
}
|
|
4884
5139
|
|
|
5140
|
+
/**
|
|
5141
|
+
* Whether `_callHooksForInfo` would call any hook for this info, so a
|
|
5142
|
+
* caller can skip building the arguments for a name nothing taps.
|
|
5143
|
+
* @template T
|
|
5144
|
+
* @template R
|
|
5145
|
+
* @param {HookMap<SyncBailHook<T, R>>} hookMap hooks that would be called
|
|
5146
|
+
* @param {ExportedVariableInfo} info variable info
|
|
5147
|
+
* @returns {boolean} true when a hook is registered for the info
|
|
5148
|
+
*/
|
|
5149
|
+
_hasHooksForInfo(hookMap, info) {
|
|
5150
|
+
if (typeof info === "string") return hookMap.get(info) !== undefined;
|
|
5151
|
+
if (!(info instanceof VariableInfo)) return false;
|
|
5152
|
+
let tagInfo = info.tagInfo;
|
|
5153
|
+
while (tagInfo !== undefined) {
|
|
5154
|
+
if (hookMap.get(tagInfo.tag) !== undefined) return true;
|
|
5155
|
+
tagInfo = tagInfo.next;
|
|
5156
|
+
}
|
|
5157
|
+
if (!info.isFree() && !info.isTagged()) return false;
|
|
5158
|
+
return hookMap.get(/** @type {string} */ (info.name)) !== undefined;
|
|
5159
|
+
}
|
|
5160
|
+
|
|
4885
5161
|
/**
|
|
4886
5162
|
* Call hooks for name with fallback.
|
|
4887
5163
|
* @template T
|
|
@@ -4903,6 +5179,69 @@ class JavascriptParser extends Parser {
|
|
|
4903
5179
|
);
|
|
4904
5180
|
}
|
|
4905
5181
|
|
|
5182
|
+
/**
|
|
5183
|
+
* Single-argument twin of `callHooksForName` (must stay in sync with
|
|
5184
|
+
* `_callHooksForInfo`): every internal dispatch passes exactly one hook
|
|
5185
|
+
* argument, so this skips the rest-array collection and spread call the
|
|
5186
|
+
* generic path pays per identifier.
|
|
5187
|
+
* @template T
|
|
5188
|
+
* @template R
|
|
5189
|
+
* @param {HookMap<SyncBailHook<T, R>>} hookMap hooks that should be called
|
|
5190
|
+
* @param {string} name key in map
|
|
5191
|
+
* @param {AsArray<T>[0]} arg the single hook argument
|
|
5192
|
+
* @returns {R | undefined} result of hook
|
|
5193
|
+
*/
|
|
5194
|
+
_callHooksForName1(hookMap, name, arg) {
|
|
5195
|
+
return this._callHooksForInfo1(hookMap, this.getVariableInfo(name), arg);
|
|
5196
|
+
}
|
|
5197
|
+
|
|
5198
|
+
/**
|
|
5199
|
+
* Single-argument twin of `callHooksForInfo` (must stay in sync with
|
|
5200
|
+
* `_callHooksForInfo`), for the hot dispatch sites that pass one argument
|
|
5201
|
+
* and no fallback/defined callbacks.
|
|
5202
|
+
* @template T
|
|
5203
|
+
* @template R
|
|
5204
|
+
* @param {HookMap<SyncBailHook<T, R>>} hookMap hooks that should be called
|
|
5205
|
+
* @param {ExportedVariableInfo} info variable info
|
|
5206
|
+
* @param {AsArray<T>[0]} arg the single hook argument
|
|
5207
|
+
* @returns {R | undefined} result of hook
|
|
5208
|
+
*/
|
|
5209
|
+
_callHooksForInfo1(hookMap, info, arg) {
|
|
5210
|
+
/** @type {string} */
|
|
5211
|
+
let name;
|
|
5212
|
+
if (typeof info === "string") {
|
|
5213
|
+
name = info;
|
|
5214
|
+
} else {
|
|
5215
|
+
if (!(info instanceof VariableInfo)) {
|
|
5216
|
+
return;
|
|
5217
|
+
}
|
|
5218
|
+
let tagInfo = info.tagInfo;
|
|
5219
|
+
while (tagInfo !== undefined) {
|
|
5220
|
+
const hook =
|
|
5221
|
+
/** @type {SyncBailHook<[AsArray<T>[0]], R> | undefined} */
|
|
5222
|
+
(hookMap.get(tagInfo.tag));
|
|
5223
|
+
if (hook !== undefined) {
|
|
5224
|
+
this.currentTagData = tagInfo.data;
|
|
5225
|
+
const result = hook.call(arg);
|
|
5226
|
+
this.currentTagData = undefined;
|
|
5227
|
+
if (result !== undefined) return result;
|
|
5228
|
+
}
|
|
5229
|
+
tagInfo = tagInfo.next;
|
|
5230
|
+
}
|
|
5231
|
+
if (!info.isFree() && !info.isTagged()) {
|
|
5232
|
+
return;
|
|
5233
|
+
}
|
|
5234
|
+
name = /** @type {string} */ (info.name);
|
|
5235
|
+
}
|
|
5236
|
+
const hook =
|
|
5237
|
+
/** @type {SyncBailHook<[AsArray<T>[0]], R> | undefined} */
|
|
5238
|
+
(hookMap.get(name));
|
|
5239
|
+
if (hook !== undefined) {
|
|
5240
|
+
const result = hook.call(arg);
|
|
5241
|
+
if (result !== undefined) return result;
|
|
5242
|
+
}
|
|
5243
|
+
}
|
|
5244
|
+
|
|
4906
5245
|
/**
|
|
4907
5246
|
* Processes the provided param.
|
|
4908
5247
|
* @deprecated
|
|
@@ -4971,26 +5310,8 @@ class JavascriptParser extends Parser {
|
|
|
4971
5310
|
* @returns {void}
|
|
4972
5311
|
*/
|
|
4973
5312
|
inFunctionScope(hasThis, params, fn) {
|
|
4974
|
-
const oldScope = this.
|
|
4975
|
-
this.scope = {
|
|
4976
|
-
topLevelScope: oldScope.topLevelScope,
|
|
4977
|
-
inTry: false,
|
|
4978
|
-
inShorthand: false,
|
|
4979
|
-
inTaggedTemplateTag: false,
|
|
4980
|
-
isStrict: oldScope.isStrict,
|
|
4981
|
-
isAsmJs: oldScope.isAsmJs,
|
|
4982
|
-
terminated: undefined,
|
|
4983
|
-
definitions: oldScope.definitions.createChild()
|
|
4984
|
-
};
|
|
4985
|
-
|
|
4986
|
-
if (hasThis) {
|
|
4987
|
-
this.undefineVariable("this");
|
|
4988
|
-
}
|
|
4989
|
-
|
|
4990
|
-
this.enterPatterns(params, this._defineVariable);
|
|
4991
|
-
|
|
5313
|
+
const oldScope = this._enterFunctionScope(hasThis, params);
|
|
4992
5314
|
fn();
|
|
4993
|
-
|
|
4994
5315
|
this.scope = oldScope;
|
|
4995
5316
|
}
|
|
4996
5317
|
|
|
@@ -5001,6 +5322,18 @@ class JavascriptParser extends Parser {
|
|
|
5001
5322
|
* @returns {void}
|
|
5002
5323
|
*/
|
|
5003
5324
|
inBlockScope(fn, inExecutedPath = false) {
|
|
5325
|
+
const oldScope = this._enterBlockScope();
|
|
5326
|
+
fn();
|
|
5327
|
+
this._exitBlockScope(oldScope, inExecutedPath);
|
|
5328
|
+
}
|
|
5329
|
+
|
|
5330
|
+
/**
|
|
5331
|
+
* Enters a fresh block scope: the closure-free core of `inBlockScope`, used
|
|
5332
|
+
* directly by the internal walkers so each block does not allocate a
|
|
5333
|
+
* closure and context. Pass the returned scope to `_exitBlockScope`.
|
|
5334
|
+
* @returns {ScopeInfo} the previous scope
|
|
5335
|
+
*/
|
|
5336
|
+
_enterBlockScope() {
|
|
5004
5337
|
const oldScope = this.scope;
|
|
5005
5338
|
this.scope = {
|
|
5006
5339
|
topLevelScope: oldScope.topLevelScope,
|
|
@@ -5012,18 +5345,50 @@ class JavascriptParser extends Parser {
|
|
|
5012
5345
|
terminated: oldScope.terminated,
|
|
5013
5346
|
definitions: oldScope.definitions.createChild()
|
|
5014
5347
|
};
|
|
5348
|
+
return oldScope;
|
|
5349
|
+
}
|
|
5015
5350
|
|
|
5016
|
-
|
|
5017
|
-
|
|
5351
|
+
/**
|
|
5352
|
+
* Leaves a block scope entered with `_enterBlockScope`.
|
|
5353
|
+
* @param {ScopeInfo} oldScope scope returned by `_enterBlockScope`
|
|
5354
|
+
* @param {boolean} inExecutedPath whether termination propagates to the outer scope
|
|
5355
|
+
* @returns {void}
|
|
5356
|
+
*/
|
|
5357
|
+
_exitBlockScope(oldScope, inExecutedPath) {
|
|
5018
5358
|
const terminated = this.scope.terminated;
|
|
5019
|
-
|
|
5020
5359
|
if (inExecutedPath && terminated) {
|
|
5021
5360
|
oldScope.terminated = terminated;
|
|
5022
5361
|
}
|
|
5023
|
-
|
|
5024
5362
|
this.scope = oldScope;
|
|
5025
5363
|
}
|
|
5026
5364
|
|
|
5365
|
+
/**
|
|
5366
|
+
* Enters a fresh function scope: the closure-free core of `inFunctionScope`,
|
|
5367
|
+
* used directly by the internal walkers. Restore `this.scope` to the
|
|
5368
|
+
* returned scope when leaving.
|
|
5369
|
+
* @param {boolean} hasThis true, when this is defined
|
|
5370
|
+
* @param {(Pattern | string)[]} params scope params
|
|
5371
|
+
* @returns {ScopeInfo} the previous scope
|
|
5372
|
+
*/
|
|
5373
|
+
_enterFunctionScope(hasThis, params) {
|
|
5374
|
+
const oldScope = this.scope;
|
|
5375
|
+
this.scope = {
|
|
5376
|
+
topLevelScope: oldScope.topLevelScope,
|
|
5377
|
+
inTry: false,
|
|
5378
|
+
inShorthand: false,
|
|
5379
|
+
inTaggedTemplateTag: false,
|
|
5380
|
+
isStrict: oldScope.isStrict,
|
|
5381
|
+
isAsmJs: oldScope.isAsmJs,
|
|
5382
|
+
terminated: undefined,
|
|
5383
|
+
definitions: oldScope.definitions.createChild()
|
|
5384
|
+
};
|
|
5385
|
+
if (hasThis) {
|
|
5386
|
+
this.undefineVariable("this");
|
|
5387
|
+
}
|
|
5388
|
+
this.enterPatterns(params, this._defineVariable);
|
|
5389
|
+
return oldScope;
|
|
5390
|
+
}
|
|
5391
|
+
|
|
5027
5392
|
/**
|
|
5028
5393
|
* Processes the provided statement.
|
|
5029
5394
|
* @param {(Directive | Statement | ModuleDeclaration)[]} statements statements
|
|
@@ -5103,7 +5468,7 @@ class JavascriptParser extends Parser {
|
|
|
5103
5468
|
* @param {OnIdent} onIdent callback
|
|
5104
5469
|
*/
|
|
5105
5470
|
enterIdentifier(pattern, onIdent) {
|
|
5106
|
-
if (!this.
|
|
5471
|
+
if (!this._callHooksForName1(this.hooks.pattern, pattern.name, pattern)) {
|
|
5107
5472
|
onIdent(pattern.name, pattern);
|
|
5108
5473
|
}
|
|
5109
5474
|
}
|
|
@@ -5408,6 +5773,7 @@ class JavascriptParser extends Parser {
|
|
|
5408
5773
|
this.destructuringAssignmentProperties = undefined;
|
|
5409
5774
|
}
|
|
5410
5775
|
this.hooks.finish.call(ast, comments);
|
|
5776
|
+
this._releaseMemberExpression();
|
|
5411
5777
|
this.scope = oldScope;
|
|
5412
5778
|
this.state = oldState;
|
|
5413
5779
|
this.comments = oldComments;
|
|
@@ -5452,6 +5818,9 @@ class JavascriptParser extends Parser {
|
|
|
5452
5818
|
`(${source})`,
|
|
5453
5819
|
{
|
|
5454
5820
|
sourceType: this.sourceType,
|
|
5821
|
+
// ranges alone take the lazy path, which serves `range` from a
|
|
5822
|
+
// getter and tracks no locations — as the module parse does
|
|
5823
|
+
ranges: true,
|
|
5455
5824
|
importPhases
|
|
5456
5825
|
},
|
|
5457
5826
|
this.options.parse
|
|
@@ -5753,7 +6122,15 @@ class JavascriptParser extends Parser {
|
|
|
5753
6122
|
};
|
|
5754
6123
|
}
|
|
5755
6124
|
}
|
|
5756
|
-
|
|
6125
|
+
const loc = node.loc;
|
|
6126
|
+
if (!loc) {
|
|
6127
|
+
return /** @type {DependencyLocation} */ (/** @type {unknown} */ (loc));
|
|
6128
|
+
}
|
|
6129
|
+
// a plain copy: a foreign parser's location class must not reach the cache
|
|
6130
|
+
return {
|
|
6131
|
+
start: { line: loc.start.line, column: loc.start.column },
|
|
6132
|
+
end: { line: loc.end.line, column: loc.end.column }
|
|
6133
|
+
};
|
|
5757
6134
|
}
|
|
5758
6135
|
|
|
5759
6136
|
/**
|
|
@@ -5995,6 +6372,7 @@ class JavascriptParser extends Parser {
|
|
|
5995
6372
|
});
|
|
5996
6373
|
}
|
|
5997
6374
|
this.scope.definitions.set(name, newInfo);
|
|
6375
|
+
this._memberExpression = undefined;
|
|
5998
6376
|
}
|
|
5999
6377
|
|
|
6000
6378
|
/**
|
|
@@ -6011,6 +6389,7 @@ class JavascriptParser extends Parser {
|
|
|
6011
6389
|
return;
|
|
6012
6390
|
}
|
|
6013
6391
|
this.scope.definitions.set(name, this.scope);
|
|
6392
|
+
this._memberExpression = undefined;
|
|
6014
6393
|
}
|
|
6015
6394
|
|
|
6016
6395
|
/**
|
|
@@ -6019,6 +6398,7 @@ class JavascriptParser extends Parser {
|
|
|
6019
6398
|
*/
|
|
6020
6399
|
undefineVariable(name) {
|
|
6021
6400
|
this.scope.definitions.delete(name);
|
|
6401
|
+
this._memberExpression = undefined;
|
|
6022
6402
|
}
|
|
6023
6403
|
|
|
6024
6404
|
/**
|
|
@@ -6071,6 +6451,7 @@ class JavascriptParser extends Parser {
|
|
|
6071
6451
|
* @returns {void}
|
|
6072
6452
|
*/
|
|
6073
6453
|
setVariable(name, variableInfo) {
|
|
6454
|
+
this._memberExpression = undefined;
|
|
6074
6455
|
if (typeof variableInfo === "string") {
|
|
6075
6456
|
if (variableInfo === name) {
|
|
6076
6457
|
this.scope.definitions.delete(name);
|
|
@@ -6242,69 +6623,219 @@ class JavascriptParser extends Parser {
|
|
|
6242
6623
|
/** @typedef {{ type: "expression", rootInfo: string | VariableInfo, name: string, getMembers: () => Members, getMembersOptionals: () => MembersOptionals, getMemberRanges: () => MemberRanges }} ExpressionExpressionInfo */
|
|
6243
6624
|
|
|
6244
6625
|
/**
|
|
6245
|
-
*
|
|
6626
|
+
* Resolves a member expression into the `_member*` slots, once per node and
|
|
6627
|
+
* scope. Returns 0 when rejected, 1 for an `expression`, 2 for a `call`.
|
|
6246
6628
|
* @param {Expression | Super} expression a member expression
|
|
6247
|
-
* @param {number} allowedTypes which types
|
|
6248
|
-
* @returns {
|
|
6629
|
+
* @param {number} allowedTypes which types may be returned, presented in bit mask
|
|
6630
|
+
* @returns {0 | 1 | 2} the kind resolved
|
|
6249
6631
|
*/
|
|
6250
|
-
|
|
6632
|
+
_resolveMemberExpression(expression, allowedTypes) {
|
|
6633
|
+
if (
|
|
6634
|
+
expression === this._memberExpression &&
|
|
6635
|
+
this._memberScope === this.scope
|
|
6636
|
+
) {
|
|
6637
|
+
const type = this._memberType;
|
|
6638
|
+
if (type !== 0) {
|
|
6639
|
+
// the root kind is a fact of the node; the mask only says whether to report it
|
|
6640
|
+
const bit =
|
|
6641
|
+
type === 2
|
|
6642
|
+
? ALLOWED_MEMBER_TYPES_CALL_EXPRESSION
|
|
6643
|
+
: ALLOWED_MEMBER_TYPES_EXPRESSION;
|
|
6644
|
+
return (allowedTypes & bit) === 0 ? 0 : type;
|
|
6645
|
+
}
|
|
6646
|
+
if ((allowedTypes & ~this._memberMask) === 0) return 0;
|
|
6647
|
+
}
|
|
6648
|
+
this._memberExpression = expression;
|
|
6649
|
+
this._memberScope = this.scope;
|
|
6650
|
+
this._memberMask = allowedTypes;
|
|
6651
|
+
this._memberType = 0;
|
|
6652
|
+
this._memberInfo = undefined;
|
|
6251
6653
|
// Resolve the root first (no allocation); most calls reject here and so
|
|
6252
|
-
// never build the member arrays
|
|
6654
|
+
// never build the member arrays
|
|
6253
6655
|
const object = this.getMemberExpressionRoot(expression);
|
|
6254
6656
|
switch (object.type) {
|
|
6255
6657
|
case "CallExpression": {
|
|
6256
|
-
if ((allowedTypes & ALLOWED_MEMBER_TYPES_CALL_EXPRESSION) === 0)
|
|
6658
|
+
if ((allowedTypes & ALLOWED_MEMBER_TYPES_CALL_EXPRESSION) === 0) {
|
|
6659
|
+
return 0;
|
|
6660
|
+
}
|
|
6257
6661
|
const calleeExpr = object.callee;
|
|
6258
6662
|
const callee =
|
|
6259
6663
|
calleeExpr.type === "MemberExpression"
|
|
6260
6664
|
? this.getMemberExpressionRoot(calleeExpr)
|
|
6261
6665
|
: calleeExpr;
|
|
6262
6666
|
const rootName = getRootName(callee);
|
|
6263
|
-
if (!rootName) return;
|
|
6264
|
-
const
|
|
6265
|
-
if (
|
|
6266
|
-
|
|
6267
|
-
|
|
6268
|
-
|
|
6269
|
-
|
|
6270
|
-
|
|
6271
|
-
|
|
6272
|
-
|
|
6667
|
+
if (!rootName) return this._rejectMemberExpression();
|
|
6668
|
+
const resolvedRoot = this._resolveMemberRoot(rootName);
|
|
6669
|
+
if (resolvedRoot === undefined) return this._rejectMemberExpression();
|
|
6670
|
+
/** @type {CalleeMembers} */
|
|
6671
|
+
let rootMembers = EMPTY_ARRAY;
|
|
6672
|
+
if (calleeExpr.type === "MemberExpression") {
|
|
6673
|
+
this._extractMembers(calleeExpr);
|
|
6674
|
+
rootMembers = this._members;
|
|
6675
|
+
}
|
|
6676
|
+
this._extractMembers(expression);
|
|
6273
6677
|
const calleeName = objectAndMembersToName(resolvedRoot, rootMembers);
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
getMemberRanges: lazyReverse(memberRanges)
|
|
6284
|
-
};
|
|
6678
|
+
this._memberType = 2;
|
|
6679
|
+
this._memberCall = object;
|
|
6680
|
+
this._memberCalleeName = calleeName;
|
|
6681
|
+
this._memberCalleeMembers = rootMembers;
|
|
6682
|
+
this._memberName = objectAndMembersToName(
|
|
6683
|
+
`${calleeName}()`,
|
|
6684
|
+
this._members
|
|
6685
|
+
);
|
|
6686
|
+
return 2;
|
|
6285
6687
|
}
|
|
6286
6688
|
case "Identifier":
|
|
6287
6689
|
case "MetaProperty":
|
|
6288
6690
|
case "ThisExpression": {
|
|
6289
|
-
if ((allowedTypes & ALLOWED_MEMBER_TYPES_EXPRESSION) === 0) return;
|
|
6691
|
+
if ((allowedTypes & ALLOWED_MEMBER_TYPES_EXPRESSION) === 0) return 0;
|
|
6290
6692
|
const rootName = getRootName(object);
|
|
6291
|
-
if (!rootName) return;
|
|
6693
|
+
if (!rootName) return this._rejectMemberExpression();
|
|
6694
|
+
const resolvedRoot = this._resolveMemberRoot(rootName);
|
|
6695
|
+
if (resolvedRoot === undefined) return this._rejectMemberExpression();
|
|
6696
|
+
this._extractMembers(expression);
|
|
6697
|
+
this._memberType = 1;
|
|
6698
|
+
this._memberName = objectAndMembersToName(resolvedRoot, this._members);
|
|
6699
|
+
return 1;
|
|
6700
|
+
}
|
|
6701
|
+
}
|
|
6702
|
+
return this._rejectMemberExpression();
|
|
6703
|
+
}
|
|
6292
6704
|
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
6705
|
+
/**
|
|
6706
|
+
* Records that the node resolves to nothing under any mask.
|
|
6707
|
+
* @returns {0} rejected
|
|
6708
|
+
*/
|
|
6709
|
+
_rejectMemberExpression() {
|
|
6710
|
+
this._memberMask = ALLOWED_MEMBER_TYPES_ALL;
|
|
6711
|
+
return 0;
|
|
6712
|
+
}
|
|
6713
|
+
|
|
6714
|
+
/**
|
|
6715
|
+
* `getNameInfoFromVariable` for the resolver: stores the info in
|
|
6716
|
+
* `_memberRootInfo` and returns the name, or undefined when rejected.
|
|
6717
|
+
* @param {string} rootName name of the root variable
|
|
6718
|
+
* @returns {string | undefined} the resolved root name
|
|
6719
|
+
*/
|
|
6720
|
+
_resolveMemberRoot(rootName) {
|
|
6721
|
+
const info = this.getVariableInfo(rootName);
|
|
6722
|
+
if (info instanceof VariableInfo && info.name) {
|
|
6723
|
+
if (!info.isFree() && !info.isTagged()) return;
|
|
6724
|
+
this._memberRootInfo = info;
|
|
6725
|
+
return info.name;
|
|
6726
|
+
}
|
|
6727
|
+
if (typeof info !== "string") return;
|
|
6728
|
+
this._memberRootInfo = info;
|
|
6729
|
+
return info;
|
|
6730
|
+
}
|
|
6731
|
+
|
|
6732
|
+
/**
|
|
6733
|
+
* Fills `_members` and `_membersOptionals` for the chain, in source order.
|
|
6734
|
+
* @param {Expression | Super} expression a member expression
|
|
6735
|
+
* @returns {void}
|
|
6736
|
+
*/
|
|
6737
|
+
_extractMembers(expression) {
|
|
6738
|
+
/** @type {Node} */
|
|
6739
|
+
let expr = expression;
|
|
6740
|
+
/** @type {Members} */
|
|
6741
|
+
const members = [];
|
|
6742
|
+
/** @type {MembersOptionals} */
|
|
6743
|
+
const membersOptionals = [];
|
|
6744
|
+
while (expr.type === "MemberExpression") {
|
|
6745
|
+
if (expr.computed) {
|
|
6746
|
+
const prop = expr.property;
|
|
6747
|
+
if (prop.type === "Literal") {
|
|
6748
|
+
members.push(`${prop.value}`);
|
|
6749
|
+
} else if (
|
|
6750
|
+
prop.type === "TemplateLiteral" &&
|
|
6751
|
+
prop.expressions.length === 0 &&
|
|
6752
|
+
typeof prop.quasis[0].value.cooked === "string"
|
|
6753
|
+
) {
|
|
6754
|
+
members.push(prop.quasis[0].value.cooked);
|
|
6755
|
+
} else {
|
|
6756
|
+
break;
|
|
6757
|
+
}
|
|
6758
|
+
} else {
|
|
6759
|
+
if (expr.property.type !== "Identifier") break;
|
|
6760
|
+
members.push(expr.property.name);
|
|
6306
6761
|
}
|
|
6762
|
+
membersOptionals.push(expr.optional);
|
|
6763
|
+
expr = expr.object;
|
|
6764
|
+
}
|
|
6765
|
+
if (members.length > 1) {
|
|
6766
|
+
members.reverse();
|
|
6767
|
+
membersOptionals.reverse();
|
|
6768
|
+
}
|
|
6769
|
+
this._members = members;
|
|
6770
|
+
this._membersOptionals = membersOptionals;
|
|
6771
|
+
}
|
|
6772
|
+
|
|
6773
|
+
/**
|
|
6774
|
+
* Drops the resolved member expression, so no AST outlives its parse.
|
|
6775
|
+
* @returns {void}
|
|
6776
|
+
*/
|
|
6777
|
+
_releaseMemberExpression() {
|
|
6778
|
+
this._memberExpression = undefined;
|
|
6779
|
+
this._memberScope = undefined;
|
|
6780
|
+
this._memberType = 0;
|
|
6781
|
+
this._memberRootInfo = undefined;
|
|
6782
|
+
this._members = EMPTY_ARRAY;
|
|
6783
|
+
this._membersOptionals = EMPTY_MEMBERS_OPTIONALS;
|
|
6784
|
+
this._memberCall = undefined;
|
|
6785
|
+
this._memberCalleeMembers = EMPTY_ARRAY;
|
|
6786
|
+
this._memberInfo = undefined;
|
|
6787
|
+
}
|
|
6788
|
+
|
|
6789
|
+
/**
|
|
6790
|
+
* Gets member expression info.
|
|
6791
|
+
* @param {Expression | Super} expression a member expression
|
|
6792
|
+
* @param {number} allowedTypes which types should be returned, presented in bit mask
|
|
6793
|
+
* @returns {CallExpressionInfo | ExpressionExpressionInfo | undefined} expression info
|
|
6794
|
+
*/
|
|
6795
|
+
getMemberExpressionInfo(expression, allowedTypes) {
|
|
6796
|
+
const type = this._resolveMemberExpression(expression, allowedTypes);
|
|
6797
|
+
if (type === 0) return;
|
|
6798
|
+
const cached = this._memberInfo;
|
|
6799
|
+
if (cached !== undefined) return cached;
|
|
6800
|
+
const members = this._members;
|
|
6801
|
+
const membersOptionals = this._membersOptionals;
|
|
6802
|
+
/** @type {MemberRanges | undefined} */
|
|
6803
|
+
let memberRanges;
|
|
6804
|
+
const getMembers = () => members;
|
|
6805
|
+
const getMembersOptionals = () => membersOptionals;
|
|
6806
|
+
const getMemberRanges = () =>
|
|
6807
|
+
memberRanges ||
|
|
6808
|
+
(memberRanges = memberRangesOf(expression, members.length));
|
|
6809
|
+
const rootInfo = /** @type {string | VariableInfo} */ (
|
|
6810
|
+
this._memberRootInfo
|
|
6811
|
+
);
|
|
6812
|
+
/** @type {CallExpressionInfo | ExpressionExpressionInfo} */
|
|
6813
|
+
let info;
|
|
6814
|
+
if (type === 2) {
|
|
6815
|
+
const calleeMembers = this._memberCalleeMembers;
|
|
6816
|
+
info = {
|
|
6817
|
+
type: "call",
|
|
6818
|
+
call: /** @type {CallExpression} */ (this._memberCall),
|
|
6819
|
+
calleeName: this._memberCalleeName,
|
|
6820
|
+
rootInfo,
|
|
6821
|
+
getCalleeMembers: () => calleeMembers,
|
|
6822
|
+
name: this._memberName,
|
|
6823
|
+
getMembers,
|
|
6824
|
+
getMembersOptionals,
|
|
6825
|
+
getMemberRanges
|
|
6826
|
+
};
|
|
6827
|
+
} else {
|
|
6828
|
+
info = {
|
|
6829
|
+
type: "expression",
|
|
6830
|
+
name: this._memberName,
|
|
6831
|
+
rootInfo,
|
|
6832
|
+
getMembers,
|
|
6833
|
+
getMembersOptionals,
|
|
6834
|
+
getMemberRanges
|
|
6835
|
+
};
|
|
6307
6836
|
}
|
|
6837
|
+
this._memberInfo = info;
|
|
6838
|
+
return info;
|
|
6308
6839
|
}
|
|
6309
6840
|
|
|
6310
6841
|
/**
|
|
@@ -6373,7 +6904,10 @@ class JavascriptParser extends Parser {
|
|
|
6373
6904
|
// syntax so `auto` avoids a second full parse in the common case
|
|
6374
6905
|
parserOptions.moduleFallback = type === "auto";
|
|
6375
6906
|
}
|
|
6376
|
-
|
|
6907
|
+
// `locations` are acorn's to track, so the lazy path serves the callers
|
|
6908
|
+
// that ask for ranges alone — which is every one inside webpack
|
|
6909
|
+
const wantLazyNodes =
|
|
6910
|
+
parserOptions.ranges === true && parserOptions.locations !== true;
|
|
6377
6911
|
/**
|
|
6378
6912
|
* Returns parse result.
|
|
6379
6913
|
* @param {string} code source code
|
|
@@ -6388,34 +6922,27 @@ class JavascriptParser extends Parser {
|
|
|
6388
6922
|
/** @type {Comment[]} */
|
|
6389
6923
|
const comments = [];
|
|
6390
6924
|
|
|
6391
|
-
//
|
|
6392
|
-
//
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
options.lazyNodes = wantRanges;
|
|
6396
|
-
if (wantRanges) {
|
|
6925
|
+
// Ranges alone (the main parse path and the concatenation re-parse) are
|
|
6926
|
+
// served on demand; hoisted, since the auto-fallback re-enters here.
|
|
6927
|
+
options.lazyNodes = wantLazyNodes;
|
|
6928
|
+
if (wantLazyNodes) {
|
|
6397
6929
|
// the lazy plugin replaces acorn's native tracking — disabling it
|
|
6398
6930
|
// here lets WebpackParser skip its defensive options copy
|
|
6399
|
-
options.locations = false;
|
|
6400
6931
|
options.ranges = false;
|
|
6401
6932
|
}
|
|
6402
6933
|
|
|
6403
6934
|
if (options.comments) {
|
|
6404
|
-
if (
|
|
6935
|
+
if (wantLazyNodes) {
|
|
6405
6936
|
// the parser plugin collects the comments itself, deferring the
|
|
6406
6937
|
// text slice until some hook actually reads `value`
|
|
6407
6938
|
options.lazyComments = comments;
|
|
6408
6939
|
} else {
|
|
6409
|
-
/** @type {
|
|
6410
|
-
(options).onComment =
|
|
6411
|
-
/** @type {import("acorn").Comment[]} */
|
|
6412
|
-
(/** @type {unknown} */ (comments));
|
|
6940
|
+
/** @type {ParserOptions} */
|
|
6941
|
+
(options).onComment = comments;
|
|
6413
6942
|
}
|
|
6414
6943
|
}
|
|
6415
6944
|
|
|
6416
|
-
const ast =
|
|
6417
|
-
/** @type {Program} */
|
|
6418
|
-
(parser.parse(code, /** @type {AcornOptions} */ (options)));
|
|
6945
|
+
const ast = /** @type {Program} */ (parser.parse(code, options));
|
|
6419
6946
|
|
|
6420
6947
|
return { ast, comments };
|
|
6421
6948
|
};
|
|
@@ -6451,7 +6978,7 @@ class JavascriptParser extends Parser {
|
|
|
6451
6978
|
// release per-parse state retained on the (possibly reused) options
|
|
6452
6979
|
// object — the comments array retains source text slices
|
|
6453
6980
|
parserOptions.lazyComments = undefined;
|
|
6454
|
-
/** @type {
|
|
6981
|
+
/** @type {ParserOptions} */
|
|
6455
6982
|
(parserOptions).onComment = undefined;
|
|
6456
6983
|
|
|
6457
6984
|
if (threw) {
|
|
@@ -6463,7 +6990,7 @@ class JavascriptParser extends Parser {
|
|
|
6463
6990
|
|
|
6464
6991
|
/**
|
|
6465
6992
|
* Returns parser.
|
|
6466
|
-
* @param {
|
|
6993
|
+
* @param {ParserPlugin[]} plugins parser plugin
|
|
6467
6994
|
* @returns {typeof JavascriptParser} parser
|
|
6468
6995
|
*/
|
|
6469
6996
|
static extend(...plugins) {
|