@depup/webpack 5.110.3-depup.0 → 5.111.1-depup.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 +7 -8
- package/changes.json +7 -11
- package/lib/APIPlugin.js +26 -11
- package/lib/AutomaticPrefetchPlugin.js +1 -1
- package/lib/Cache.js +8 -3
- package/lib/CacheFacade.js +1 -1
- package/lib/CircularModulesPlugin.js +157 -55
- package/lib/CleanPlugin.js +2 -2
- package/lib/CompatibilityPlugin.js +3 -4
- package/lib/Compilation.js +336 -337
- package/lib/Compiler.js +213 -51
- package/lib/ConstPlugin.js +16 -132
- package/lib/CopyPlugin.js +1054 -0
- package/lib/DefinePlugin.js +24 -8
- package/lib/DependencyTemplate.js +2 -1
- package/lib/DotenvPlugin.js +24 -28
- package/lib/ErrorHelpers.js +113 -0
- package/lib/ExportsInfo.js +20 -16
- package/lib/ExternalModule.js +47 -22
- package/lib/FileSystemInfo.js +17 -14
- package/lib/FlagDependencyExportsPlugin.js +53 -34
- package/lib/FlagDependencyUsagePlugin.js +9 -13
- package/lib/Generator.js +24 -2
- package/lib/HotModuleReplacementPlugin.js +55 -7
- package/lib/IgnorePlugin.js +1 -1
- package/lib/JavascriptMetaInfoPlugin.js +5 -3
- package/lib/LoaderOptionsPlugin.js +1 -1
- package/lib/MainTemplate.js +5 -1
- package/lib/Module.js +19 -10
- package/lib/ModuleGraph.js +6 -9
- package/lib/MultiCompiler.js +7 -17
- package/lib/MultiWatching.js +1 -1
- package/lib/NormalModule.js +135 -50
- package/lib/NormalModuleFactory.js +1 -1
- package/lib/RuntimeGlobals.js +21 -7
- package/lib/RuntimeModule.js +28 -12
- package/lib/RuntimePlugin.js +30 -3
- package/lib/RuntimeTemplate.js +813 -518
- package/lib/SourceMapDevToolPlugin.js +54 -104
- package/lib/TemplatedPathPlugin.js +16 -59
- package/lib/Watching.js +9 -0
- package/lib/WebpackOptionsApply.js +84 -91
- package/lib/asset/AssetBytesGenerator.js +7 -1
- package/lib/asset/AssetGenerator.js +50 -24
- package/lib/asset/AssetModule.js +3 -0
- package/lib/asset/AssetSourceGenerator.js +7 -1
- package/lib/asset/WebManifestParser.js +7 -5
- package/lib/buildChunkGraph.js +11 -15
- package/lib/cache/AddBuildDependenciesPlugin.js +33 -4
- package/lib/cache/IdleFileCachePlugin.js +2 -2
- package/lib/cache/MemoryCachePlugin.js +4 -4
- package/lib/cache/MemoryWithGcCachePlugin.js +7 -8
- package/lib/cache/PackFileCacheStrategy.js +17 -19
- package/lib/cache/getLazyHashedEtag.js +3 -5
- package/lib/config/browserslistTargetHandler.js +17 -4
- package/lib/config/defaults.js +138 -128
- package/lib/config/getClaimedAssetTypes.js +10 -11
- package/lib/config/normalization.js +82 -12
- package/lib/config/target.js +13 -4
- package/lib/container/ContainerReferencePlugin.js +6 -0
- package/lib/container/RemoteRuntimeModule.js +9 -0
- package/lib/container/declaredRemotes.js +39 -0
- package/lib/{ContextExclusionPlugin.js → context/ContextExclusionPlugin.js} +1 -1
- package/lib/{ContextModule.js → context/ContextModule.js} +54 -115
- package/lib/{ContextModuleFactory.js → context/ContextModuleFactory.js} +19 -21
- package/lib/{ContextReplacementPlugin.js → context/ContextReplacementPlugin.js} +4 -4
- package/lib/css/CssGenerator.js +27 -11
- 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 +162 -31
- package/lib/css/CssServerStylesRuntimeModule.js +9 -0
- package/lib/css/cssMinify.js +43 -32
- package/lib/css/data.js +3514 -869
- package/lib/css/syntax.js +6370 -1220
- package/lib/debug/ProfilingPlugin.js +7 -4
- package/lib/dependencies/AMDDefineDependencyParserPlugin.js +6 -3
- package/lib/dependencies/AMDRuntimeModules.js +18 -0
- package/lib/dependencies/CommonJsExportRequireDependency.js +13 -12
- package/lib/dependencies/CommonJsExportsParserPlugin.js +12 -13
- package/lib/dependencies/CommonJsImportsParserPlugin.js +5 -5
- package/lib/dependencies/CommonJsPlugin.js +19 -3
- package/lib/dependencies/CommonJsRequireDependency.js +14 -5
- package/lib/dependencies/CommonJsSelfReferenceDependency.js +2 -4
- package/lib/dependencies/ContextDependency.js +1 -1
- package/lib/dependencies/ContextDependencyHelpers.js +3 -9
- package/lib/dependencies/ContextElementDependency.js +1 -1
- package/lib/dependencies/CssIcssExportDependency.js +13 -9
- package/lib/dependencies/CssIcssImportDependency.js +3 -6
- package/lib/dependencies/CssUrlDependency.js +3 -5
- package/lib/dependencies/HarmonyCompatibilityDependency.js +67 -22
- package/lib/dependencies/HarmonyDetectionParserPlugin.js +3 -4
- package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +10 -7
- package/lib/dependencies/HarmonyExportExpressionDependency.js +47 -33
- package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +74 -17
- package/lib/dependencies/HarmonyExportInitFragment.js +110 -23
- package/lib/dependencies/HarmonyExportSpecifierDependency.js +25 -58
- package/lib/dependencies/HarmonyImportBareSideEffectDependency.js +59 -0
- package/lib/dependencies/HarmonyImportDependency.js +6 -1
- package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +111 -17
- package/lib/dependencies/HarmonyImportSideEffectDependency.js +3 -4
- package/lib/dependencies/HarmonyImportSpecifierDependency.js +40 -3
- package/lib/dependencies/HarmonyModulesPlugin.js +20 -0
- package/lib/dependencies/HtmlEntryDependency.js +124 -102
- package/lib/dependencies/HtmlInlineScriptDependency.js +3 -4
- package/lib/dependencies/HtmlInlineStyleDependency.js +3 -4
- package/lib/dependencies/ImportMetaContextDependencyParserPlugin.js +1 -1
- package/lib/dependencies/ImportMetaGlobHelpers.js +1 -1
- package/lib/dependencies/ImportMetaMainDependency.js +104 -0
- package/lib/dependencies/ImportMetaPlugin.js +67 -25
- package/lib/dependencies/ImportParserPlugin.js +1 -1
- package/lib/dependencies/LoaderPlugin.js +26 -1
- package/lib/dependencies/RequireContextDependencyParserPlugin.js +1 -1
- package/lib/dependencies/SystemRuntimeModule.js +9 -0
- package/lib/dependencies/URLContextDependency.js +1 -1
- package/lib/dependencies/URLDependency.js +6 -5
- package/lib/dependencies/WorkerAndWorkletPlugin.js +15 -21
- package/lib/dependencies/WorkerDependency.js +7 -7
- package/lib/dependencies/WorkletDependency.js +7 -11
- 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/DuplicateModulesWarning.js +12 -7
- package/lib/errors/EmptyCopyPatternWarning.js +26 -0
- package/lib/errors/ExternalStarReexportError.js +44 -0
- package/lib/errors/HookWebpackError.js +3 -2
- 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/hmr/LazyCompilationPlugin.js +3 -5
- package/lib/html/HtmlGenerator.js +72 -87
- package/lib/html/HtmlModulesPlugin.js +418 -200
- package/lib/html/HtmlParser.js +110 -147
- package/lib/html/builtinEmbeddedRenderer.js +107 -0
- package/lib/html/data.js +142 -7
- package/lib/html/htmlMinify.js +92 -122
- package/lib/html/syntax.js +1618 -1391
- package/lib/ids/HashedModuleIdsPlugin.js +2 -1
- package/lib/index.js +49 -3
- package/lib/javascript/ChunkFormatHelpers.js +4 -3
- package/lib/javascript/JavascriptGenerator.js +8 -1
- package/lib/javascript/JavascriptModule.js +1 -0
- package/lib/javascript/JavascriptModulesPlugin.js +73 -72
- package/lib/javascript/JavascriptParser.js +1970 -900
- 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 +1500 -0
- package/lib/javascript/regexp.js +1762 -0
- package/lib/javascript/regexpData.js +51 -0
- package/lib/javascript/syntax.js +9061 -5262
- package/lib/json/JsonGenerator.js +7 -1
- package/lib/library/ModuleLibraryPlugin.js +171 -132
- package/lib/loaders/LoaderRunner.js +137 -9
- package/lib/node/NodeWatchFileSystem.js +3 -9
- package/lib/node/ReadFileChunkLoadingRuntimeModule.js +22 -0
- package/lib/node/RequireChunkLoadingRuntimeModule.js +22 -0
- package/lib/optimize/AggressiveMergingPlugin.js +3 -5
- package/lib/optimize/ConcatenatedModule.js +178 -120
- package/lib/optimize/ConstExportsPlugin.js +50 -39
- package/lib/optimize/FlagIncludedChunksPlugin.js +3 -11
- package/lib/optimize/InlineExports.js +20 -123
- package/lib/optimize/InnerGraphPlugin.js +7 -13
- package/lib/optimize/LimitChunkCountPlugin.js +5 -8
- package/lib/optimize/MangleExportsPlugin.js +13 -4
- package/lib/optimize/ModuleConcatenationPlugin.js +27 -5
- package/lib/optimize/RealContentHashPlugin.js +68 -9
- package/lib/optimize/SideEffectsFlagPlugin.js +24 -28
- package/lib/optimize/SplitChunksPlugin.js +2 -4
- package/lib/performance/AnalyzableBailoutsPlugin.js +115 -0
- package/lib/performance/BroadContextsPlugin.js +1 -1
- package/lib/performance/CacheEffectivenessPlugin.js +7 -7
- 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/SizeLimitsPlugin.js +2 -4
- 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 +8 -8
- 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 +18 -23
- package/lib/prefetch/ResourceHintRuntimeModule.js +9 -0
- package/lib/prefetch/StartupAssetHintRuntimeModule.js +16 -10
- package/lib/rules/RuleSetCompiler.js +211 -4
- package/lib/runtime/AsyncModuleRuntimeModule.js +98 -66
- 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 +12 -4
- 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 +11 -4
- package/lib/runtime/HasOwnPropertyRuntimeModule.js +9 -0
- package/lib/runtime/HelperRuntimeModule.js +10 -0
- package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +305 -224
- 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/DataUriPlugin.js +3 -6
- package/lib/schemes/VirtualUrlPlugin.js +1 -1
- package/lib/serialization/BinaryMiddleware.js +9 -9
- package/lib/serialization/FileMiddleware.js +16 -16
- package/lib/serialization/ObjectMiddleware.js +168 -139
- 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 +6 -5
- package/lib/stats/DefaultStatsPrinterPlugin.js +3 -0
- package/lib/typescript/TypeScriptPlugin.js +2 -3
- package/lib/url/URLParserPlugin.js +6 -8
- package/lib/util/LocConverter.js +4 -7
- package/lib/util/SourceProcessor.js +91 -91
- package/lib/util/async.js +292 -0
- package/lib/util/buildDiagnostics.js +69 -0
- package/lib/util/chainedImports.js +3 -4
- package/lib/util/concatenate.js +4 -4
- package/lib/util/createHooksRegistry.js +1 -2
- package/lib/util/dataURL.js +2 -3
- package/lib/util/deterministicGrouping.js +8 -13
- package/lib/util/findGraphRoots.js +6 -13
- package/lib/util/fs.js +27 -1
- package/lib/util/globUtils.js +1 -1
- package/lib/util/handlerKeys.js +40 -0
- package/lib/util/hash/wasm-hash.js +3 -4
- package/lib/util/identifier.js +20 -0
- package/lib/util/internalSerializables.js +5 -1
- package/lib/util/registerExternalSerializer.js +6 -45
- package/lib/util/semver.js +5 -3
- package/lib/wasm-async/AsyncWasmCompileRuntimeModule.js +9 -0
- package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +9 -0
- package/lib/wasm-async/AsyncWebAssemblyGenerator.js +6 -1
- package/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js +5 -1
- package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +12 -4
- package/lib/wasm-sync/WebAssemblyGenerator.js +6 -1
- package/lib/wasm-sync/WebAssemblyJavascriptGenerator.js +5 -1
- package/lib/wasm-sync/WebAssemblyUtils.js +2 -4
- package/lib/web/JsonpChunkLoadingRuntimeModule.js +36 -0
- package/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js +19 -0
- package/package.json +55 -46
- package/schemas/WebpackOptions.check.js +1 -1
- package/schemas/WebpackOptions.json +379 -66
- 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 +1723 -604
- package/lib/dependencies/ExportBindingInitFragment.js +0 -191
- package/lib/errors/EntrypointOverlapWarning.js +0 -45
- package/lib/performance/EntrypointOverlapPlugin.js +0 -122
|
@@ -17,22 +17,23 @@ const {
|
|
|
17
17
|
parseCommentOptionsInRange
|
|
18
18
|
} = require("../util/magicComment");
|
|
19
19
|
const BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
|
|
20
|
+
const { nonASCIIwhitespace } = require("./parser");
|
|
20
21
|
const {
|
|
22
|
+
BLOCK_DECLARATIONS,
|
|
23
|
+
HOISTED_DECLARATIONS,
|
|
21
24
|
LEGACY_ASSERT_ATTRIBUTES,
|
|
25
|
+
MAX_MASKED_INDEX,
|
|
26
|
+
MODULE_DECLARATIONS,
|
|
22
27
|
WebpackParser,
|
|
23
28
|
buildLineStarts,
|
|
29
|
+
declaresIntoBlock,
|
|
24
30
|
hasOctalEscape,
|
|
25
31
|
isIdentifierChar,
|
|
32
|
+
overflowFrom,
|
|
26
33
|
positionAt
|
|
27
34
|
} = require("./syntax");
|
|
28
35
|
|
|
29
|
-
/** @
|
|
30
|
-
/**
|
|
31
|
-
* @import {
|
|
32
|
-
* Options as AcornOptions,
|
|
33
|
-
* ecmaVersion as EcmaVersion
|
|
34
|
-
* } from "acorn"
|
|
35
|
-
*/
|
|
36
|
+
/** @import { EcmaVersion, ParserOptions, ParserPlugin } from "./syntax" */
|
|
36
37
|
/**
|
|
37
38
|
* @import {
|
|
38
39
|
* AssignmentExpression,
|
|
@@ -143,6 +144,9 @@ const {
|
|
|
143
144
|
/** @typedef {(ident: string) => void} OnIdentString */
|
|
144
145
|
/** @typedef {(ident: string, identifier: Identifier) => void} OnIdent */
|
|
145
146
|
/** @typedef {StatementPathItem[]} StatementPath */
|
|
147
|
+
/** @typedef {(Statement | ModuleDeclaration)[]} HoistedDeclarations the declarations one scope hoists, in source order */
|
|
148
|
+
/** @typedef {(ModuleDeclaration | Statement | undefined)[]} ModuleDeclarations the program's import and re-export declarations in source order, each followed by the statement written before it */
|
|
149
|
+
/** @typedef {number | number[]} BlockDeclarations which statements of one list declare into its block scope: a mask of their indices, or the indices themselves once one is too large to mask */
|
|
146
150
|
|
|
147
151
|
/** @typedef {Set<DestructuringAssignmentProperty>} DestructuringAssignmentProperties */
|
|
148
152
|
|
|
@@ -151,25 +155,34 @@ const {
|
|
|
151
155
|
|
|
152
156
|
/** @type {string[]} */
|
|
153
157
|
const EMPTY_ARRAY = [];
|
|
158
|
+
/** @type {HoistedDeclarations} */
|
|
159
|
+
const EMPTY_HOISTED_DECLARATIONS = [];
|
|
160
|
+
// what the module pass reports; `export default` is the block pass's
|
|
161
|
+
const MODULE_STATEMENT_TYPES = new Set([
|
|
162
|
+
"ImportDeclaration",
|
|
163
|
+
"ExportNamedDeclaration",
|
|
164
|
+
"ExportAllDeclaration"
|
|
165
|
+
]);
|
|
166
|
+
// what the parser records per scope, and so what the hoisting pass reaches
|
|
167
|
+
const RECORDED_STATEMENT_TYPES = new Set([
|
|
168
|
+
"VariableDeclaration",
|
|
169
|
+
"FunctionDeclaration",
|
|
170
|
+
"ClassDeclaration"
|
|
171
|
+
]);
|
|
172
|
+
/** @type {ModuleDeclarations} */
|
|
173
|
+
const EMPTY_MODULE_DECLARATIONS = [];
|
|
174
|
+
// what the parser records per statement list, and so what the block pass
|
|
175
|
+
// reaches. An expression statement is recorded only when it assigns to an
|
|
176
|
+
// object pattern, so a tap on that type is not served from the list.
|
|
177
|
+
const BLOCK_DECLARATION_TYPES = new Set([
|
|
178
|
+
"VariableDeclaration",
|
|
179
|
+
"ClassDeclaration",
|
|
180
|
+
"ExportNamedDeclaration",
|
|
181
|
+
"ExportDefaultDeclaration"
|
|
182
|
+
]);
|
|
154
183
|
|
|
155
|
-
/**
|
|
156
|
-
|
|
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
|
-
};
|
|
184
|
+
/** @type {MembersOptionals} */
|
|
185
|
+
const EMPTY_MEMBERS_OPTIONALS = [];
|
|
173
186
|
|
|
174
187
|
const ALLOWED_MEMBER_TYPES_CALL_EXPRESSION = 0b01;
|
|
175
188
|
const ALLOWED_MEMBER_TYPES_EXPRESSION = 0b10;
|
|
@@ -183,8 +196,11 @@ const RETURN_FALSE = () => false;
|
|
|
183
196
|
// replacing three fresh closures per evaluated free variable.
|
|
184
197
|
const RETURN_EMPTY_ARRAY = () => [];
|
|
185
198
|
|
|
199
|
+
// Shared no-result fallback for the identifier evaluators.
|
|
200
|
+
const RETURN_UNDEFINED = () => undefined;
|
|
201
|
+
|
|
186
202
|
// Syntax: https://developer.mozilla.org/en/SpiderMonkey/Parser_API
|
|
187
|
-
let parser =
|
|
203
|
+
let parser = WebpackParser;
|
|
188
204
|
|
|
189
205
|
/** @typedef {Record<string, string> & { _isLegacyAssert?: boolean }} ImportAttributes */
|
|
190
206
|
|
|
@@ -327,7 +343,7 @@ class VariableInfo {
|
|
|
327
343
|
* @property {boolean=} ranges
|
|
328
344
|
* @property {boolean=} allowHashBang
|
|
329
345
|
* @property {boolean=} allowReturnOutsideFunction
|
|
330
|
-
* @property {boolean=} lazyNodes internal: serve `range` lazily and skip
|
|
346
|
+
* @property {boolean=} lazyNodes internal: serve `range` lazily and skip the parser's location/range tracking
|
|
331
347
|
* @property {Comment[]=} lazyComments internal: collect comments here without slicing their text eagerly
|
|
332
348
|
* @property {boolean=} importPhases enable parsing of the import phase proposals (import defer / import source)
|
|
333
349
|
* @property {boolean=} moduleFallback internal: for `auto`, let the parser downgrade module->script in place instead of re-parsing
|
|
@@ -374,6 +390,7 @@ class VariableInfo {
|
|
|
374
390
|
|
|
375
391
|
/** @typedef {string[]} CalleeMembers */
|
|
376
392
|
/** @typedef {string[]} Members */
|
|
393
|
+
/** @typedef {UpdateExpression | ForInStatement | ForOfStatement | AssignmentExpression} WriteStatement a construct that writes to the reference it carries */
|
|
377
394
|
/** @typedef {boolean[]} MembersOptionals */
|
|
378
395
|
/** @typedef {Range[]} MemberRanges */
|
|
379
396
|
|
|
@@ -430,24 +447,455 @@ const joinRanges = (startRange, endRange) => {
|
|
|
430
447
|
* Helper function used to generate a string representation of a
|
|
431
448
|
* [member expression](https://github.com/estree/estree/blob/master/es5.md#memberexpression).
|
|
432
449
|
* @param {string} object object to name
|
|
433
|
-
* @param {Members}
|
|
450
|
+
* @param {Members} members members in source order
|
|
434
451
|
* @returns {string} member expression as a string
|
|
435
452
|
* @example
|
|
436
453
|
* ```js
|
|
437
|
-
* const
|
|
438
|
-
* const name = objectAndMembersToName("myObject",
|
|
454
|
+
* const members = ["property1", "property2", "property3"]; // Members parsed from the AST
|
|
455
|
+
* const name = objectAndMembersToName("myObject", members);
|
|
439
456
|
*
|
|
440
457
|
* console.log(name); // "myObject.property1.property2.property3"
|
|
441
458
|
* ```
|
|
442
459
|
*/
|
|
443
|
-
const objectAndMembersToName = (object,
|
|
460
|
+
const objectAndMembersToName = (object, members) => {
|
|
444
461
|
let name = object;
|
|
445
|
-
for (let i =
|
|
446
|
-
name = `${name}.${
|
|
462
|
+
for (let i = 0; i < members.length; i++) {
|
|
463
|
+
name = `${name}.${members[i]}`;
|
|
447
464
|
}
|
|
448
465
|
return name;
|
|
449
466
|
};
|
|
450
467
|
|
|
468
|
+
/**
|
|
469
|
+
* The range of the object below each of the first `count` members of a chain,
|
|
470
|
+
* in source order: what `extractMemberExpressionChain` reports as memberRanges.
|
|
471
|
+
* @param {Expression | Super} expression a member expression
|
|
472
|
+
* @param {number} count how many members the chain has
|
|
473
|
+
* @returns {MemberRanges} the ranges
|
|
474
|
+
*/
|
|
475
|
+
const memberRangesOf = (expression, count) => {
|
|
476
|
+
/** @type {MemberRanges} */
|
|
477
|
+
const ranges = [];
|
|
478
|
+
let expr = /** @type {MemberExpression} */ (expression);
|
|
479
|
+
for (let i = 0; i < count; i++) {
|
|
480
|
+
const object = expr.object;
|
|
481
|
+
ranges.push(/** @type {Range} */ (object.range));
|
|
482
|
+
expr = /** @type {MemberExpression} */ (object);
|
|
483
|
+
}
|
|
484
|
+
if (count > 1) ranges.reverse();
|
|
485
|
+
return ranges;
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* In simple logical cases, we can use valueAsExpression to assist us in evaluating the expression on
|
|
490
|
+
* either side of a [BinaryExpression](https://github.com/estree/estree/blob/master/es5.md#binaryexpression).
|
|
491
|
+
* This supports scenarios in webpack like conditionally `import()`'ing modules based on some simple evaluation:
|
|
492
|
+
*
|
|
493
|
+
* ```js
|
|
494
|
+
* if (1 === 3) {
|
|
495
|
+
* import("./moduleA"); // webpack will auto evaluate this and not import the modules
|
|
496
|
+
* }
|
|
497
|
+
* ```
|
|
498
|
+
*
|
|
499
|
+
* Additional scenarios include evaluation of strings inside of dynamic import statements:
|
|
500
|
+
*
|
|
501
|
+
* ```js
|
|
502
|
+
* const foo = "foo";
|
|
503
|
+
* const bar = "bar";
|
|
504
|
+
*
|
|
505
|
+
* import("./" + foo + bar); // webpack will auto evaluate this into import("./foobar")
|
|
506
|
+
* ```
|
|
507
|
+
* @param {boolean | number | bigint | string} value the value to convert to an expression
|
|
508
|
+
* @param {BinaryExpression | UnaryExpression} expr the expression being evaluated
|
|
509
|
+
* @param {boolean} sideEffects whether the expression has side effects
|
|
510
|
+
* @returns {BasicEvaluatedExpression | undefined} the evaluated expression
|
|
511
|
+
* @example
|
|
512
|
+
*
|
|
513
|
+
* ```js
|
|
514
|
+
* const binaryExpr = new BinaryExpression("+",
|
|
515
|
+
* { type: "Literal", value: 2 },
|
|
516
|
+
* { type: "Literal", value: 3 }
|
|
517
|
+
* );
|
|
518
|
+
*
|
|
519
|
+
* const leftValue = 2;
|
|
520
|
+
* const rightValue = 3;
|
|
521
|
+
*
|
|
522
|
+
* const leftExpr = valueAsExpression(leftValue, binaryExpr.left, false);
|
|
523
|
+
* const rightExpr = valueAsExpression(rightValue, binaryExpr.right, false);
|
|
524
|
+
* const result = new BasicEvaluatedExpression()
|
|
525
|
+
* .setNumber(leftExpr.number + rightExpr.number)
|
|
526
|
+
* .setRange(binaryExpr.range);
|
|
527
|
+
*
|
|
528
|
+
* console.log(result.number); // Output: 5
|
|
529
|
+
* ```
|
|
530
|
+
*/
|
|
531
|
+
const valueAsExpression = (value, expr, sideEffects) => {
|
|
532
|
+
switch (typeof value) {
|
|
533
|
+
case "boolean":
|
|
534
|
+
return new BasicEvaluatedExpression()
|
|
535
|
+
.setBoolean(value)
|
|
536
|
+
.setSideEffects(sideEffects)
|
|
537
|
+
.setRange(/** @type {Range} */ (expr.range));
|
|
538
|
+
case "number":
|
|
539
|
+
return new BasicEvaluatedExpression()
|
|
540
|
+
.setNumber(value)
|
|
541
|
+
.setSideEffects(sideEffects)
|
|
542
|
+
.setRange(/** @type {Range} */ (expr.range));
|
|
543
|
+
case "bigint":
|
|
544
|
+
return new BasicEvaluatedExpression()
|
|
545
|
+
.setBigInt(value)
|
|
546
|
+
.setSideEffects(sideEffects)
|
|
547
|
+
.setRange(/** @type {Range} */ (expr.range));
|
|
548
|
+
case "string":
|
|
549
|
+
return new BasicEvaluatedExpression()
|
|
550
|
+
.setString(value)
|
|
551
|
+
.setSideEffects(sideEffects)
|
|
552
|
+
.setRange(/** @type {Range} */ (expr.range));
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
// The constant operators, shared so evaluating `a - b` allocates no handler.
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* @param {EXPECTED_ANY} l left operand
|
|
560
|
+
* @param {EXPECTED_ANY} r right operand
|
|
561
|
+
* @returns {EXPECTED_ANY} the result
|
|
562
|
+
*/
|
|
563
|
+
const SUBTRACT = (l, r) => l - r;
|
|
564
|
+
|
|
565
|
+
/**
|
|
566
|
+
* @param {EXPECTED_ANY} l left operand
|
|
567
|
+
* @param {EXPECTED_ANY} r right operand
|
|
568
|
+
* @returns {EXPECTED_ANY} the result
|
|
569
|
+
*/
|
|
570
|
+
const MULTIPLY = (l, r) => l * r;
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* @param {EXPECTED_ANY} l left operand
|
|
574
|
+
* @param {EXPECTED_ANY} r right operand
|
|
575
|
+
* @returns {EXPECTED_ANY} the result
|
|
576
|
+
*/
|
|
577
|
+
const DIVIDE = (l, r) => l / r;
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* @param {EXPECTED_ANY} l left operand
|
|
581
|
+
* @param {EXPECTED_ANY} r right operand
|
|
582
|
+
* @returns {EXPECTED_ANY} the result
|
|
583
|
+
*/
|
|
584
|
+
const POWER = (l, r) => l ** r;
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* @param {EXPECTED_ANY} l left operand
|
|
588
|
+
* @param {EXPECTED_ANY} r right operand
|
|
589
|
+
* @returns {EXPECTED_ANY} the result
|
|
590
|
+
*/
|
|
591
|
+
const BITWISE_AND = (l, r) => l & r;
|
|
592
|
+
|
|
593
|
+
/**
|
|
594
|
+
* @param {EXPECTED_ANY} l left operand
|
|
595
|
+
* @param {EXPECTED_ANY} r right operand
|
|
596
|
+
* @returns {EXPECTED_ANY} the result
|
|
597
|
+
*/
|
|
598
|
+
const BITWISE_OR = (l, r) => l | r;
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* @param {EXPECTED_ANY} l left operand
|
|
602
|
+
* @param {EXPECTED_ANY} r right operand
|
|
603
|
+
* @returns {EXPECTED_ANY} the result
|
|
604
|
+
*/
|
|
605
|
+
const BITWISE_XOR = (l, r) => l ^ r;
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* @param {EXPECTED_ANY} l left operand
|
|
609
|
+
* @param {EXPECTED_ANY} r right operand
|
|
610
|
+
* @returns {EXPECTED_ANY} the result
|
|
611
|
+
*/
|
|
612
|
+
const UNSIGNED_SHIFT_RIGHT = (l, r) => l >>> r;
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* @param {EXPECTED_ANY} l left operand
|
|
616
|
+
* @param {EXPECTED_ANY} r right operand
|
|
617
|
+
* @returns {EXPECTED_ANY} the result
|
|
618
|
+
*/
|
|
619
|
+
const SHIFT_RIGHT = (l, r) => l >> r;
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* @param {EXPECTED_ANY} l left operand
|
|
623
|
+
* @param {EXPECTED_ANY} r right operand
|
|
624
|
+
* @returns {EXPECTED_ANY} the result
|
|
625
|
+
*/
|
|
626
|
+
const SHIFT_LEFT = (l, r) => l << r;
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* @param {EXPECTED_ANY} l left operand
|
|
630
|
+
* @param {EXPECTED_ANY} r right operand
|
|
631
|
+
* @returns {EXPECTED_ANY} the result
|
|
632
|
+
*/
|
|
633
|
+
const LESS_THAN = (l, r) => l < r;
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* @param {EXPECTED_ANY} l left operand
|
|
637
|
+
* @param {EXPECTED_ANY} r right operand
|
|
638
|
+
* @returns {EXPECTED_ANY} the result
|
|
639
|
+
*/
|
|
640
|
+
const GREATER_THAN = (l, r) => l > r;
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* @param {EXPECTED_ANY} l left operand
|
|
644
|
+
* @param {EXPECTED_ANY} r right operand
|
|
645
|
+
* @returns {EXPECTED_ANY} the result
|
|
646
|
+
*/
|
|
647
|
+
const LESS_THAN_OR_EQUAL = (l, r) => l <= r;
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* @param {EXPECTED_ANY} l left operand
|
|
651
|
+
* @param {EXPECTED_ANY} r right operand
|
|
652
|
+
* @returns {EXPECTED_ANY} the result
|
|
653
|
+
*/
|
|
654
|
+
const GREATER_THAN_OR_EQUAL = (l, r) => l >= r;
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* @param {EXPECTED_ANY} v operand
|
|
658
|
+
* @returns {EXPECTED_ANY} the result
|
|
659
|
+
*/
|
|
660
|
+
const BITWISE_NOT = (v) => ~v;
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* @param {EXPECTED_ANY} v operand
|
|
664
|
+
* @returns {EXPECTED_ANY} the result
|
|
665
|
+
*/
|
|
666
|
+
// eslint-disable-next-line no-implicit-coercion
|
|
667
|
+
const TO_NUMBER = (v) => +v;
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* @param {EXPECTED_ANY} v operand
|
|
671
|
+
* @returns {EXPECTED_ANY} the result
|
|
672
|
+
*/
|
|
673
|
+
const NEGATE = (v) => -v;
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* Evaluates a binary expression if and only if it is a const operation (e.g. 1 + 2, "a" + "b", etc.).
|
|
677
|
+
* @template T
|
|
678
|
+
* @param {JavascriptParser} parser the parser evaluating the expression
|
|
679
|
+
* @param {BinaryExpression} expr the binary expression
|
|
680
|
+
* @param {(leftOperand: T, rightOperand: T) => boolean | number | bigint | string} operandHandler the handler for the operation (e.g. (a, b) => a + b)
|
|
681
|
+
* @returns {BasicEvaluatedExpression | undefined} the evaluated expression
|
|
682
|
+
*/
|
|
683
|
+
const handleConstOperation = (parser, expr, operandHandler) => {
|
|
684
|
+
const left = parser.evaluateExpression(expr.left);
|
|
685
|
+
if (!left.isCompileTimeValue()) return;
|
|
686
|
+
|
|
687
|
+
const right = parser.evaluateExpression(expr.right);
|
|
688
|
+
if (!right.isCompileTimeValue()) return;
|
|
689
|
+
|
|
690
|
+
const result = operandHandler(
|
|
691
|
+
/** @type {T} */ (left.asCompileTimeValue()),
|
|
692
|
+
/** @type {T} */ (right.asCompileTimeValue())
|
|
693
|
+
);
|
|
694
|
+
return valueAsExpression(
|
|
695
|
+
result,
|
|
696
|
+
expr,
|
|
697
|
+
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
698
|
+
);
|
|
699
|
+
};
|
|
700
|
+
|
|
701
|
+
/**
|
|
702
|
+
* Helper function to determine if two booleans are always different. This is used in `handleStrictEqualityComparison`
|
|
703
|
+
* to determine if an expressions boolean or nullish conversion is equal or not.
|
|
704
|
+
* @param {boolean} a first boolean to compare
|
|
705
|
+
* @param {boolean} b second boolean to compare
|
|
706
|
+
* @returns {boolean} true if the two booleans are always different, false otherwise
|
|
707
|
+
*/
|
|
708
|
+
const isAlwaysDifferent = (a, b) =>
|
|
709
|
+
(a === true && b === false) || (a === false && b === true);
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* Handle template string compare.
|
|
713
|
+
* @param {BasicEvaluatedExpression} left left
|
|
714
|
+
* @param {BasicEvaluatedExpression} right right
|
|
715
|
+
* @param {BinaryExpression} expr the comparison, for its range
|
|
716
|
+
* @param {boolean} eql true for "===" and false for "!=="
|
|
717
|
+
* @returns {BasicEvaluatedExpression | undefined} result
|
|
718
|
+
*/
|
|
719
|
+
const handleTemplateStringCompare = (left, right, expr, eql) => {
|
|
720
|
+
/**
|
|
721
|
+
* Returns value.
|
|
722
|
+
* @param {BasicEvaluatedExpression[]} parts parts
|
|
723
|
+
* @returns {string} value
|
|
724
|
+
*/
|
|
725
|
+
const getPrefix = (parts) => {
|
|
726
|
+
let value = "";
|
|
727
|
+
for (const p of parts) {
|
|
728
|
+
const v = p.asString();
|
|
729
|
+
if (v !== undefined) value += v;
|
|
730
|
+
else break;
|
|
731
|
+
}
|
|
732
|
+
return value;
|
|
733
|
+
};
|
|
734
|
+
/**
|
|
735
|
+
* Returns value.
|
|
736
|
+
* @param {BasicEvaluatedExpression[]} parts parts
|
|
737
|
+
* @returns {string} value
|
|
738
|
+
*/
|
|
739
|
+
const getSuffix = (parts) => {
|
|
740
|
+
let value = "";
|
|
741
|
+
for (let i = parts.length - 1; i >= 0; i--) {
|
|
742
|
+
const v = parts[i].asString();
|
|
743
|
+
if (v !== undefined) value = v + value;
|
|
744
|
+
else break;
|
|
745
|
+
}
|
|
746
|
+
return value;
|
|
747
|
+
};
|
|
748
|
+
const leftPrefix = getPrefix(
|
|
749
|
+
/** @type {BasicEvaluatedExpression[]} */ (left.parts)
|
|
750
|
+
);
|
|
751
|
+
const rightPrefix = getPrefix(
|
|
752
|
+
/** @type {BasicEvaluatedExpression[]} */ (right.parts)
|
|
753
|
+
);
|
|
754
|
+
const leftSuffix = getSuffix(
|
|
755
|
+
/** @type {BasicEvaluatedExpression[]} */ (left.parts)
|
|
756
|
+
);
|
|
757
|
+
const rightSuffix = getSuffix(
|
|
758
|
+
/** @type {BasicEvaluatedExpression[]} */ (right.parts)
|
|
759
|
+
);
|
|
760
|
+
const lenPrefix = Math.min(leftPrefix.length, rightPrefix.length);
|
|
761
|
+
const lenSuffix = Math.min(leftSuffix.length, rightSuffix.length);
|
|
762
|
+
const prefixMismatch =
|
|
763
|
+
lenPrefix > 0 &&
|
|
764
|
+
leftPrefix.slice(0, lenPrefix) !== rightPrefix.slice(0, lenPrefix);
|
|
765
|
+
const suffixMismatch =
|
|
766
|
+
lenSuffix > 0 &&
|
|
767
|
+
leftSuffix.slice(-lenSuffix) !== rightSuffix.slice(-lenSuffix);
|
|
768
|
+
if (prefixMismatch || suffixMismatch) {
|
|
769
|
+
return new BasicEvaluatedExpression()
|
|
770
|
+
.setRange(/** @type {Range} */ (expr.range))
|
|
771
|
+
.setBoolean(!eql)
|
|
772
|
+
.setSideEffects(
|
|
773
|
+
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
774
|
+
);
|
|
775
|
+
}
|
|
776
|
+
};
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* Helper function to handle BinaryExpressions using strict equality comparisons (e.g. "===" and "!==").
|
|
780
|
+
* @param {JavascriptParser} parser the parser evaluating the expression
|
|
781
|
+
* @param {BinaryExpression} expr the binary expression
|
|
782
|
+
* @param {boolean} eql true for "===" and false for "!=="
|
|
783
|
+
* @returns {BasicEvaluatedExpression | undefined} the evaluated expression
|
|
784
|
+
*/
|
|
785
|
+
const handleStrictEqualityComparison = (parser, expr, eql) => {
|
|
786
|
+
const left = parser.evaluateExpression(expr.left);
|
|
787
|
+
const right = parser.evaluateExpression(expr.right);
|
|
788
|
+
|
|
789
|
+
const leftConst = left.isCompileTimeValue();
|
|
790
|
+
const rightConst = right.isCompileTimeValue();
|
|
791
|
+
|
|
792
|
+
if (leftConst && rightConst) {
|
|
793
|
+
return new BasicEvaluatedExpression()
|
|
794
|
+
.setRange(/** @type {Range} */ (expr.range))
|
|
795
|
+
.setBoolean(
|
|
796
|
+
eql === (left.asCompileTimeValue() === right.asCompileTimeValue())
|
|
797
|
+
)
|
|
798
|
+
.setSideEffects(
|
|
799
|
+
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
800
|
+
);
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
if (left.isArray() && right.isArray()) {
|
|
804
|
+
return new BasicEvaluatedExpression()
|
|
805
|
+
.setRange(/** @type {Range} */ (expr.range))
|
|
806
|
+
.setBoolean(!eql)
|
|
807
|
+
.setSideEffects(
|
|
808
|
+
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
809
|
+
);
|
|
810
|
+
}
|
|
811
|
+
if (left.isTemplateString() && right.isTemplateString()) {
|
|
812
|
+
return handleTemplateStringCompare(left, right, expr, eql);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
const leftPrimitive = left.isPrimitiveType();
|
|
816
|
+
const rightPrimitive = right.isPrimitiveType();
|
|
817
|
+
|
|
818
|
+
if (
|
|
819
|
+
// Primitive !== Object or
|
|
820
|
+
// compile-time object types are never equal to something at runtime
|
|
821
|
+
(leftPrimitive === false && (leftConst || rightPrimitive === true)) ||
|
|
822
|
+
(rightPrimitive === false && (rightConst || leftPrimitive === true)) ||
|
|
823
|
+
// Different nullish or boolish status also means not equal
|
|
824
|
+
isAlwaysDifferent(
|
|
825
|
+
/** @type {boolean} */ (left.asBool()),
|
|
826
|
+
/** @type {boolean} */ (right.asBool())
|
|
827
|
+
) ||
|
|
828
|
+
isAlwaysDifferent(
|
|
829
|
+
/** @type {boolean} */ (left.asNullish()),
|
|
830
|
+
/** @type {boolean} */ (right.asNullish())
|
|
831
|
+
)
|
|
832
|
+
) {
|
|
833
|
+
return new BasicEvaluatedExpression()
|
|
834
|
+
.setRange(/** @type {Range} */ (expr.range))
|
|
835
|
+
.setBoolean(!eql)
|
|
836
|
+
.setSideEffects(
|
|
837
|
+
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
838
|
+
);
|
|
839
|
+
}
|
|
840
|
+
};
|
|
841
|
+
|
|
842
|
+
/**
|
|
843
|
+
* Helper function to handle BinaryExpressions using abstract equality comparisons (e.g. "==" and "!=").
|
|
844
|
+
* @param {JavascriptParser} parser the parser evaluating the expression
|
|
845
|
+
* @param {BinaryExpression} expr the binary expression
|
|
846
|
+
* @param {boolean} eql true for "==" and false for "!="
|
|
847
|
+
* @returns {BasicEvaluatedExpression | undefined} the evaluated expression
|
|
848
|
+
*/
|
|
849
|
+
const handleAbstractEqualityComparison = (parser, expr, eql) => {
|
|
850
|
+
const left = parser.evaluateExpression(expr.left);
|
|
851
|
+
const right = parser.evaluateExpression(expr.right);
|
|
852
|
+
|
|
853
|
+
const leftConst = left.isCompileTimeValue();
|
|
854
|
+
const rightConst = right.isCompileTimeValue();
|
|
855
|
+
|
|
856
|
+
if (leftConst && rightConst) {
|
|
857
|
+
return new BasicEvaluatedExpression()
|
|
858
|
+
.setRange(/** @type {Range} */ (expr.range))
|
|
859
|
+
.setBoolean(
|
|
860
|
+
eql ===
|
|
861
|
+
// eslint-disable-next-line eqeqeq
|
|
862
|
+
(left.asCompileTimeValue() == right.asCompileTimeValue())
|
|
863
|
+
)
|
|
864
|
+
.setSideEffects(
|
|
865
|
+
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
866
|
+
);
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
if (left.isArray() && right.isArray()) {
|
|
870
|
+
return new BasicEvaluatedExpression()
|
|
871
|
+
.setRange(/** @type {Range} */ (expr.range))
|
|
872
|
+
.setBoolean(!eql)
|
|
873
|
+
.setSideEffects(
|
|
874
|
+
left.couldHaveSideEffects() || right.couldHaveSideEffects()
|
|
875
|
+
);
|
|
876
|
+
}
|
|
877
|
+
if (left.isTemplateString() && right.isTemplateString()) {
|
|
878
|
+
return handleTemplateStringCompare(left, right, expr, eql);
|
|
879
|
+
}
|
|
880
|
+
};
|
|
881
|
+
|
|
882
|
+
/**
|
|
883
|
+
* Evaluates a UnaryExpression if and only if it is a basic const operator (e.g. +a, -a, ~a).
|
|
884
|
+
* @template T
|
|
885
|
+
* @param {JavascriptParser} parser the parser evaluating the expression
|
|
886
|
+
* @param {UnaryExpression} expr the unary expression
|
|
887
|
+
* @param {(operand: T) => boolean | number | bigint | string} operandHandler handler for the operand
|
|
888
|
+
* @returns {BasicEvaluatedExpression | undefined} evaluated expression
|
|
889
|
+
*/
|
|
890
|
+
const handleUnaryConstOperation = (parser, expr, operandHandler) => {
|
|
891
|
+
const argument = parser.evaluateExpression(expr.argument);
|
|
892
|
+
if (!argument.isCompileTimeValue()) return;
|
|
893
|
+
const result = operandHandler(
|
|
894
|
+
/** @type {T} */ (argument.asCompileTimeValue())
|
|
895
|
+
);
|
|
896
|
+
return valueAsExpression(result, expr, argument.couldHaveSideEffects());
|
|
897
|
+
};
|
|
898
|
+
|
|
451
899
|
/**
|
|
452
900
|
* Grabs the name of a given expression and returns it as a string or undefined. Has particular
|
|
453
901
|
* handling for [Identifiers](https://github.com/estree/estree/blob/master/es5.md#identifier),
|
|
@@ -511,6 +959,183 @@ const evaluateAstCaches = new WeakMap();
|
|
|
511
959
|
// The inner map is strong while the compilation lives, so cap it
|
|
512
960
|
const EVALUATE_AST_CACHE_LIMIT = 4096;
|
|
513
961
|
|
|
962
|
+
/**
|
|
963
|
+
* Add one declaration, starting the list at the first — most scopes declare
|
|
964
|
+
* nothing, and the shared empty list spares them an array.
|
|
965
|
+
* @param {HoistedDeclarations} hoisted the list so far
|
|
966
|
+
* @param {Statement | ModuleDeclaration} declaration what to add
|
|
967
|
+
* @returns {HoistedDeclarations} the list holding it
|
|
968
|
+
*/
|
|
969
|
+
const addHoistedDeclaration = (hoisted, declaration) => {
|
|
970
|
+
if (hoisted === EMPTY_HOISTED_DECLARATIONS) return [declaration];
|
|
971
|
+
hoisted.push(declaration);
|
|
972
|
+
return hoisted;
|
|
973
|
+
};
|
|
974
|
+
|
|
975
|
+
/**
|
|
976
|
+
* Collect the declarations that hoist to one scope, for an AST that did not
|
|
977
|
+
* come from webpack's parser and so carries no record of its own.
|
|
978
|
+
* @param {(Statement | ModuleDeclaration)[]} statements the scope's statements
|
|
979
|
+
* @param {HoistedDeclarations} hoisted the list so far
|
|
980
|
+
* @returns {HoistedDeclarations} the list holding what they declare
|
|
981
|
+
*/
|
|
982
|
+
const collectHoistedDeclarations = (statements, hoisted) => {
|
|
983
|
+
for (let index = 0, len = statements.length; index < len; index++) {
|
|
984
|
+
hoisted = collectHoistedDeclaration(statements[index], hoisted);
|
|
985
|
+
}
|
|
986
|
+
return hoisted;
|
|
987
|
+
};
|
|
988
|
+
|
|
989
|
+
/**
|
|
990
|
+
* Collect from one statement, descending exactly as far as a `var` reaches:
|
|
991
|
+
* through blocks and loop bodies, never into another function.
|
|
992
|
+
* @param {Statement | ModuleDeclaration} statement the statement
|
|
993
|
+
* @param {HoistedDeclarations} hoisted the list so far
|
|
994
|
+
* @returns {HoistedDeclarations} the list holding what it declares
|
|
995
|
+
*/
|
|
996
|
+
const collectHoistedDeclaration = (statement, hoisted) => {
|
|
997
|
+
switch (statement.type) {
|
|
998
|
+
case "VariableDeclaration":
|
|
999
|
+
if (statement.kind === "var") {
|
|
1000
|
+
hoisted = addHoistedDeclaration(hoisted, statement);
|
|
1001
|
+
}
|
|
1002
|
+
break;
|
|
1003
|
+
case "FunctionDeclaration":
|
|
1004
|
+
case "ClassDeclaration":
|
|
1005
|
+
hoisted = addHoistedDeclaration(hoisted, statement);
|
|
1006
|
+
break;
|
|
1007
|
+
case "BlockStatement":
|
|
1008
|
+
hoisted = collectHoistedDeclarations(statement.body, hoisted);
|
|
1009
|
+
break;
|
|
1010
|
+
case "IfStatement":
|
|
1011
|
+
hoisted = collectHoistedDeclaration(statement.consequent, hoisted);
|
|
1012
|
+
if (statement.alternate) {
|
|
1013
|
+
hoisted = collectHoistedDeclaration(statement.alternate, hoisted);
|
|
1014
|
+
}
|
|
1015
|
+
break;
|
|
1016
|
+
case "ForStatement":
|
|
1017
|
+
if (statement.init && statement.init.type === "VariableDeclaration") {
|
|
1018
|
+
hoisted = collectHoistedDeclaration(statement.init, hoisted);
|
|
1019
|
+
}
|
|
1020
|
+
hoisted = collectHoistedDeclaration(statement.body, hoisted);
|
|
1021
|
+
break;
|
|
1022
|
+
case "ForInStatement":
|
|
1023
|
+
case "ForOfStatement":
|
|
1024
|
+
if (statement.left.type === "VariableDeclaration") {
|
|
1025
|
+
hoisted = collectHoistedDeclaration(statement.left, hoisted);
|
|
1026
|
+
}
|
|
1027
|
+
hoisted = collectHoistedDeclaration(statement.body, hoisted);
|
|
1028
|
+
break;
|
|
1029
|
+
case "WhileStatement":
|
|
1030
|
+
case "DoWhileStatement":
|
|
1031
|
+
case "LabeledStatement":
|
|
1032
|
+
case "WithStatement":
|
|
1033
|
+
hoisted = collectHoistedDeclaration(statement.body, hoisted);
|
|
1034
|
+
break;
|
|
1035
|
+
case "TryStatement":
|
|
1036
|
+
hoisted = collectHoistedDeclaration(statement.block, hoisted);
|
|
1037
|
+
if (statement.handler) {
|
|
1038
|
+
hoisted = collectHoistedDeclaration(statement.handler.body, hoisted);
|
|
1039
|
+
}
|
|
1040
|
+
if (statement.finalizer) {
|
|
1041
|
+
hoisted = collectHoistedDeclaration(statement.finalizer, hoisted);
|
|
1042
|
+
}
|
|
1043
|
+
break;
|
|
1044
|
+
case "SwitchStatement": {
|
|
1045
|
+
const cases = statement.cases;
|
|
1046
|
+
for (let index = 0, len = cases.length; index < len; index++) {
|
|
1047
|
+
hoisted = collectHoistedDeclarations(cases[index].consequent, hoisted);
|
|
1048
|
+
}
|
|
1049
|
+
break;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
return hoisted;
|
|
1053
|
+
};
|
|
1054
|
+
|
|
1055
|
+
/**
|
|
1056
|
+
* What the program imports and re-exports: the parser's own record, or a scan
|
|
1057
|
+
* of the top-level statements for an AST some other parser built.
|
|
1058
|
+
* @param {Program} ast the program
|
|
1059
|
+
* @param {boolean} trusted whether the parser's own record may be read
|
|
1060
|
+
* @returns {ModuleDeclarations} the declarations, in source order
|
|
1061
|
+
*/
|
|
1062
|
+
const moduleDeclarationsOf = (ast, trusted) => {
|
|
1063
|
+
if (trusted) {
|
|
1064
|
+
const recorded = /** @type {EXPECTED_ANY} */ (ast)[MODULE_DECLARATIONS];
|
|
1065
|
+
if (recorded !== undefined) return recorded;
|
|
1066
|
+
}
|
|
1067
|
+
/** @type {ModuleDeclarations} */
|
|
1068
|
+
let declarations = EMPTY_MODULE_DECLARATIONS;
|
|
1069
|
+
const body = ast.body;
|
|
1070
|
+
for (let index = 0, len = body.length; index < len; index++) {
|
|
1071
|
+
const statement = body[index];
|
|
1072
|
+
if (MODULE_STATEMENT_TYPES.has(statement.type)) {
|
|
1073
|
+
if (declarations === EMPTY_MODULE_DECLARATIONS) declarations = [];
|
|
1074
|
+
declarations.push(statement, index === 0 ? undefined : body[index - 1]);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
return declarations;
|
|
1078
|
+
};
|
|
1079
|
+
|
|
1080
|
+
/**
|
|
1081
|
+
* What hoists to the scope the node opens: the parser's own record, or a walk
|
|
1082
|
+
* of the body for an AST some other parser built.
|
|
1083
|
+
* @param {Program | BlockStatement} node the node owning the scope
|
|
1084
|
+
* @param {boolean} trusted whether the parser's own record may be read
|
|
1085
|
+
* @returns {HoistedDeclarations} the declarations, in source order
|
|
1086
|
+
*/
|
|
1087
|
+
const hoistedDeclarationsOf = (node, trusted) => {
|
|
1088
|
+
if (trusted) {
|
|
1089
|
+
const recorded = /** @type {EXPECTED_ANY} */ (node)[HOISTED_DECLARATIONS];
|
|
1090
|
+
if (recorded !== undefined) return recorded;
|
|
1091
|
+
}
|
|
1092
|
+
return collectHoistedDeclarations(node.body, EMPTY_HOISTED_DECLARATIONS);
|
|
1093
|
+
};
|
|
1094
|
+
|
|
1095
|
+
/**
|
|
1096
|
+
* Which statements of a list declare into its block scope, scanned for an AST
|
|
1097
|
+
* some other parser built. The parser's own record is read instead when there
|
|
1098
|
+
* is one.
|
|
1099
|
+
* @param {(Statement | ModuleDeclaration)[]} statements the list
|
|
1100
|
+
* @returns {BlockDeclarations} their indices, in source order
|
|
1101
|
+
*/
|
|
1102
|
+
const collectBlockDeclarations = (statements) => {
|
|
1103
|
+
let mask = 0;
|
|
1104
|
+
/** @type {number[] | undefined} */
|
|
1105
|
+
let overflow;
|
|
1106
|
+
for (let index = 0, len = statements.length; index < len; index++) {
|
|
1107
|
+
if (!declaresIntoBlock(statements[index])) continue;
|
|
1108
|
+
if (overflow !== undefined) overflow.push(index);
|
|
1109
|
+
else if (index <= MAX_MASKED_INDEX) mask |= 1 << index;
|
|
1110
|
+
else overflow = overflowFrom(mask, index);
|
|
1111
|
+
}
|
|
1112
|
+
return overflow === undefined ? mask : overflow;
|
|
1113
|
+
};
|
|
1114
|
+
|
|
1115
|
+
/**
|
|
1116
|
+
* Whether the source between two offsets is whitespace only.
|
|
1117
|
+
* @param {string} source the module source
|
|
1118
|
+
* @param {number} start where to start
|
|
1119
|
+
* @param {number} end where to stop
|
|
1120
|
+
* @returns {boolean} whether nothing but whitespace lies between them
|
|
1121
|
+
*/
|
|
1122
|
+
const onlyWhitespaceBetween = (source, start, end) => {
|
|
1123
|
+
for (let index = start; index < end; index++) {
|
|
1124
|
+
const code = source.charCodeAt(index);
|
|
1125
|
+
// the classification `skipSpace` uses: anything else is a token, and a
|
|
1126
|
+
// token means the run of comments before the statement has ended
|
|
1127
|
+
if (
|
|
1128
|
+
code !== 32 &&
|
|
1129
|
+
code !== 160 &&
|
|
1130
|
+
!(code > 8 && code < 14) &&
|
|
1131
|
+
!(code >= 5760 && nonASCIIwhitespace.test(source[index]))
|
|
1132
|
+
) {
|
|
1133
|
+
return false;
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
return true;
|
|
1137
|
+
};
|
|
1138
|
+
|
|
514
1139
|
const CLASS_NAME = "JavascriptParser";
|
|
515
1140
|
|
|
516
1141
|
// Reserved words in strict mode, so unusable as binding names there (12.7.2).
|
|
@@ -573,17 +1198,33 @@ class JavascriptParser extends Parser {
|
|
|
573
1198
|
isPure: new HookMap(
|
|
574
1199
|
() => new SyncBailHook(["expression", "commentsStartPosition"])
|
|
575
1200
|
),
|
|
576
|
-
/**
|
|
1201
|
+
/**
|
|
1202
|
+
* Every statement the hoisting pass reads, which a tap on this turns
|
|
1203
|
+
* back into a walk of them all. Tap `preStatementByType` instead.
|
|
1204
|
+
* @type {SyncBailHook<[Statement | ModuleDeclaration | MaybeNamedClassDeclaration | MaybeNamedFunctionDeclaration], boolean | void>}
|
|
1205
|
+
* @deprecated TODO webpack 6: remove, with the statement walk it turns on
|
|
1206
|
+
*/
|
|
577
1207
|
preStatement: new SyncBailHook(["statement"]),
|
|
578
1208
|
/**
|
|
1209
|
+
* Each declaration the parser records: a variable, function or class
|
|
1210
|
+
* one. Any other type turns the pass back into a walk of every
|
|
1211
|
+
* statement, and goes away with that walk in webpack 6.
|
|
579
1212
|
* @type {HookMap<SyncBailHook<[Statement | ModuleDeclaration | MaybeNamedClassDeclaration | MaybeNamedFunctionDeclaration], boolean | void>>}
|
|
580
1213
|
* @since 5.109.0
|
|
581
1214
|
*/
|
|
582
1215
|
preStatementByType: new HookMap(() => new SyncBailHook(["statement"])),
|
|
583
1216
|
|
|
584
|
-
/**
|
|
1217
|
+
/**
|
|
1218
|
+
* Every statement the block pass reads, which a tap on this turns back
|
|
1219
|
+
* into a walk of them all. Tap `blockPreStatementByType` instead.
|
|
1220
|
+
* @type {SyncBailHook<[Statement | ModuleDeclaration | MaybeNamedClassDeclaration | MaybeNamedFunctionDeclaration], boolean | void>}
|
|
1221
|
+
* @deprecated TODO webpack 6: remove, with the statement walk it turns on
|
|
1222
|
+
*/
|
|
585
1223
|
blockPreStatement: new SyncBailHook(["declaration"]),
|
|
586
1224
|
/**
|
|
1225
|
+
* Each statement the parser records for the block pass: a variable, class
|
|
1226
|
+
* or export declaration. Any other type turns the pass back into a walk
|
|
1227
|
+
* of every statement, and goes away with that walk in webpack 6.
|
|
587
1228
|
* @type {HookMap<SyncBailHook<[Statement | ModuleDeclaration | MaybeNamedClassDeclaration | MaybeNamedFunctionDeclaration], boolean | void>>}
|
|
588
1229
|
* @since 5.109.0
|
|
589
1230
|
*/
|
|
@@ -681,6 +1322,12 @@ class JavascriptParser extends Parser {
|
|
|
681
1322
|
rename: new HookMap(() => new SyncBailHook(["initExpression"])),
|
|
682
1323
|
/** @type {HookMap<SyncBailHook<[AssignmentExpression], boolean | void>>} */
|
|
683
1324
|
assign: new HookMap(() => new SyncBailHook(["expression"])),
|
|
1325
|
+
/** @type {HookMap<SyncBailHook<[WriteStatement], boolean | void>>} */
|
|
1326
|
+
write: new HookMap(() => new SyncBailHook(["node"])),
|
|
1327
|
+
/** @type {HookMap<SyncBailHook<[WriteStatement, Members], boolean | void>>} */
|
|
1328
|
+
writeMemberChain: new HookMap(
|
|
1329
|
+
() => new SyncBailHook(["node", "members"])
|
|
1330
|
+
),
|
|
684
1331
|
/** @type {HookMap<SyncBailHook<[AssignmentExpression, Members], boolean | void>>} */
|
|
685
1332
|
assignMemberChain: new HookMap(
|
|
686
1333
|
() => new SyncBailHook(["expression", "members"])
|
|
@@ -790,6 +1437,37 @@ class JavascriptParser extends Parser {
|
|
|
790
1437
|
this.statementPath = undefined;
|
|
791
1438
|
/** @type {Statement | ModuleDeclaration | Expression | MaybeNamedFunctionDeclaration | MaybeNamedClassDeclaration | undefined} */
|
|
792
1439
|
this.prevStatement = undefined;
|
|
1440
|
+
/** @type {boolean} */
|
|
1441
|
+
this._hasParserRecord = false;
|
|
1442
|
+
// BACKWARD-COMPAT START
|
|
1443
|
+
|
|
1444
|
+
// WHY: the hoisting pass reaches declarations alone, so a tap that
|
|
1445
|
+
// expects every statement would quietly stop seeing most of them. Such a
|
|
1446
|
+
// tap turns the pass back into the walk it used to be, which no build
|
|
1447
|
+
// webpack's own plugins drive ever asks for.
|
|
1448
|
+
/** @type {boolean} */
|
|
1449
|
+
this._needsFullPreWalk = false;
|
|
1450
|
+
this.hooks.preStatementByType.intercept({
|
|
1451
|
+
factory: (type, hook) => {
|
|
1452
|
+
if (!RECORDED_STATEMENT_TYPES.has(type)) {
|
|
1453
|
+
this._needsFullPreWalk = true;
|
|
1454
|
+
}
|
|
1455
|
+
return hook;
|
|
1456
|
+
}
|
|
1457
|
+
});
|
|
1458
|
+
|
|
1459
|
+
// The same for the block pass, over the types the parser records for it.
|
|
1460
|
+
/** @type {boolean} */
|
|
1461
|
+
this._needsFullBlockPreWalk = false;
|
|
1462
|
+
this.hooks.blockPreStatementByType.intercept({
|
|
1463
|
+
factory: (type, hook) => {
|
|
1464
|
+
if (!BLOCK_DECLARATION_TYPES.has(type)) {
|
|
1465
|
+
this._needsFullBlockPreWalk = true;
|
|
1466
|
+
}
|
|
1467
|
+
return hook;
|
|
1468
|
+
}
|
|
1469
|
+
});
|
|
1470
|
+
// BACKWARD-COMPAT END
|
|
793
1471
|
/** @type {WeakMap<Expression, DestructuringAssignmentProperties> | undefined} */
|
|
794
1472
|
this.destructuringAssignmentProperties = undefined;
|
|
795
1473
|
/** @type {TagData | undefined} */
|
|
@@ -802,6 +1480,32 @@ class JavascriptParser extends Parser {
|
|
|
802
1480
|
// Offset of each line's first character, built on first getLocation use.
|
|
803
1481
|
/** @type {number[] | undefined} */
|
|
804
1482
|
this._lineStarts = undefined;
|
|
1483
|
+
// The last member expression resolved, kept while the node and the scope
|
|
1484
|
+
// it resolved in stay the same: the walk and an evaluate of one node meet
|
|
1485
|
+
/** @type {Expression | Super | undefined} */
|
|
1486
|
+
this._memberExpression = undefined;
|
|
1487
|
+
/** @type {ScopeInfo | undefined} */
|
|
1488
|
+
this._memberScope = undefined;
|
|
1489
|
+
/** @type {number} */
|
|
1490
|
+
this._memberMask = 0;
|
|
1491
|
+
/** @type {0 | 1 | 2} */
|
|
1492
|
+
this._memberType = 0;
|
|
1493
|
+
/** @type {string} */
|
|
1494
|
+
this._memberName = "";
|
|
1495
|
+
/** @type {string | VariableInfo | undefined} */
|
|
1496
|
+
this._memberRootInfo = undefined;
|
|
1497
|
+
/** @type {Members} */
|
|
1498
|
+
this._members = EMPTY_ARRAY;
|
|
1499
|
+
/** @type {MembersOptionals} */
|
|
1500
|
+
this._membersOptionals = EMPTY_MEMBERS_OPTIONALS;
|
|
1501
|
+
/** @type {CallExpression | undefined} */
|
|
1502
|
+
this._memberCall = undefined;
|
|
1503
|
+
/** @type {string} */
|
|
1504
|
+
this._memberCalleeName = "";
|
|
1505
|
+
/** @type {CalleeMembers} */
|
|
1506
|
+
this._memberCalleeMembers = EMPTY_ARRAY;
|
|
1507
|
+
/** @type {CallExpressionInfo | ExpressionExpressionInfo | undefined} */
|
|
1508
|
+
this._memberInfo = undefined;
|
|
805
1509
|
// True while only the parser's own taps sit on evaluate.for("Identifier");
|
|
806
1510
|
// recomputed per parse, gates the defined-identifier fast paths.
|
|
807
1511
|
this._evalIdentOwnTaps = false;
|
|
@@ -809,6 +1513,22 @@ class JavascriptParser extends Parser {
|
|
|
809
1513
|
// Reused for enterPatterns on every scope entry to avoid per-scope closures.
|
|
810
1514
|
/** @type {OnIdentString} */
|
|
811
1515
|
this._defineVariable = (ident) => this.defineVariable(ident);
|
|
1516
|
+
// The expression an identifier evaluator is running for, read by the
|
|
1517
|
+
// shared `_evaluateDefinedIdentifier` instead of a closure per evaluation
|
|
1518
|
+
/** @type {Identifier | ThisExpression | MemberExpression | undefined} */
|
|
1519
|
+
this._evaluatingExpression = undefined;
|
|
1520
|
+
/** @type {(name?: string) => BasicEvaluatedExpression | null | undefined} */
|
|
1521
|
+
this._evaluateDefinedIdentifier = (name) => {
|
|
1522
|
+
const hook = this.hooks.evaluateDefinedIdentifier.get(
|
|
1523
|
+
/** @type {string} */ (name)
|
|
1524
|
+
);
|
|
1525
|
+
if (hook !== undefined) {
|
|
1526
|
+
return hook.call(
|
|
1527
|
+
/** @type {Identifier | ThisExpression | MemberExpression} */
|
|
1528
|
+
(this._evaluatingExpression)
|
|
1529
|
+
);
|
|
1530
|
+
}
|
|
1531
|
+
};
|
|
812
1532
|
this._initializeEvaluating();
|
|
813
1533
|
// keyed taps are free for every other member chain, and a shadowed
|
|
814
1534
|
// `arguments` binding never dispatches the free-variable hooks
|
|
@@ -867,7 +1587,7 @@ class JavascriptParser extends Parser {
|
|
|
867
1587
|
const callee = expr.callee;
|
|
868
1588
|
if (callee.type !== "Identifier") return;
|
|
869
1589
|
if (callee.name !== "RegExp") {
|
|
870
|
-
return this.
|
|
1590
|
+
return this._callHooksForName1(
|
|
871
1591
|
this.hooks.evaluateNewExpression,
|
|
872
1592
|
callee.name,
|
|
873
1593
|
expr
|
|
@@ -979,278 +1699,10 @@ class JavascriptParser extends Parser {
|
|
|
979
1699
|
}
|
|
980
1700
|
});
|
|
981
1701
|
|
|
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
1702
|
this.hooks.evaluate.for("BinaryExpression").tap(CLASS_NAME, (_expr) => {
|
|
1051
1703
|
const expr = /** @type {BinaryExpression} */ (_expr);
|
|
1052
1704
|
|
|
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
|
-
if (expr.operator === "+") {
|
|
1705
|
+
if (expr.operator === "+") {
|
|
1254
1706
|
const left = this.evaluateExpression(expr.left);
|
|
1255
1707
|
const right = this.evaluateExpression(expr.right);
|
|
1256
1708
|
const res = new BasicEvaluatedExpression();
|
|
@@ -1416,41 +1868,41 @@ class JavascriptParser extends Parser {
|
|
|
1416
1868
|
res.setRange(/** @type {Range} */ (expr.range));
|
|
1417
1869
|
return res;
|
|
1418
1870
|
} else if (expr.operator === "-") {
|
|
1419
|
-
return handleConstOperation(
|
|
1871
|
+
return handleConstOperation(this, expr, SUBTRACT);
|
|
1420
1872
|
} else if (expr.operator === "*") {
|
|
1421
|
-
return handleConstOperation(
|
|
1873
|
+
return handleConstOperation(this, expr, MULTIPLY);
|
|
1422
1874
|
} else if (expr.operator === "/") {
|
|
1423
|
-
return handleConstOperation(
|
|
1875
|
+
return handleConstOperation(this, expr, DIVIDE);
|
|
1424
1876
|
} else if (expr.operator === "**") {
|
|
1425
|
-
return handleConstOperation(
|
|
1877
|
+
return handleConstOperation(this, expr, POWER);
|
|
1426
1878
|
} else if (expr.operator === "===") {
|
|
1427
|
-
return handleStrictEqualityComparison(true);
|
|
1879
|
+
return handleStrictEqualityComparison(this, expr, true);
|
|
1428
1880
|
} else if (expr.operator === "==") {
|
|
1429
|
-
return handleAbstractEqualityComparison(true);
|
|
1881
|
+
return handleAbstractEqualityComparison(this, expr, true);
|
|
1430
1882
|
} else if (expr.operator === "!==") {
|
|
1431
|
-
return handleStrictEqualityComparison(false);
|
|
1883
|
+
return handleStrictEqualityComparison(this, expr, false);
|
|
1432
1884
|
} else if (expr.operator === "!=") {
|
|
1433
|
-
return handleAbstractEqualityComparison(false);
|
|
1885
|
+
return handleAbstractEqualityComparison(this, expr, false);
|
|
1434
1886
|
} else if (expr.operator === "&") {
|
|
1435
|
-
return handleConstOperation(
|
|
1887
|
+
return handleConstOperation(this, expr, BITWISE_AND);
|
|
1436
1888
|
} else if (expr.operator === "|") {
|
|
1437
|
-
return handleConstOperation(
|
|
1889
|
+
return handleConstOperation(this, expr, BITWISE_OR);
|
|
1438
1890
|
} else if (expr.operator === "^") {
|
|
1439
|
-
return handleConstOperation(
|
|
1891
|
+
return handleConstOperation(this, expr, BITWISE_XOR);
|
|
1440
1892
|
} else if (expr.operator === ">>>") {
|
|
1441
|
-
return handleConstOperation(
|
|
1893
|
+
return handleConstOperation(this, expr, UNSIGNED_SHIFT_RIGHT);
|
|
1442
1894
|
} else if (expr.operator === ">>") {
|
|
1443
|
-
return handleConstOperation(
|
|
1895
|
+
return handleConstOperation(this, expr, SHIFT_RIGHT);
|
|
1444
1896
|
} else if (expr.operator === "<<") {
|
|
1445
|
-
return handleConstOperation(
|
|
1897
|
+
return handleConstOperation(this, expr, SHIFT_LEFT);
|
|
1446
1898
|
} else if (expr.operator === "<") {
|
|
1447
|
-
return handleConstOperation(
|
|
1899
|
+
return handleConstOperation(this, expr, LESS_THAN);
|
|
1448
1900
|
} else if (expr.operator === ">") {
|
|
1449
|
-
return handleConstOperation(
|
|
1901
|
+
return handleConstOperation(this, expr, GREATER_THAN);
|
|
1450
1902
|
} else if (expr.operator === "<=") {
|
|
1451
|
-
return handleConstOperation(
|
|
1903
|
+
return handleConstOperation(this, expr, LESS_THAN_OR_EQUAL);
|
|
1452
1904
|
} else if (expr.operator === ">=") {
|
|
1453
|
-
return handleConstOperation(
|
|
1905
|
+
return handleConstOperation(this, expr, GREATER_THAN_OR_EQUAL);
|
|
1454
1906
|
} else if (expr.operator === "in") {
|
|
1455
1907
|
// `x in y` always evaluates to a boolean, so it is never nullish
|
|
1456
1908
|
const left = this.evaluateExpression(expr.left);
|
|
@@ -1466,25 +1918,10 @@ class JavascriptParser extends Parser {
|
|
|
1466
1918
|
this.hooks.evaluate.for("UnaryExpression").tap(CLASS_NAME, (_expr) => {
|
|
1467
1919
|
const expr = /** @type {UnaryExpression} */ (_expr);
|
|
1468
1920
|
|
|
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
1921
|
if (expr.operator === "typeof") {
|
|
1485
1922
|
switch (expr.argument.type) {
|
|
1486
1923
|
case "Identifier": {
|
|
1487
|
-
const res = this.
|
|
1924
|
+
const res = this._callHooksForName1(
|
|
1488
1925
|
this.hooks.evaluateTypeof,
|
|
1489
1926
|
expr.argument.name,
|
|
1490
1927
|
expr
|
|
@@ -1493,7 +1930,7 @@ class JavascriptParser extends Parser {
|
|
|
1493
1930
|
break;
|
|
1494
1931
|
}
|
|
1495
1932
|
case "MetaProperty": {
|
|
1496
|
-
const res = this.
|
|
1933
|
+
const res = this._callHooksForName1(
|
|
1497
1934
|
this.hooks.evaluateTypeof,
|
|
1498
1935
|
/** @type {string} */
|
|
1499
1936
|
(getRootName(expr.argument)),
|
|
@@ -1579,12 +2016,11 @@ class JavascriptParser extends Parser {
|
|
|
1579
2016
|
.setSideEffects(argument.couldHaveSideEffects())
|
|
1580
2017
|
.setRange(/** @type {Range} */ (expr.range));
|
|
1581
2018
|
} else if (expr.operator === "~") {
|
|
1582
|
-
return
|
|
2019
|
+
return handleUnaryConstOperation(this, expr, BITWISE_NOT);
|
|
1583
2020
|
} else if (expr.operator === "+") {
|
|
1584
|
-
|
|
1585
|
-
return handleConstOperation((v) => +v);
|
|
2021
|
+
return handleUnaryConstOperation(this, expr, TO_NUMBER);
|
|
1586
2022
|
} else if (expr.operator === "-") {
|
|
1587
|
-
return
|
|
2023
|
+
return handleUnaryConstOperation(this, expr, NEGATE);
|
|
1588
2024
|
}
|
|
1589
2025
|
});
|
|
1590
2026
|
this.hooks.evaluateTypeof
|
|
@@ -1623,18 +2059,18 @@ class JavascriptParser extends Parser {
|
|
|
1623
2059
|
cachedExpression = expression;
|
|
1624
2060
|
cachedInfo = info;
|
|
1625
2061
|
if (info !== undefined) {
|
|
1626
|
-
|
|
2062
|
+
// saved around the call: a hook may evaluate another identifier
|
|
2063
|
+
const outer = this._evaluatingExpression;
|
|
2064
|
+
this._evaluatingExpression = expression;
|
|
2065
|
+
const result = this.callHooksForInfoWithFallback(
|
|
1627
2066
|
this.hooks.evaluateIdentifier,
|
|
1628
2067
|
info.name,
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
const hook = this.hooks.evaluateDefinedIdentifier.get(name);
|
|
1632
|
-
if (hook !== undefined) {
|
|
1633
|
-
return hook.call(expression);
|
|
1634
|
-
}
|
|
1635
|
-
},
|
|
2068
|
+
RETURN_UNDEFINED,
|
|
2069
|
+
this._evaluateDefinedIdentifier,
|
|
1636
2070
|
expression
|
|
1637
2071
|
);
|
|
2072
|
+
this._evaluatingExpression = outer;
|
|
2073
|
+
return result;
|
|
1638
2074
|
}
|
|
1639
2075
|
});
|
|
1640
2076
|
this.hooks.evaluate
|
|
@@ -1699,7 +2135,7 @@ class JavascriptParser extends Parser {
|
|
|
1699
2135
|
this.hooks.evaluate.for("MetaProperty").tap(CLASS_NAME, (expr) => {
|
|
1700
2136
|
const metaProperty = /** @type {MetaProperty} */ (expr);
|
|
1701
2137
|
|
|
1702
|
-
return this.
|
|
2138
|
+
return this._callHooksForName1(
|
|
1703
2139
|
this.hooks.evaluateIdentifier,
|
|
1704
2140
|
/** @type {string} */
|
|
1705
2141
|
(getRootName(metaProperty)),
|
|
@@ -1733,7 +2169,7 @@ class JavascriptParser extends Parser {
|
|
|
1733
2169
|
return hook.call(expr, param);
|
|
1734
2170
|
}
|
|
1735
2171
|
} else if (expr.callee.type === "Identifier") {
|
|
1736
|
-
return this.
|
|
2172
|
+
return this._callHooksForName1(
|
|
1737
2173
|
this.hooks.evaluateCallExpression,
|
|
1738
2174
|
expr.callee.name,
|
|
1739
2175
|
expr
|
|
@@ -2209,12 +2645,19 @@ class JavascriptParser extends Parser {
|
|
|
2209
2645
|
}
|
|
2210
2646
|
|
|
2211
2647
|
/**
|
|
2212
|
-
*
|
|
2213
|
-
*
|
|
2648
|
+
* Report what the program imports and re-exports, before anything reads a
|
|
2649
|
+
* name. The list is what the parser recorded, in source order.
|
|
2650
|
+
* @param {ModuleDeclarations} declarations the program's module declarations
|
|
2214
2651
|
*/
|
|
2215
|
-
|
|
2216
|
-
for (let index = 0, len =
|
|
2217
|
-
const statement =
|
|
2652
|
+
_modulePreWalkDeclarations(declarations) {
|
|
2653
|
+
for (let index = 0, len = declarations.length; index < len; index += 2) {
|
|
2654
|
+
const statement =
|
|
2655
|
+
/** @type {ModuleDeclaration} */
|
|
2656
|
+
(declarations[index]);
|
|
2657
|
+
// what precedes it decides whether removing it joins two statements
|
|
2658
|
+
this.prevStatement =
|
|
2659
|
+
/** @type {Statement | undefined} */
|
|
2660
|
+
(declarations[index + 1]);
|
|
2218
2661
|
/** @type {StatementPath} */
|
|
2219
2662
|
(this.statementPath).push(statement);
|
|
2220
2663
|
switch (statement.type) {
|
|
@@ -2235,19 +2678,212 @@ class JavascriptParser extends Parser {
|
|
|
2235
2678
|
}
|
|
2236
2679
|
|
|
2237
2680
|
/**
|
|
2238
|
-
*
|
|
2681
|
+
* Declare what the scope the node opens hoists, before anything reads a
|
|
2682
|
+
* name in it.
|
|
2683
|
+
* @param {Program | BlockStatement} node the node owning the scope
|
|
2684
|
+
*/
|
|
2685
|
+
_preWalkScope(node) {
|
|
2686
|
+
// BACKWARD-COMPAT START
|
|
2687
|
+
if (this._needsFullPreWalk || this.hooks.preStatement.taps.length !== 0) {
|
|
2688
|
+
if (node.type === "Program") this.preWalkStatements(node.body);
|
|
2689
|
+
else this.preWalkStatement(node);
|
|
2690
|
+
return;
|
|
2691
|
+
}
|
|
2692
|
+
// BACKWARD-COMPAT END
|
|
2693
|
+
this._preWalkHoistedDeclarations(
|
|
2694
|
+
hoistedDeclarationsOf(node, this._hasParserRecord)
|
|
2695
|
+
);
|
|
2696
|
+
}
|
|
2697
|
+
|
|
2698
|
+
/**
|
|
2699
|
+
* Declare what hoists to the scope being entered, from what the parser
|
|
2700
|
+
* recorded while reading it. `prevStatement` is not available here.
|
|
2701
|
+
* @param {HoistedDeclarations} hoisted what the scope declares
|
|
2702
|
+
*/
|
|
2703
|
+
_preWalkHoistedDeclarations(hoisted) {
|
|
2704
|
+
for (let index = 0, len = hoisted.length; index < len; index++) {
|
|
2705
|
+
// WHY: the statements between two declarations are not read here, so
|
|
2706
|
+
// the one before this declaration is unknown rather than the previous
|
|
2707
|
+
// declaration. A tap needing it taps `preStatement`, which walks.
|
|
2708
|
+
this.prevStatement = undefined;
|
|
2709
|
+
this.preWalkStatement(hoisted[index]);
|
|
2710
|
+
}
|
|
2711
|
+
}
|
|
2712
|
+
|
|
2713
|
+
// BACKWARD-COMPAT START
|
|
2714
|
+
/**
|
|
2715
|
+
* Walk every statement of a scope to declare what hoists to it. Only a tap
|
|
2716
|
+
* on the deprecated `preStatement` hook asks for this.
|
|
2239
2717
|
* @param {(Statement | ModuleDeclaration)[]} statements statements
|
|
2718
|
+
* @deprecated TODO webpack 6: remove, with the `preStatement` hook
|
|
2240
2719
|
*/
|
|
2241
2720
|
preWalkStatements(statements) {
|
|
2721
|
+
for (let index = 0, len = statements.length; index < len; index++) {
|
|
2722
|
+
this.preWalkStatement(statements[index]);
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
|
|
2726
|
+
/**
|
|
2727
|
+
* Pre walk block statement.
|
|
2728
|
+
* @param {BlockStatement} statement block statement
|
|
2729
|
+
* @deprecated TODO webpack 6: remove, with the `preStatement` hook
|
|
2730
|
+
*/
|
|
2731
|
+
preWalkBlockStatement(statement) {
|
|
2732
|
+
this.preWalkStatements(statement.body);
|
|
2733
|
+
}
|
|
2734
|
+
|
|
2735
|
+
/**
|
|
2736
|
+
* Pre walk if statement.
|
|
2737
|
+
* @param {IfStatement} statement if statement
|
|
2738
|
+
* @deprecated TODO webpack 6: remove, with the `preStatement` hook
|
|
2739
|
+
*/
|
|
2740
|
+
preWalkIfStatement(statement) {
|
|
2741
|
+
this.preWalkStatement(statement.consequent);
|
|
2742
|
+
if (statement.alternate) {
|
|
2743
|
+
this.preWalkStatement(statement.alternate);
|
|
2744
|
+
}
|
|
2745
|
+
}
|
|
2746
|
+
|
|
2747
|
+
/**
|
|
2748
|
+
* Pre walk labeled statement.
|
|
2749
|
+
* @param {LabeledStatement} statement labeled statement
|
|
2750
|
+
* @deprecated TODO webpack 6: remove, with the `preStatement` hook
|
|
2751
|
+
*/
|
|
2752
|
+
preWalkLabeledStatement(statement) {
|
|
2753
|
+
this.preWalkStatement(statement.body);
|
|
2754
|
+
}
|
|
2755
|
+
|
|
2756
|
+
/**
|
|
2757
|
+
* Pre walk with statement.
|
|
2758
|
+
* @param {WithStatement} statement with statement
|
|
2759
|
+
* @deprecated TODO webpack 6: remove, with the `preStatement` hook
|
|
2760
|
+
*/
|
|
2761
|
+
preWalkWithStatement(statement) {
|
|
2762
|
+
this.preWalkStatement(statement.body);
|
|
2763
|
+
}
|
|
2764
|
+
|
|
2765
|
+
/**
|
|
2766
|
+
* Pre walk switch statement.
|
|
2767
|
+
* @param {SwitchStatement} statement switch statement
|
|
2768
|
+
* @deprecated TODO webpack 6: remove, with the `preStatement` hook
|
|
2769
|
+
*/
|
|
2770
|
+
preWalkSwitchStatement(statement) {
|
|
2771
|
+
this.preWalkSwitchCases(statement.cases);
|
|
2772
|
+
}
|
|
2773
|
+
|
|
2774
|
+
/**
|
|
2775
|
+
* Pre walk switch cases.
|
|
2776
|
+
* @param {SwitchCase[]} switchCases switch cases
|
|
2777
|
+
* @deprecated TODO webpack 6: remove, with the `preStatement` hook
|
|
2778
|
+
*/
|
|
2779
|
+
preWalkSwitchCases(switchCases) {
|
|
2780
|
+
for (let index = 0, len = switchCases.length; index < len; index++) {
|
|
2781
|
+
this.preWalkStatements(switchCases[index].consequent);
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2784
|
+
|
|
2785
|
+
/**
|
|
2786
|
+
* Pre walk try statement.
|
|
2787
|
+
* @param {TryStatement} statement try statement
|
|
2788
|
+
* @deprecated TODO webpack 6: remove, with the `preStatement` hook
|
|
2789
|
+
*/
|
|
2790
|
+
preWalkTryStatement(statement) {
|
|
2791
|
+
this.preWalkStatement(statement.block);
|
|
2792
|
+
if (statement.handler) this.preWalkCatchClause(statement.handler);
|
|
2793
|
+
if (statement.finalizer) this.preWalkStatement(statement.finalizer);
|
|
2794
|
+
}
|
|
2795
|
+
|
|
2796
|
+
/**
|
|
2797
|
+
* Pre walk catch clause.
|
|
2798
|
+
* @param {CatchClause} catchClause catch clause
|
|
2799
|
+
* @deprecated TODO webpack 6: remove, with the `preStatement` hook
|
|
2800
|
+
*/
|
|
2801
|
+
preWalkCatchClause(catchClause) {
|
|
2802
|
+
this.preWalkStatement(catchClause.body);
|
|
2803
|
+
}
|
|
2804
|
+
|
|
2805
|
+
/**
|
|
2806
|
+
* Pre walk while statement.
|
|
2807
|
+
* @param {WhileStatement} statement while statement
|
|
2808
|
+
* @deprecated TODO webpack 6: remove, with the `preStatement` hook
|
|
2809
|
+
*/
|
|
2810
|
+
preWalkWhileStatement(statement) {
|
|
2811
|
+
this.preWalkStatement(statement.body);
|
|
2812
|
+
}
|
|
2813
|
+
|
|
2814
|
+
/**
|
|
2815
|
+
* Pre walk do while statement.
|
|
2816
|
+
* @param {DoWhileStatement} statement do while statement
|
|
2817
|
+
* @deprecated TODO webpack 6: remove, with the `preStatement` hook
|
|
2818
|
+
*/
|
|
2819
|
+
preWalkDoWhileStatement(statement) {
|
|
2820
|
+
this.preWalkStatement(statement.body);
|
|
2821
|
+
}
|
|
2822
|
+
|
|
2823
|
+
/**
|
|
2824
|
+
* Pre walk for statement.
|
|
2825
|
+
* @param {ForStatement} statement for statement
|
|
2826
|
+
* @deprecated TODO webpack 6: remove, with the `preStatement` hook
|
|
2827
|
+
*/
|
|
2828
|
+
preWalkForStatement(statement) {
|
|
2829
|
+
if (statement.init && statement.init.type === "VariableDeclaration") {
|
|
2830
|
+
this.preWalkStatement(statement.init);
|
|
2831
|
+
}
|
|
2832
|
+
this.preWalkStatement(statement.body);
|
|
2833
|
+
}
|
|
2834
|
+
|
|
2835
|
+
/**
|
|
2836
|
+
* Pre walk for in statement.
|
|
2837
|
+
* @param {ForInStatement} statement for in statement
|
|
2838
|
+
* @deprecated TODO webpack 6: remove, with the `preStatement` hook
|
|
2839
|
+
*/
|
|
2840
|
+
preWalkForInStatement(statement) {
|
|
2841
|
+
if (statement.left.type === "VariableDeclaration") {
|
|
2842
|
+
this.preWalkStatement(statement.left);
|
|
2843
|
+
}
|
|
2844
|
+
this.preWalkStatement(statement.body);
|
|
2845
|
+
}
|
|
2846
|
+
|
|
2847
|
+
/**
|
|
2848
|
+
* Pre walk for of statement. `for await` is reported by the walk, not here.
|
|
2849
|
+
* @param {ForOfStatement} statement for of statement
|
|
2850
|
+
* @deprecated TODO webpack 6: remove, with the `preStatement` hook
|
|
2851
|
+
*/
|
|
2852
|
+
preWalkForOfStatement(statement) {
|
|
2853
|
+
if (statement.left.type === "VariableDeclaration") {
|
|
2854
|
+
this.preWalkStatement(statement.left);
|
|
2855
|
+
}
|
|
2856
|
+
this.preWalkStatement(statement.body);
|
|
2857
|
+
}
|
|
2858
|
+
|
|
2859
|
+
/**
|
|
2860
|
+
* Scan every top-level statement for the program's module declarations.
|
|
2861
|
+
* The parser records them now, so nothing inside webpack scans for them.
|
|
2862
|
+
* @deprecated TODO webpack 6: remove
|
|
2863
|
+
* @param {(Statement | ModuleDeclaration)[]} statements statements
|
|
2864
|
+
*/
|
|
2865
|
+
modulePreWalkStatements(statements) {
|
|
2866
|
+
/** @type {ModuleDeclarations} */
|
|
2867
|
+
const declarations = [];
|
|
2242
2868
|
for (let index = 0, len = statements.length; index < len; index++) {
|
|
2243
2869
|
const statement = statements[index];
|
|
2244
|
-
|
|
2870
|
+
if (MODULE_STATEMENT_TYPES.has(statement.type)) {
|
|
2871
|
+
declarations.push(
|
|
2872
|
+
statement,
|
|
2873
|
+
index === 0 ? undefined : statements[index - 1]
|
|
2874
|
+
);
|
|
2875
|
+
}
|
|
2245
2876
|
}
|
|
2877
|
+
this._modulePreWalkDeclarations(declarations);
|
|
2246
2878
|
}
|
|
2879
|
+
// BACKWARD-COMPAT END
|
|
2247
2880
|
|
|
2881
|
+
// BACKWARD-COMPAT START
|
|
2248
2882
|
/**
|
|
2249
|
-
*
|
|
2883
|
+
* Walk every statement of a list to declare what it binds. Only a tap on the
|
|
2884
|
+
* deprecated `blockPreStatement` hook asks for this.
|
|
2250
2885
|
* @param {(Statement | ModuleDeclaration)[]} statements statements
|
|
2886
|
+
* @deprecated TODO webpack 6: remove, with the `blockPreStatement` hook
|
|
2251
2887
|
*/
|
|
2252
2888
|
blockPreWalkStatements(statements) {
|
|
2253
2889
|
for (let index = 0, len = statements.length; index < len; index++) {
|
|
@@ -2255,6 +2891,68 @@ class JavascriptParser extends Parser {
|
|
|
2255
2891
|
this.blockPreWalkStatement(statement);
|
|
2256
2892
|
}
|
|
2257
2893
|
}
|
|
2894
|
+
// BACKWARD-COMPAT END
|
|
2895
|
+
|
|
2896
|
+
/**
|
|
2897
|
+
* Declare what the statement list binds into its own block scope, before any
|
|
2898
|
+
* of it is walked. The list is what the parser recorded while reading it.
|
|
2899
|
+
* @param {Program | BlockStatement | StaticBlock | SwitchCase} node the node owning the list
|
|
2900
|
+
* @param {(Statement | ModuleDeclaration)[]} statements the list it holds
|
|
2901
|
+
*/
|
|
2902
|
+
_blockPreWalkScope(node, statements) {
|
|
2903
|
+
// BACKWARD-COMPAT START
|
|
2904
|
+
if (
|
|
2905
|
+
this._needsFullBlockPreWalk ||
|
|
2906
|
+
this.hooks.blockPreStatement.taps.length !== 0
|
|
2907
|
+
) {
|
|
2908
|
+
this.blockPreWalkStatements(statements);
|
|
2909
|
+
return;
|
|
2910
|
+
}
|
|
2911
|
+
// BACKWARD-COMPAT END
|
|
2912
|
+
/** @type {BlockDeclarations | undefined} */
|
|
2913
|
+
let recorded;
|
|
2914
|
+
if (this._hasParserRecord) {
|
|
2915
|
+
recorded = /** @type {EXPECTED_ANY} */ (node)[BLOCK_DECLARATIONS];
|
|
2916
|
+
// 72.8% of the lists a build reads declare nothing, and saying so is
|
|
2917
|
+
// the whole pass for them
|
|
2918
|
+
if (recorded === 0) return;
|
|
2919
|
+
}
|
|
2920
|
+
if (recorded === undefined) {
|
|
2921
|
+
recorded = collectBlockDeclarations(statements);
|
|
2922
|
+
if (recorded === 0) return;
|
|
2923
|
+
}
|
|
2924
|
+
this._blockPreWalkDeclarations(statements, recorded);
|
|
2925
|
+
}
|
|
2926
|
+
|
|
2927
|
+
/**
|
|
2928
|
+
* Declare what the recorded statements of the list bind, in source order.
|
|
2929
|
+
* @param {(Statement | ModuleDeclaration)[]} statements the whole list
|
|
2930
|
+
* @param {BlockDeclarations} declarations which of them declare
|
|
2931
|
+
*/
|
|
2932
|
+
_blockPreWalkDeclarations(statements, declarations) {
|
|
2933
|
+
if (typeof declarations === "number") {
|
|
2934
|
+
for (let bits = declarations; bits !== 0; bits &= bits - 1) {
|
|
2935
|
+
this._blockPreWalkAt(statements, 31 - Math.clz32(bits & -bits));
|
|
2936
|
+
}
|
|
2937
|
+
return;
|
|
2938
|
+
}
|
|
2939
|
+
for (let index = 0, len = declarations.length; index < len; index++) {
|
|
2940
|
+
this._blockPreWalkAt(statements, declarations[index]);
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2943
|
+
|
|
2944
|
+
/**
|
|
2945
|
+
* Declare what one statement of the list binds, with the statement written
|
|
2946
|
+
* before it, so a tap reading `prevStatement` sees what the walk would show.
|
|
2947
|
+
* @param {(Statement | ModuleDeclaration)[]} statements the whole list
|
|
2948
|
+
* @param {number} index which statement declares
|
|
2949
|
+
*/
|
|
2950
|
+
_blockPreWalkAt(statements, index) {
|
|
2951
|
+
// the first statement of the list has nothing before it, and leaves
|
|
2952
|
+
// whatever the caller set standing, as walking the whole list did
|
|
2953
|
+
if (index !== 0) this.prevStatement = statements[index - 1];
|
|
2954
|
+
this.blockPreWalkStatement(statements[index]);
|
|
2955
|
+
}
|
|
2258
2956
|
|
|
2259
2957
|
/**
|
|
2260
2958
|
* Walking iterates the statements and expressions and processes them
|
|
@@ -2304,21 +3002,22 @@ class JavascriptParser extends Parser {
|
|
|
2304
3002
|
(this.statementPath).pop();
|
|
2305
3003
|
return;
|
|
2306
3004
|
}
|
|
2307
|
-
//
|
|
2308
|
-
//
|
|
3005
|
+
// a class declaration reaches here for the typed hook alone: defining it
|
|
3006
|
+
// is the block pass's. The rest are only walked into by the deprecated
|
|
3007
|
+
// statement walk, which a tap expecting every statement turns back on.
|
|
2309
3008
|
switch (statement.type) {
|
|
2310
3009
|
case "VariableDeclaration":
|
|
2311
3010
|
this.preWalkVariableDeclaration(statement);
|
|
2312
3011
|
break;
|
|
3012
|
+
case "FunctionDeclaration":
|
|
3013
|
+
this.preWalkFunctionDeclaration(statement);
|
|
3014
|
+
break;
|
|
2313
3015
|
case "IfStatement":
|
|
2314
3016
|
this.preWalkIfStatement(statement);
|
|
2315
3017
|
break;
|
|
2316
3018
|
case "BlockStatement":
|
|
2317
3019
|
this.preWalkBlockStatement(statement);
|
|
2318
3020
|
break;
|
|
2319
|
-
case "FunctionDeclaration":
|
|
2320
|
-
this.preWalkFunctionDeclaration(statement);
|
|
2321
|
-
break;
|
|
2322
3021
|
case "ForStatement":
|
|
2323
3022
|
this.preWalkForStatement(statement);
|
|
2324
3023
|
break;
|
|
@@ -2491,26 +3190,20 @@ class JavascriptParser extends Parser {
|
|
|
2491
3190
|
}
|
|
2492
3191
|
|
|
2493
3192
|
// Real Statements
|
|
2494
|
-
/**
|
|
2495
|
-
* Pre walk block statement.
|
|
2496
|
-
* @param {BlockStatement} statement block statement
|
|
2497
|
-
*/
|
|
2498
|
-
preWalkBlockStatement(statement) {
|
|
2499
|
-
this.preWalkStatements(statement.body);
|
|
2500
|
-
}
|
|
2501
3193
|
|
|
2502
3194
|
/**
|
|
2503
3195
|
* Walk block statement.
|
|
2504
3196
|
* @param {BlockStatement | StaticBlock} statement block statement
|
|
2505
3197
|
*/
|
|
2506
3198
|
walkBlockStatement(statement) {
|
|
2507
|
-
this.
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
3199
|
+
const oldScope = this._enterBlockScope();
|
|
3200
|
+
const body = statement.body;
|
|
3201
|
+
const prev = this.prevStatement;
|
|
3202
|
+
this._blockPreWalkScope(statement, body);
|
|
3203
|
+
this.prevStatement = prev;
|
|
3204
|
+
this.walkStatements(body);
|
|
3205
|
+
|
|
3206
|
+
this._exitBlockScope(oldScope, true);
|
|
2514
3207
|
}
|
|
2515
3208
|
|
|
2516
3209
|
/**
|
|
@@ -2521,17 +3214,6 @@ class JavascriptParser extends Parser {
|
|
|
2521
3214
|
this.walkExpression(statement.expression);
|
|
2522
3215
|
}
|
|
2523
3216
|
|
|
2524
|
-
/**
|
|
2525
|
-
* Pre walk if statement.
|
|
2526
|
-
* @param {IfStatement} statement if statement
|
|
2527
|
-
*/
|
|
2528
|
-
preWalkIfStatement(statement) {
|
|
2529
|
-
this.preWalkStatement(statement.consequent);
|
|
2530
|
-
if (statement.alternate) {
|
|
2531
|
-
this.preWalkStatement(statement.alternate);
|
|
2532
|
-
}
|
|
2533
|
-
}
|
|
2534
|
-
|
|
2535
3217
|
/**
|
|
2536
3218
|
* Walks a conditional branch with its guard frame (if any) pushed onto the
|
|
2537
3219
|
* parser-state guard stack for the duration of the branch body.
|
|
@@ -2562,18 +3244,27 @@ class JavascriptParser extends Parser {
|
|
|
2562
3244
|
if (result === undefined) {
|
|
2563
3245
|
const guard = this.hooks.collectGuards.call(statement.test);
|
|
2564
3246
|
this.walkExpression(statement.test);
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
3247
|
+
// allocate the branch closure only when a guard frame needs pushing
|
|
3248
|
+
if (guard && guard.consequent) {
|
|
3249
|
+
this.walkGuardedBranch(guard.consequent, () =>
|
|
3250
|
+
this.walkNestedStatement(statement.consequent)
|
|
3251
|
+
);
|
|
3252
|
+
} else {
|
|
3253
|
+
this.walkNestedStatement(statement.consequent);
|
|
3254
|
+
}
|
|
2568
3255
|
|
|
2569
3256
|
const consequentTerminated = this.scope.terminated;
|
|
2570
3257
|
this.scope.terminated = undefined;
|
|
2571
3258
|
|
|
2572
3259
|
if (statement.alternate) {
|
|
2573
3260
|
const alternate = statement.alternate;
|
|
2574
|
-
|
|
2575
|
-
this.
|
|
2576
|
-
|
|
3261
|
+
if (guard && guard.alternate) {
|
|
3262
|
+
this.walkGuardedBranch(guard.alternate, () =>
|
|
3263
|
+
this.walkNestedStatement(alternate)
|
|
3264
|
+
);
|
|
3265
|
+
} else {
|
|
3266
|
+
this.walkNestedStatement(alternate);
|
|
3267
|
+
}
|
|
2577
3268
|
}
|
|
2578
3269
|
|
|
2579
3270
|
const alternateTerminated = this.scope.terminated;
|
|
@@ -2589,14 +3280,6 @@ class JavascriptParser extends Parser {
|
|
|
2589
3280
|
}
|
|
2590
3281
|
}
|
|
2591
3282
|
|
|
2592
|
-
/**
|
|
2593
|
-
* Pre walk labeled statement.
|
|
2594
|
-
* @param {LabeledStatement} statement with statement
|
|
2595
|
-
*/
|
|
2596
|
-
preWalkLabeledStatement(statement) {
|
|
2597
|
-
this.preWalkStatement(statement.body);
|
|
2598
|
-
}
|
|
2599
|
-
|
|
2600
3283
|
/**
|
|
2601
3284
|
* Walk labeled statement.
|
|
2602
3285
|
* @param {LabeledStatement} statement with statement
|
|
@@ -2607,17 +3290,10 @@ class JavascriptParser extends Parser {
|
|
|
2607
3290
|
const result = hook.call(statement);
|
|
2608
3291
|
if (result === true) return;
|
|
2609
3292
|
}
|
|
2610
|
-
this.
|
|
2611
|
-
|
|
2612
|
-
});
|
|
2613
|
-
}
|
|
3293
|
+
const oldScope = this._enterBlockScope();
|
|
3294
|
+
this.walkNestedStatement(statement.body);
|
|
2614
3295
|
|
|
2615
|
-
|
|
2616
|
-
* Pre walk with statement.
|
|
2617
|
-
* @param {WithStatement} statement with statement
|
|
2618
|
-
*/
|
|
2619
|
-
preWalkWithStatement(statement) {
|
|
2620
|
-
this.preWalkStatement(statement.body);
|
|
3296
|
+
this._exitBlockScope(oldScope, false);
|
|
2621
3297
|
}
|
|
2622
3298
|
|
|
2623
3299
|
/**
|
|
@@ -2631,18 +3307,11 @@ class JavascriptParser extends Parser {
|
|
|
2631
3307
|
statement
|
|
2632
3308
|
);
|
|
2633
3309
|
}
|
|
2634
|
-
this.
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
});
|
|
2638
|
-
}
|
|
3310
|
+
const oldScope = this._enterBlockScope();
|
|
3311
|
+
this.walkExpression(statement.object);
|
|
3312
|
+
this.walkNestedStatement(statement.body);
|
|
2639
3313
|
|
|
2640
|
-
|
|
2641
|
-
* Pre walk switch statement.
|
|
2642
|
-
* @param {SwitchStatement} statement switch statement
|
|
2643
|
-
*/
|
|
2644
|
-
preWalkSwitchStatement(statement) {
|
|
2645
|
-
this.preWalkSwitchCases(statement.cases);
|
|
3314
|
+
this._exitBlockScope(oldScope, false);
|
|
2646
3315
|
}
|
|
2647
3316
|
|
|
2648
3317
|
/**
|
|
@@ -2686,16 +3355,6 @@ class JavascriptParser extends Parser {
|
|
|
2686
3355
|
this.walkTerminatingStatement(statement);
|
|
2687
3356
|
}
|
|
2688
3357
|
|
|
2689
|
-
/**
|
|
2690
|
-
* Pre walk try statement.
|
|
2691
|
-
* @param {TryStatement} statement try statement
|
|
2692
|
-
*/
|
|
2693
|
-
preWalkTryStatement(statement) {
|
|
2694
|
-
this.preWalkStatement(statement.block);
|
|
2695
|
-
if (statement.handler) this.preWalkCatchClause(statement.handler);
|
|
2696
|
-
if (statement.finalizer) this.preWalkStatement(statement.finalizer);
|
|
2697
|
-
}
|
|
2698
|
-
|
|
2699
3358
|
/**
|
|
2700
3359
|
* Walk try statement.
|
|
2701
3360
|
* @param {TryStatement} statement try statement
|
|
@@ -2734,53 +3393,28 @@ class JavascriptParser extends Parser {
|
|
|
2734
3393
|
}
|
|
2735
3394
|
}
|
|
2736
3395
|
|
|
2737
|
-
/**
|
|
2738
|
-
* Pre walk while statement.
|
|
2739
|
-
* @param {WhileStatement} statement while statement
|
|
2740
|
-
*/
|
|
2741
|
-
preWalkWhileStatement(statement) {
|
|
2742
|
-
this.preWalkStatement(statement.body);
|
|
2743
|
-
}
|
|
2744
|
-
|
|
2745
3396
|
/**
|
|
2746
3397
|
* Walk while statement.
|
|
2747
3398
|
* @param {WhileStatement} statement while statement
|
|
2748
3399
|
*/
|
|
2749
3400
|
walkWhileStatement(statement) {
|
|
2750
|
-
this.
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
});
|
|
2754
|
-
}
|
|
3401
|
+
const oldScope = this._enterBlockScope();
|
|
3402
|
+
this.walkExpression(statement.test);
|
|
3403
|
+
this.walkNestedStatement(statement.body);
|
|
2755
3404
|
|
|
2756
|
-
|
|
2757
|
-
* Pre walk do while statement.
|
|
2758
|
-
* @param {DoWhileStatement} statement do while statement
|
|
2759
|
-
*/
|
|
2760
|
-
preWalkDoWhileStatement(statement) {
|
|
2761
|
-
this.preWalkStatement(statement.body);
|
|
2762
|
-
}
|
|
2763
|
-
|
|
2764
|
-
/**
|
|
2765
|
-
* Walk do while statement.
|
|
2766
|
-
* @param {DoWhileStatement} statement do while statement
|
|
2767
|
-
*/
|
|
2768
|
-
walkDoWhileStatement(statement) {
|
|
2769
|
-
this.inBlockScope(() => {
|
|
2770
|
-
this.walkNestedStatement(statement.body);
|
|
2771
|
-
this.walkExpression(statement.test);
|
|
2772
|
-
});
|
|
3405
|
+
this._exitBlockScope(oldScope, false);
|
|
2773
3406
|
}
|
|
2774
3407
|
|
|
2775
|
-
/**
|
|
2776
|
-
*
|
|
2777
|
-
* @param {
|
|
2778
|
-
*/
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
3408
|
+
/**
|
|
3409
|
+
* Walk do while statement.
|
|
3410
|
+
* @param {DoWhileStatement} statement do while statement
|
|
3411
|
+
*/
|
|
3412
|
+
walkDoWhileStatement(statement) {
|
|
3413
|
+
const oldScope = this._enterBlockScope();
|
|
3414
|
+
this.walkNestedStatement(statement.body);
|
|
3415
|
+
this.walkExpression(statement.test);
|
|
3416
|
+
|
|
3417
|
+
this._exitBlockScope(oldScope, false);
|
|
2784
3418
|
}
|
|
2785
3419
|
|
|
2786
3420
|
/**
|
|
@@ -2788,46 +3422,36 @@ class JavascriptParser extends Parser {
|
|
|
2788
3422
|
* @param {ForStatement} statement for statement
|
|
2789
3423
|
*/
|
|
2790
3424
|
walkForStatement(statement) {
|
|
2791
|
-
this.
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
} else {
|
|
2798
|
-
this.walkExpression(statement.init);
|
|
2799
|
-
}
|
|
2800
|
-
}
|
|
2801
|
-
if (statement.test) {
|
|
2802
|
-
this.walkExpression(statement.test);
|
|
2803
|
-
}
|
|
2804
|
-
if (statement.update) {
|
|
2805
|
-
this.walkExpression(statement.update);
|
|
2806
|
-
}
|
|
2807
|
-
|
|
2808
|
-
const body = statement.body;
|
|
2809
|
-
|
|
2810
|
-
if (body.type === "BlockStatement") {
|
|
2811
|
-
// no need to add additional scope
|
|
2812
|
-
const prev = this.prevStatement;
|
|
2813
|
-
this.blockPreWalkStatements(body.body);
|
|
2814
|
-
this.prevStatement = prev;
|
|
2815
|
-
this.walkStatements(body.body);
|
|
3425
|
+
const oldScope = this._enterBlockScope();
|
|
3426
|
+
if (statement.init) {
|
|
3427
|
+
if (statement.init.type === "VariableDeclaration") {
|
|
3428
|
+
this.blockPreWalkVariableDeclaration(statement.init);
|
|
3429
|
+
this.prevStatement = undefined;
|
|
3430
|
+
this.walkStatement(statement.init);
|
|
2816
3431
|
} else {
|
|
2817
|
-
this.
|
|
3432
|
+
this.walkExpression(statement.init);
|
|
2818
3433
|
}
|
|
2819
|
-
}
|
|
2820
|
-
|
|
3434
|
+
}
|
|
3435
|
+
if (statement.test) {
|
|
3436
|
+
this.walkExpression(statement.test);
|
|
3437
|
+
}
|
|
3438
|
+
if (statement.update) {
|
|
3439
|
+
this.walkExpression(statement.update);
|
|
3440
|
+
}
|
|
2821
3441
|
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
this.
|
|
3442
|
+
const body = statement.body;
|
|
3443
|
+
|
|
3444
|
+
if (body.type === "BlockStatement") {
|
|
3445
|
+
// no need to add additional scope
|
|
3446
|
+
const prev = this.prevStatement;
|
|
3447
|
+
this._blockPreWalkScope(body, body.body);
|
|
3448
|
+
this.prevStatement = prev;
|
|
3449
|
+
this.walkStatements(body.body);
|
|
3450
|
+
} else {
|
|
3451
|
+
this.walkNestedStatement(body);
|
|
2829
3452
|
}
|
|
2830
|
-
|
|
3453
|
+
|
|
3454
|
+
this._exitBlockScope(oldScope, false);
|
|
2831
3455
|
}
|
|
2832
3456
|
|
|
2833
3457
|
/**
|
|
@@ -2835,71 +3459,62 @@ class JavascriptParser extends Parser {
|
|
|
2835
3459
|
* @param {ForInStatement} statement for statement
|
|
2836
3460
|
*/
|
|
2837
3461
|
walkForInStatement(statement) {
|
|
2838
|
-
this.
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
3462
|
+
const oldScope = this._enterBlockScope();
|
|
3463
|
+
if (statement.left.type === "VariableDeclaration") {
|
|
3464
|
+
this.blockPreWalkVariableDeclaration(statement.left);
|
|
3465
|
+
this.walkVariableDeclaration(statement.left);
|
|
3466
|
+
} else if (!this._walkWriteTarget(statement.left, statement)) {
|
|
3467
|
+
this.walkPattern(statement.left);
|
|
3468
|
+
}
|
|
2845
3469
|
|
|
2846
|
-
|
|
3470
|
+
this.walkExpression(statement.right);
|
|
2847
3471
|
|
|
2848
|
-
|
|
3472
|
+
const body = statement.body;
|
|
2849
3473
|
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
3474
|
+
if (body.type === "BlockStatement") {
|
|
3475
|
+
// no need to add additional scope
|
|
3476
|
+
const prev = this.prevStatement;
|
|
3477
|
+
this._blockPreWalkScope(body, body.body);
|
|
3478
|
+
this.prevStatement = prev;
|
|
3479
|
+
this.walkStatements(body.body);
|
|
3480
|
+
} else {
|
|
3481
|
+
this.walkNestedStatement(body);
|
|
3482
|
+
}
|
|
3483
|
+
|
|
3484
|
+
this._exitBlockScope(oldScope, false);
|
|
2860
3485
|
}
|
|
2861
3486
|
|
|
2862
3487
|
/**
|
|
2863
|
-
*
|
|
2864
|
-
* @param {ForOfStatement} statement statement
|
|
3488
|
+
* Walk for of statement.
|
|
3489
|
+
* @param {ForOfStatement} statement for statement
|
|
2865
3490
|
*/
|
|
2866
|
-
|
|
3491
|
+
walkForOfStatement(statement) {
|
|
2867
3492
|
if (statement.await && this.scope.topLevelScope === true) {
|
|
2868
3493
|
this.hooks.topLevelAwait.call(statement);
|
|
2869
3494
|
}
|
|
3495
|
+
const oldScope = this._enterBlockScope();
|
|
2870
3496
|
if (statement.left.type === "VariableDeclaration") {
|
|
2871
|
-
this.
|
|
3497
|
+
this.blockPreWalkVariableDeclaration(statement.left);
|
|
3498
|
+
this.walkVariableDeclaration(statement.left);
|
|
3499
|
+
} else if (!this._walkWriteTarget(statement.left, statement)) {
|
|
3500
|
+
this.walkPattern(statement.left);
|
|
2872
3501
|
}
|
|
2873
|
-
this.preWalkStatement(statement.body);
|
|
2874
|
-
}
|
|
2875
3502
|
|
|
2876
|
-
|
|
2877
|
-
* Walk for of statement.
|
|
2878
|
-
* @param {ForOfStatement} statement for statement
|
|
2879
|
-
*/
|
|
2880
|
-
walkForOfStatement(statement) {
|
|
2881
|
-
this.inBlockScope(() => {
|
|
2882
|
-
if (statement.left.type === "VariableDeclaration") {
|
|
2883
|
-
this.blockPreWalkVariableDeclaration(statement.left);
|
|
2884
|
-
this.walkVariableDeclaration(statement.left);
|
|
2885
|
-
} else {
|
|
2886
|
-
this.walkPattern(statement.left);
|
|
2887
|
-
}
|
|
3503
|
+
this.walkExpression(statement.right);
|
|
2888
3504
|
|
|
2889
|
-
|
|
3505
|
+
const body = statement.body;
|
|
2890
3506
|
|
|
2891
|
-
|
|
3507
|
+
if (body.type === "BlockStatement") {
|
|
3508
|
+
// no need to add additional scope
|
|
3509
|
+
const prev = this.prevStatement;
|
|
3510
|
+
this._blockPreWalkScope(body, body.body);
|
|
3511
|
+
this.prevStatement = prev;
|
|
3512
|
+
this.walkStatements(body.body);
|
|
3513
|
+
} else {
|
|
3514
|
+
this.walkNestedStatement(body);
|
|
3515
|
+
}
|
|
2892
3516
|
|
|
2893
|
-
|
|
2894
|
-
// no need to add additional scope
|
|
2895
|
-
const prev = this.prevStatement;
|
|
2896
|
-
this.blockPreWalkStatements(body.body);
|
|
2897
|
-
this.prevStatement = prev;
|
|
2898
|
-
this.walkStatements(body.body);
|
|
2899
|
-
} else {
|
|
2900
|
-
this.walkNestedStatement(body);
|
|
2901
|
-
}
|
|
2902
|
-
});
|
|
3517
|
+
this._exitBlockScope(oldScope, false);
|
|
2903
3518
|
}
|
|
2904
3519
|
|
|
2905
3520
|
/**
|
|
@@ -2925,19 +3540,20 @@ class JavascriptParser extends Parser {
|
|
|
2925
3540
|
if (this._strictInModuleOutput) {
|
|
2926
3541
|
this._checkStrictModeParams(statement.params);
|
|
2927
3542
|
}
|
|
2928
|
-
this.
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
3543
|
+
const oldScope = this._enterFunctionScope(true, statement.params);
|
|
3544
|
+
for (const param of statement.params) {
|
|
3545
|
+
this.walkPattern(param);
|
|
3546
|
+
}
|
|
2932
3547
|
|
|
2933
|
-
|
|
3548
|
+
this.detectMode(statement.body.body);
|
|
2934
3549
|
|
|
2935
|
-
|
|
3550
|
+
const prev = this.prevStatement;
|
|
2936
3551
|
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
3552
|
+
this._preWalkScope(statement.body);
|
|
3553
|
+
this.prevStatement = prev;
|
|
3554
|
+
this.walkStatement(statement.body);
|
|
3555
|
+
|
|
3556
|
+
this.scope = oldScope;
|
|
2941
3557
|
this.scope.topLevelScope = wasTopLevel;
|
|
2942
3558
|
}
|
|
2943
3559
|
|
|
@@ -3303,7 +3919,9 @@ class JavascriptParser extends Parser {
|
|
|
3303
3919
|
/** @type {OnIdent | undefined} */
|
|
3304
3920
|
let onIdent;
|
|
3305
3921
|
const checkStrictBindings = this._strictInModuleOutput;
|
|
3306
|
-
|
|
3922
|
+
const declarations = statement.declarations;
|
|
3923
|
+
for (let i = 0, len = declarations.length; i < len; i++) {
|
|
3924
|
+
const declarator = declarations[i];
|
|
3307
3925
|
if (declarator.type !== "VariableDeclarator") continue;
|
|
3308
3926
|
this.preWalkVariableDeclarator(declarator);
|
|
3309
3927
|
if (this.hooks.preDeclarator.call(declarator, statement)) continue;
|
|
@@ -3312,7 +3930,7 @@ class JavascriptParser extends Parser {
|
|
|
3312
3930
|
if (checkStrictBindings) this._checkStrictModeBinding(id.name, id);
|
|
3313
3931
|
// fast path: plain `const x =` skips the enterPattern dispatch and
|
|
3314
3932
|
// the per-declaration onIdent closure (only patterns need it)
|
|
3315
|
-
if (!this.
|
|
3933
|
+
if (!this._callHooksForName1(this.hooks.pattern, id.name, id)) {
|
|
3316
3934
|
this._defineVariableForDeclaration(id.name, id, hookMap);
|
|
3317
3935
|
}
|
|
3318
3936
|
} else {
|
|
@@ -3452,7 +4070,9 @@ class JavascriptParser extends Parser {
|
|
|
3452
4070
|
* @param {VariableDeclaration} statement variable declaration
|
|
3453
4071
|
*/
|
|
3454
4072
|
walkVariableDeclaration(statement) {
|
|
3455
|
-
|
|
4073
|
+
const declarations = statement.declarations;
|
|
4074
|
+
for (let i = 0, len = declarations.length; i < len; i++) {
|
|
4075
|
+
const declarator = declarations[i];
|
|
3456
4076
|
switch (declarator.type) {
|
|
3457
4077
|
case "VariableDeclarator": {
|
|
3458
4078
|
const renameIdentifier =
|
|
@@ -3507,64 +4127,40 @@ class JavascriptParser extends Parser {
|
|
|
3507
4127
|
this.walkClass(statement);
|
|
3508
4128
|
}
|
|
3509
4129
|
|
|
3510
|
-
/**
|
|
3511
|
-
* Pre walk switch cases.
|
|
3512
|
-
* @param {SwitchCase[]} switchCases switch statement
|
|
3513
|
-
*/
|
|
3514
|
-
preWalkSwitchCases(switchCases) {
|
|
3515
|
-
for (let index = 0, len = switchCases.length; index < len; index++) {
|
|
3516
|
-
const switchCase = switchCases[index];
|
|
3517
|
-
this.preWalkStatements(switchCase.consequent);
|
|
3518
|
-
}
|
|
3519
|
-
}
|
|
3520
|
-
|
|
3521
4130
|
/**
|
|
3522
4131
|
* Processes the provided switch case.
|
|
3523
4132
|
* @param {SwitchCase[]} switchCases switch statement
|
|
3524
4133
|
*/
|
|
3525
4134
|
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
|
-
}
|
|
4135
|
+
const oldScope = this._enterBlockScope();
|
|
4136
|
+
const len = switchCases.length;
|
|
4137
|
+
|
|
4138
|
+
// pre-walk every case first: a `const` declared in a later case is already
|
|
4139
|
+
// in scope for an earlier case that reads it (and fails at runtime)
|
|
4140
|
+
for (let index = 0; index < len; index++) {
|
|
4141
|
+
const switchCase = switchCases[index];
|
|
4142
|
+
|
|
4143
|
+
if (switchCase.consequent.length > 0) {
|
|
4144
|
+
const prev = this.prevStatement;
|
|
4145
|
+
this._blockPreWalkScope(switchCase, switchCase.consequent);
|
|
4146
|
+
this.prevStatement = prev;
|
|
3545
4147
|
}
|
|
4148
|
+
}
|
|
3546
4149
|
|
|
3547
|
-
|
|
3548
|
-
|
|
4150
|
+
for (let index = 0; index < len; index++) {
|
|
4151
|
+
const switchCase = switchCases[index];
|
|
3549
4152
|
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
4153
|
+
if (switchCase.test) {
|
|
4154
|
+
this.walkExpression(switchCase.test);
|
|
4155
|
+
}
|
|
3553
4156
|
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
}
|
|
4157
|
+
if (switchCase.consequent.length > 0) {
|
|
4158
|
+
this.walkStatements(switchCase.consequent);
|
|
4159
|
+
this.scope.terminated = undefined;
|
|
3558
4160
|
}
|
|
3559
|
-
}
|
|
3560
|
-
}
|
|
4161
|
+
}
|
|
3561
4162
|
|
|
3562
|
-
|
|
3563
|
-
* Pre walk catch clause.
|
|
3564
|
-
* @param {CatchClause} catchClause catch clause
|
|
3565
|
-
*/
|
|
3566
|
-
preWalkCatchClause(catchClause) {
|
|
3567
|
-
this.preWalkStatement(catchClause.body);
|
|
4163
|
+
this._exitBlockScope(oldScope, false);
|
|
3568
4164
|
}
|
|
3569
4165
|
|
|
3570
4166
|
/**
|
|
@@ -3572,22 +4168,23 @@ class JavascriptParser extends Parser {
|
|
|
3572
4168
|
* @param {CatchClause} catchClause catch clause
|
|
3573
4169
|
*/
|
|
3574
4170
|
walkCatchClause(catchClause) {
|
|
3575
|
-
this.
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
4171
|
+
const oldScope = this._enterBlockScope();
|
|
4172
|
+
// Error binding is optional in catch clause since ECMAScript 2019
|
|
4173
|
+
if (catchClause.param !== null) {
|
|
4174
|
+
this.enterPattern(catchClause.param, (ident, identifier) => {
|
|
4175
|
+
if (this._strictInModuleOutput) {
|
|
4176
|
+
this._checkStrictModeBinding(ident, identifier);
|
|
4177
|
+
}
|
|
4178
|
+
this.defineVariable(ident);
|
|
4179
|
+
});
|
|
4180
|
+
this.walkPattern(catchClause.param);
|
|
4181
|
+
}
|
|
4182
|
+
const prev = this.prevStatement;
|
|
4183
|
+
this.blockPreWalkStatement(catchClause.body);
|
|
4184
|
+
this.prevStatement = prev;
|
|
4185
|
+
this.walkStatement(catchClause.body);
|
|
4186
|
+
|
|
4187
|
+
this._exitBlockScope(oldScope, true);
|
|
3591
4188
|
}
|
|
3592
4189
|
|
|
3593
4190
|
/**
|
|
@@ -3885,19 +4482,20 @@ class JavascriptParser extends Parser {
|
|
|
3885
4482
|
this._checkStrictModeBinding(expression.id.name, expression.id);
|
|
3886
4483
|
}
|
|
3887
4484
|
}
|
|
3888
|
-
this.
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
4485
|
+
const oldScope = this._enterFunctionScope(true, scopeParams);
|
|
4486
|
+
for (const param of expression.params) {
|
|
4487
|
+
this.walkPattern(param);
|
|
4488
|
+
}
|
|
3892
4489
|
|
|
3893
|
-
|
|
4490
|
+
this.detectMode(expression.body.body);
|
|
3894
4491
|
|
|
3895
|
-
|
|
4492
|
+
const prev = this.prevStatement;
|
|
3896
4493
|
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
4494
|
+
this._preWalkScope(expression.body);
|
|
4495
|
+
this.prevStatement = prev;
|
|
4496
|
+
this.walkStatement(expression.body);
|
|
4497
|
+
|
|
4498
|
+
this.scope = oldScope;
|
|
3901
4499
|
this.scope.topLevelScope = wasTopLevel;
|
|
3902
4500
|
}
|
|
3903
4501
|
|
|
@@ -3911,20 +4509,21 @@ class JavascriptParser extends Parser {
|
|
|
3911
4509
|
if (this._strictInModuleOutput) {
|
|
3912
4510
|
this._checkStrictModeParams(expression.params);
|
|
3913
4511
|
}
|
|
3914
|
-
this.
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
4512
|
+
const oldScope = this._enterFunctionScope(false, expression.params);
|
|
4513
|
+
for (const param of expression.params) {
|
|
4514
|
+
this.walkPattern(param);
|
|
4515
|
+
}
|
|
4516
|
+
if (expression.body.type === "BlockStatement") {
|
|
4517
|
+
this.detectMode(expression.body.body);
|
|
4518
|
+
const prev = this.prevStatement;
|
|
4519
|
+
this._preWalkScope(expression.body);
|
|
4520
|
+
this.prevStatement = prev;
|
|
4521
|
+
this.walkStatement(expression.body);
|
|
4522
|
+
} else {
|
|
4523
|
+
this.walkExpression(expression.body);
|
|
4524
|
+
}
|
|
4525
|
+
|
|
4526
|
+
this.scope = oldScope;
|
|
3928
4527
|
this.scope.topLevelScope = wasTopLevel;
|
|
3929
4528
|
}
|
|
3930
4529
|
|
|
@@ -3978,9 +4577,98 @@ class JavascriptParser extends Parser {
|
|
|
3978
4577
|
) {
|
|
3979
4578
|
this._checkStrictModeAssignTarget(expression.argument.name, expression);
|
|
3980
4579
|
}
|
|
4580
|
+
if (this._walkWriteTarget(expression.argument, expression)) return;
|
|
3981
4581
|
this.walkExpression(expression.argument);
|
|
3982
4582
|
}
|
|
3983
4583
|
|
|
4584
|
+
/**
|
|
4585
|
+
* Offers a write that is not an assignment's left side — an update's target
|
|
4586
|
+
* or a loop's binding — to the taps that care, `assign` carrying only an
|
|
4587
|
+
* AssignmentExpression.
|
|
4588
|
+
* @param {Expression | Pattern} target the written reference
|
|
4589
|
+
* @param {WriteStatement} node the construct performing the write
|
|
4590
|
+
* @returns {boolean} true when a tap rendered the write itself
|
|
4591
|
+
*/
|
|
4592
|
+
_walkWriteTarget(target, node) {
|
|
4593
|
+
if (target.type === "Identifier") {
|
|
4594
|
+
return Boolean(
|
|
4595
|
+
this._callHooksForName1(this.hooks.write, target.name, node)
|
|
4596
|
+
);
|
|
4597
|
+
}
|
|
4598
|
+
if (target.type.endsWith("Pattern")) {
|
|
4599
|
+
this.enterPattern(/** @type {Pattern} */ (target), (name) => {
|
|
4600
|
+
this._callHooksForName1(this.hooks.write, name, node);
|
|
4601
|
+
});
|
|
4602
|
+
this._walkPatternWriteMembers(target, node);
|
|
4603
|
+
return false;
|
|
4604
|
+
}
|
|
4605
|
+
return Boolean(
|
|
4606
|
+
target.type === "MemberExpression" &&
|
|
4607
|
+
this._callWriteMemberChain(target, node)
|
|
4608
|
+
);
|
|
4609
|
+
}
|
|
4610
|
+
|
|
4611
|
+
/**
|
|
4612
|
+
* Offers the member expressions a destructuring target writes to the
|
|
4613
|
+
* `writeMemberChain` taps, which `enterPattern` passes over because they
|
|
4614
|
+
* bind no name.
|
|
4615
|
+
* @param {Pattern | Expression | null} pattern the destructuring target
|
|
4616
|
+
* @param {WriteStatement} node the construct performing the write
|
|
4617
|
+
* @returns {void}
|
|
4618
|
+
*/
|
|
4619
|
+
_walkPatternWriteMembers(pattern, node) {
|
|
4620
|
+
if (!pattern) return;
|
|
4621
|
+
switch (pattern.type) {
|
|
4622
|
+
case "MemberExpression":
|
|
4623
|
+
this._callWriteMemberChain(pattern, node);
|
|
4624
|
+
break;
|
|
4625
|
+
case "ObjectPattern":
|
|
4626
|
+
for (const property of pattern.properties) {
|
|
4627
|
+
this._walkPatternWriteMembers(
|
|
4628
|
+
property.type === "RestElement"
|
|
4629
|
+
? property.argument
|
|
4630
|
+
: /** @type {Pattern} */ (property.value),
|
|
4631
|
+
node
|
|
4632
|
+
);
|
|
4633
|
+
}
|
|
4634
|
+
break;
|
|
4635
|
+
case "ArrayPattern":
|
|
4636
|
+
for (const element of pattern.elements) {
|
|
4637
|
+
this._walkPatternWriteMembers(element, node);
|
|
4638
|
+
}
|
|
4639
|
+
break;
|
|
4640
|
+
case "AssignmentPattern":
|
|
4641
|
+
this._walkPatternWriteMembers(pattern.left, node);
|
|
4642
|
+
break;
|
|
4643
|
+
case "RestElement":
|
|
4644
|
+
this._walkPatternWriteMembers(pattern.argument, node);
|
|
4645
|
+
break;
|
|
4646
|
+
}
|
|
4647
|
+
}
|
|
4648
|
+
|
|
4649
|
+
/**
|
|
4650
|
+
* Offers a written member expression to the `writeMemberChain` taps.
|
|
4651
|
+
* @param {MemberExpression} target the written member expression
|
|
4652
|
+
* @param {WriteStatement} node the construct performing the write
|
|
4653
|
+
* @returns {boolean} true when a tap rendered the write itself
|
|
4654
|
+
*/
|
|
4655
|
+
_callWriteMemberChain(target, node) {
|
|
4656
|
+
return Boolean(
|
|
4657
|
+
this._resolveMemberExpression(target, ALLOWED_MEMBER_TYPES_EXPRESSION) ===
|
|
4658
|
+
1 &&
|
|
4659
|
+
this._hasHooksForInfo(
|
|
4660
|
+
this.hooks.writeMemberChain,
|
|
4661
|
+
/** @type {string | VariableInfo} */ (this._memberRootInfo)
|
|
4662
|
+
) &&
|
|
4663
|
+
this.callHooksForInfo(
|
|
4664
|
+
this.hooks.writeMemberChain,
|
|
4665
|
+
/** @type {string | VariableInfo} */ (this._memberRootInfo),
|
|
4666
|
+
node,
|
|
4667
|
+
this._members
|
|
4668
|
+
)
|
|
4669
|
+
);
|
|
4670
|
+
}
|
|
4671
|
+
|
|
3984
4672
|
/**
|
|
3985
4673
|
* Reports `arguments.callee` / `arguments.caller` — both throw a TypeError
|
|
3986
4674
|
* once the module runs in strict-mode ESM output.
|
|
@@ -4185,7 +4873,7 @@ class JavascriptParser extends Parser {
|
|
|
4185
4873
|
const renameIdentifier = this.getRenameIdentifier(expression.right);
|
|
4186
4874
|
if (
|
|
4187
4875
|
renameIdentifier &&
|
|
4188
|
-
this.
|
|
4876
|
+
this._callHooksForInfo1(
|
|
4189
4877
|
this.hooks.canRename,
|
|
4190
4878
|
renameIdentifier,
|
|
4191
4879
|
expression.right
|
|
@@ -4193,7 +4881,7 @@ class JavascriptParser extends Parser {
|
|
|
4193
4881
|
) {
|
|
4194
4882
|
// renaming "a = b;"
|
|
4195
4883
|
if (
|
|
4196
|
-
!this.
|
|
4884
|
+
!this._callHooksForInfo1(
|
|
4197
4885
|
this.hooks.rename,
|
|
4198
4886
|
renameIdentifier,
|
|
4199
4887
|
expression.right
|
|
@@ -4209,34 +4897,43 @@ class JavascriptParser extends Parser {
|
|
|
4209
4897
|
return;
|
|
4210
4898
|
}
|
|
4211
4899
|
this.walkExpression(expression.right);
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4900
|
+
// inlined enterPattern → enterIdentifier for the Identifier left side:
|
|
4901
|
+
// same hook sequence without the per-assignment closure
|
|
4902
|
+
const leftName = expression.left.name;
|
|
4903
|
+
if (
|
|
4904
|
+
!this._callHooksForName1(
|
|
4905
|
+
this.hooks.pattern,
|
|
4906
|
+
leftName,
|
|
4907
|
+
expression.left
|
|
4908
|
+
) &&
|
|
4909
|
+
!this._callHooksForName1(this.hooks.assign, leftName, expression)
|
|
4910
|
+
) {
|
|
4911
|
+
this.walkExpression(expression.left);
|
|
4912
|
+
}
|
|
4220
4913
|
} else if (expression.left.type.endsWith("Pattern")) {
|
|
4221
4914
|
this.walkExpression(expression.right);
|
|
4222
4915
|
this.enterPattern(expression.left, (name, _decl) => {
|
|
4223
|
-
if (!this.
|
|
4916
|
+
if (!this._callHooksForName1(this.hooks.assign, name, expression)) {
|
|
4224
4917
|
this.defineVariable(name);
|
|
4225
4918
|
}
|
|
4226
4919
|
});
|
|
4920
|
+
this._walkPatternWriteMembers(expression.left, expression);
|
|
4227
4921
|
this.walkPattern(expression.left);
|
|
4228
4922
|
} else if (expression.left.type === "MemberExpression") {
|
|
4229
|
-
const exprName = this.getMemberExpressionInfo(
|
|
4230
|
-
expression.left,
|
|
4231
|
-
ALLOWED_MEMBER_TYPES_EXPRESSION
|
|
4232
|
-
);
|
|
4233
4923
|
if (
|
|
4234
|
-
|
|
4924
|
+
this._resolveMemberExpression(
|
|
4925
|
+
expression.left,
|
|
4926
|
+
ALLOWED_MEMBER_TYPES_EXPRESSION
|
|
4927
|
+
) === 1 &&
|
|
4928
|
+
this._hasHooksForInfo(
|
|
4929
|
+
this.hooks.assignMemberChain,
|
|
4930
|
+
/** @type {string | VariableInfo} */ (this._memberRootInfo)
|
|
4931
|
+
) &&
|
|
4235
4932
|
this.callHooksForInfo(
|
|
4236
4933
|
this.hooks.assignMemberChain,
|
|
4237
|
-
|
|
4934
|
+
/** @type {string | VariableInfo} */ (this._memberRootInfo),
|
|
4238
4935
|
expression,
|
|
4239
|
-
|
|
4936
|
+
this._members
|
|
4240
4937
|
)
|
|
4241
4938
|
) {
|
|
4242
4939
|
return;
|
|
@@ -4261,15 +4958,24 @@ class JavascriptParser extends Parser {
|
|
|
4261
4958
|
if (result === undefined) {
|
|
4262
4959
|
const guard = this.hooks.collectGuards.call(expression.test);
|
|
4263
4960
|
this.walkExpression(expression.test);
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4961
|
+
// allocate the branch closure only when a guard frame needs pushing
|
|
4962
|
+
if (guard && guard.consequent) {
|
|
4963
|
+
this.walkGuardedBranch(guard.consequent, () =>
|
|
4964
|
+
this.walkExpression(expression.consequent)
|
|
4965
|
+
);
|
|
4966
|
+
} else {
|
|
4967
|
+
this.walkExpression(expression.consequent);
|
|
4968
|
+
}
|
|
4267
4969
|
|
|
4268
4970
|
if (expression.alternate) {
|
|
4269
4971
|
const alternate = expression.alternate;
|
|
4270
|
-
|
|
4271
|
-
this.
|
|
4272
|
-
|
|
4972
|
+
if (guard && guard.alternate) {
|
|
4973
|
+
this.walkGuardedBranch(guard.alternate, () =>
|
|
4974
|
+
this.walkExpression(alternate)
|
|
4975
|
+
);
|
|
4976
|
+
} else {
|
|
4977
|
+
this.walkExpression(alternate);
|
|
4978
|
+
}
|
|
4273
4979
|
}
|
|
4274
4980
|
} else if (result) {
|
|
4275
4981
|
this.walkExpression(expression.consequent);
|
|
@@ -4375,13 +5081,13 @@ class JavascriptParser extends Parser {
|
|
|
4375
5081
|
const renameIdentifier = this.getRenameIdentifier(argOrThis);
|
|
4376
5082
|
if (
|
|
4377
5083
|
renameIdentifier &&
|
|
4378
|
-
this.
|
|
5084
|
+
this._callHooksForInfo1(
|
|
4379
5085
|
this.hooks.canRename,
|
|
4380
5086
|
renameIdentifier,
|
|
4381
5087
|
/** @type {Expression} */
|
|
4382
5088
|
(argOrThis)
|
|
4383
5089
|
) &&
|
|
4384
|
-
!this.
|
|
5090
|
+
!this._callHooksForInfo1(
|
|
4385
5091
|
this.hooks.rename,
|
|
4386
5092
|
renameIdentifier,
|
|
4387
5093
|
/** @type {Expression} */
|
|
@@ -4422,26 +5128,27 @@ class JavascriptParser extends Parser {
|
|
|
4422
5128
|
scopeParams.push(functionExpression.id.name);
|
|
4423
5129
|
}
|
|
4424
5130
|
|
|
4425
|
-
this.
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
5131
|
+
const oldScope = this._enterFunctionScope(true, scopeParams);
|
|
5132
|
+
if (renameThis && !arrow) {
|
|
5133
|
+
this.setVariable("this", renameThis);
|
|
5134
|
+
}
|
|
5135
|
+
for (let i = 0; i < varInfoForArgs.length; i++) {
|
|
5136
|
+
const varInfo = varInfoForArgs[i];
|
|
5137
|
+
if (!varInfo) continue;
|
|
5138
|
+
if (!params[i] || params[i].type !== "Identifier") continue;
|
|
5139
|
+
this.setVariable(/** @type {Identifier} */ (params[i]).name, varInfo);
|
|
5140
|
+
}
|
|
5141
|
+
if (functionExpression.body.type === "BlockStatement") {
|
|
5142
|
+
this.detectMode(functionExpression.body.body);
|
|
5143
|
+
const prev = this.prevStatement;
|
|
5144
|
+
this._preWalkScope(functionExpression.body);
|
|
5145
|
+
this.prevStatement = prev;
|
|
5146
|
+
this.walkStatement(functionExpression.body);
|
|
5147
|
+
} else {
|
|
5148
|
+
this.walkExpression(functionExpression.body);
|
|
5149
|
+
}
|
|
5150
|
+
|
|
5151
|
+
this.scope = oldScope;
|
|
4445
5152
|
this.scope.topLevelScope = wasTopLevel;
|
|
4446
5153
|
}
|
|
4447
5154
|
|
|
@@ -4553,22 +5260,26 @@ class JavascriptParser extends Parser {
|
|
|
4553
5260
|
}
|
|
4554
5261
|
const callee = this.evaluateExpression(expression.callee);
|
|
4555
5262
|
if (callee.isIdentifier()) {
|
|
4556
|
-
const
|
|
4557
|
-
/** @type {NonNullable<BasicEvaluatedExpression["getMembers"]>} */
|
|
4558
|
-
(callee.getMembers)();
|
|
4559
|
-
const result1 = this.callHooksForInfo(
|
|
4560
|
-
this.hooks.callMemberChain,
|
|
5263
|
+
const rootInfo =
|
|
4561
5264
|
/** @type {NonNullable<BasicEvaluatedExpression["rootInfo"]>} */
|
|
4562
|
-
(callee.rootInfo)
|
|
4563
|
-
|
|
4564
|
-
members
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
5265
|
+
(callee.rootInfo);
|
|
5266
|
+
if (this._hasHooksForInfo(this.hooks.callMemberChain, rootInfo)) {
|
|
5267
|
+
const members =
|
|
5268
|
+
/** @type {NonNullable<BasicEvaluatedExpression["getMembers"]>} */
|
|
5269
|
+
(callee.getMembers)();
|
|
5270
|
+
const result1 = this.callHooksForInfo(
|
|
5271
|
+
this.hooks.callMemberChain,
|
|
5272
|
+
rootInfo,
|
|
5273
|
+
expression,
|
|
5274
|
+
members,
|
|
5275
|
+
callee.getMembersOptionals
|
|
5276
|
+
? callee.getMembersOptionals()
|
|
5277
|
+
: members.map(RETURN_FALSE),
|
|
5278
|
+
callee.getMemberRanges ? callee.getMemberRanges() : []
|
|
5279
|
+
);
|
|
5280
|
+
if (result1 === true) return;
|
|
5281
|
+
}
|
|
5282
|
+
const result2 = this._callHooksForInfo1(
|
|
4572
5283
|
this.hooks.call,
|
|
4573
5284
|
/** @type {NonNullable<BasicEvaluatedExpression["identifier"]>} */
|
|
4574
5285
|
(callee.identifier),
|
|
@@ -4593,69 +5304,113 @@ class JavascriptParser extends Parser {
|
|
|
4593
5304
|
}
|
|
4594
5305
|
|
|
4595
5306
|
/**
|
|
4596
|
-
* Walk member expression.
|
|
4597
|
-
* @param {MemberExpression} expression member expression
|
|
5307
|
+
* Walk member expression.
|
|
5308
|
+
* @param {MemberExpression} expression member expression
|
|
5309
|
+
*/
|
|
5310
|
+
walkMemberExpression(expression) {
|
|
5311
|
+
const type = this._resolveMemberExpression(
|
|
5312
|
+
expression,
|
|
5313
|
+
ALLOWED_MEMBER_TYPES_ALL
|
|
5314
|
+
);
|
|
5315
|
+
if (type === 1) {
|
|
5316
|
+
// copied out first: a hook may resolve another chain and reuse the slots
|
|
5317
|
+
const name = this._memberName;
|
|
5318
|
+
const rootInfo = /** @type {string | VariableInfo} */ (
|
|
5319
|
+
this._memberRootInfo
|
|
5320
|
+
);
|
|
5321
|
+
const members = this._members;
|
|
5322
|
+
const membersOptionals = this._membersOptionals;
|
|
5323
|
+
const result1 = this._callHooksForInfo1(
|
|
5324
|
+
this.hooks.expression,
|
|
5325
|
+
name,
|
|
5326
|
+
expression
|
|
5327
|
+
);
|
|
5328
|
+
if (result1 === true) return;
|
|
5329
|
+
if (this._hasHooksForInfo(this.hooks.expressionMemberChain, rootInfo)) {
|
|
5330
|
+
const result2 = this.callHooksForInfo(
|
|
5331
|
+
this.hooks.expressionMemberChain,
|
|
5332
|
+
rootInfo,
|
|
5333
|
+
expression,
|
|
5334
|
+
members,
|
|
5335
|
+
membersOptionals,
|
|
5336
|
+
memberRangesOf(expression, members.length)
|
|
5337
|
+
);
|
|
5338
|
+
if (result2 === true) return;
|
|
5339
|
+
}
|
|
5340
|
+
this._walkMemberChain(
|
|
5341
|
+
expression,
|
|
5342
|
+
expression,
|
|
5343
|
+
name,
|
|
5344
|
+
rootInfo,
|
|
5345
|
+
members,
|
|
5346
|
+
members.length
|
|
5347
|
+
);
|
|
5348
|
+
return;
|
|
5349
|
+
}
|
|
5350
|
+
if (type === 2) {
|
|
5351
|
+
const call = /** @type {CallExpression} */ (this._memberCall);
|
|
5352
|
+
const result = this.callHooksForInfo(
|
|
5353
|
+
this.hooks.memberChainOfCallMemberChain,
|
|
5354
|
+
/** @type {string | VariableInfo} */ (this._memberRootInfo),
|
|
5355
|
+
expression,
|
|
5356
|
+
this._memberCalleeMembers,
|
|
5357
|
+
call,
|
|
5358
|
+
this._members,
|
|
5359
|
+
memberRangesOf(expression, this._members.length)
|
|
5360
|
+
);
|
|
5361
|
+
if (result === true) return;
|
|
5362
|
+
// Fast skip over the member chain as we already called memberChainOfCallMemberChain
|
|
5363
|
+
// and call computed property are literals anyway
|
|
5364
|
+
this.walkExpression(call);
|
|
5365
|
+
return;
|
|
5366
|
+
}
|
|
5367
|
+
this.walkExpression(expression.object);
|
|
5368
|
+
if (expression.computed === true) this.walkExpression(expression.property);
|
|
5369
|
+
}
|
|
5370
|
+
|
|
5371
|
+
/**
|
|
5372
|
+
* The walk `walkMemberExpressionWithExpressionName` does over a resolved
|
|
5373
|
+
* chain, reading `members` up to `end` instead of popping a copy of it.
|
|
5374
|
+
* @param {MemberExpression} outer the whole chain, for the unhandled hook
|
|
5375
|
+
* @param {MemberExpression} expression the chain from here inwards
|
|
5376
|
+
* @param {string} name name of `expression`
|
|
5377
|
+
* @param {string | VariableInfo} rootInfo root info
|
|
5378
|
+
* @param {Members} members members of the whole chain, in source order
|
|
5379
|
+
* @param {number} end how many of `members` are inside `expression`
|
|
5380
|
+
* @returns {void}
|
|
4598
5381
|
*/
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
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
|
-
}
|
|
4656
|
-
}
|
|
5382
|
+
_walkMemberChain(outer, expression, name, rootInfo, members, end) {
|
|
5383
|
+
if (expression.object.type === "MemberExpression") {
|
|
5384
|
+
const property = members[end - 1];
|
|
5385
|
+
name = name.slice(0, -property.length - 1);
|
|
5386
|
+
const result = this._callHooksForInfo1(
|
|
5387
|
+
this.hooks.expression,
|
|
5388
|
+
name,
|
|
5389
|
+
expression.object
|
|
5390
|
+
);
|
|
5391
|
+
if (result === true) return;
|
|
5392
|
+
this._walkMemberChain(
|
|
5393
|
+
outer,
|
|
5394
|
+
expression.object,
|
|
5395
|
+
name,
|
|
5396
|
+
rootInfo,
|
|
5397
|
+
members,
|
|
5398
|
+
end - 1
|
|
5399
|
+
);
|
|
5400
|
+
} else if (
|
|
5401
|
+
!this._hasHooksForInfo(
|
|
5402
|
+
this.hooks.unhandledExpressionMemberChain,
|
|
5403
|
+
rootInfo
|
|
5404
|
+
) ||
|
|
5405
|
+
!this.callHooksForInfo(
|
|
5406
|
+
this.hooks.unhandledExpressionMemberChain,
|
|
5407
|
+
rootInfo,
|
|
5408
|
+
outer,
|
|
5409
|
+
members
|
|
5410
|
+
)
|
|
5411
|
+
) {
|
|
5412
|
+
this.walkExpression(expression.object);
|
|
4657
5413
|
}
|
|
4658
|
-
this.walkExpression(expression.object);
|
|
4659
5414
|
if (expression.computed === true) this.walkExpression(expression.property);
|
|
4660
5415
|
}
|
|
4661
5416
|
|
|
@@ -4676,15 +5431,13 @@ class JavascriptParser extends Parser {
|
|
|
4676
5431
|
onUnhandled
|
|
4677
5432
|
) {
|
|
4678
5433
|
if (expression.object.type === "MemberExpression") {
|
|
4679
|
-
//
|
|
4680
|
-
//
|
|
4681
|
-
//
|
|
4682
|
-
// extractMemberExpressionChain) since the AST node may be a
|
|
4683
|
-
// TemplateLiteral, which has neither .name nor .value.
|
|
5434
|
+
// A nested MemberExpression keeps its info by calling walkMemberExpression
|
|
5435
|
+
// directly. The property comes from `members` rather than the node, which
|
|
5436
|
+
// may be a TemplateLiteral and carry neither `.name` nor `.value`.
|
|
4684
5437
|
const property = members[members.length - 1];
|
|
4685
5438
|
name = name.slice(0, -property.length - 1);
|
|
4686
5439
|
members.pop();
|
|
4687
|
-
const result = this.
|
|
5440
|
+
const result = this._callHooksForInfo1(
|
|
4688
5441
|
this.hooks.expression,
|
|
4689
5442
|
name,
|
|
4690
5443
|
expression.object
|
|
@@ -4708,7 +5461,7 @@ class JavascriptParser extends Parser {
|
|
|
4708
5461
|
* @param {ThisExpression} expression this expression
|
|
4709
5462
|
*/
|
|
4710
5463
|
walkThisExpression(expression) {
|
|
4711
|
-
this.
|
|
5464
|
+
this._callHooksForName1(this.hooks.expression, "this", expression);
|
|
4712
5465
|
}
|
|
4713
5466
|
|
|
4714
5467
|
/**
|
|
@@ -4716,7 +5469,7 @@ class JavascriptParser extends Parser {
|
|
|
4716
5469
|
* @param {Identifier} expression identifier
|
|
4717
5470
|
*/
|
|
4718
5471
|
walkIdentifier(expression) {
|
|
4719
|
-
this.
|
|
5472
|
+
this._callHooksForName1(this.hooks.expression, expression.name, expression);
|
|
4720
5473
|
}
|
|
4721
5474
|
|
|
4722
5475
|
/**
|
|
@@ -4882,6 +5635,27 @@ class JavascriptParser extends Parser {
|
|
|
4882
5635
|
}
|
|
4883
5636
|
}
|
|
4884
5637
|
|
|
5638
|
+
/**
|
|
5639
|
+
* Whether `_callHooksForInfo` would call any hook for this info, so a
|
|
5640
|
+
* caller can skip building the arguments for a name nothing taps.
|
|
5641
|
+
* @template T
|
|
5642
|
+
* @template R
|
|
5643
|
+
* @param {HookMap<SyncBailHook<T, R>>} hookMap hooks that would be called
|
|
5644
|
+
* @param {ExportedVariableInfo} info variable info
|
|
5645
|
+
* @returns {boolean} true when a hook is registered for the info
|
|
5646
|
+
*/
|
|
5647
|
+
_hasHooksForInfo(hookMap, info) {
|
|
5648
|
+
if (typeof info === "string") return hookMap.get(info) !== undefined;
|
|
5649
|
+
if (!(info instanceof VariableInfo)) return false;
|
|
5650
|
+
let tagInfo = info.tagInfo;
|
|
5651
|
+
while (tagInfo !== undefined) {
|
|
5652
|
+
if (hookMap.get(tagInfo.tag) !== undefined) return true;
|
|
5653
|
+
tagInfo = tagInfo.next;
|
|
5654
|
+
}
|
|
5655
|
+
if (!info.isFree() && !info.isTagged()) return false;
|
|
5656
|
+
return hookMap.get(/** @type {string} */ (info.name)) !== undefined;
|
|
5657
|
+
}
|
|
5658
|
+
|
|
4885
5659
|
/**
|
|
4886
5660
|
* Call hooks for name with fallback.
|
|
4887
5661
|
* @template T
|
|
@@ -4903,6 +5677,69 @@ class JavascriptParser extends Parser {
|
|
|
4903
5677
|
);
|
|
4904
5678
|
}
|
|
4905
5679
|
|
|
5680
|
+
/**
|
|
5681
|
+
* Single-argument twin of `callHooksForName` (must stay in sync with
|
|
5682
|
+
* `_callHooksForInfo`): every internal dispatch passes exactly one hook
|
|
5683
|
+
* argument, so this skips the rest-array collection and spread call the
|
|
5684
|
+
* generic path pays per identifier.
|
|
5685
|
+
* @template T
|
|
5686
|
+
* @template R
|
|
5687
|
+
* @param {HookMap<SyncBailHook<T, R>>} hookMap hooks that should be called
|
|
5688
|
+
* @param {string} name key in map
|
|
5689
|
+
* @param {AsArray<T>[0]} arg the single hook argument
|
|
5690
|
+
* @returns {R | undefined} result of hook
|
|
5691
|
+
*/
|
|
5692
|
+
_callHooksForName1(hookMap, name, arg) {
|
|
5693
|
+
return this._callHooksForInfo1(hookMap, this.getVariableInfo(name), arg);
|
|
5694
|
+
}
|
|
5695
|
+
|
|
5696
|
+
/**
|
|
5697
|
+
* Single-argument twin of `callHooksForInfo` (must stay in sync with
|
|
5698
|
+
* `_callHooksForInfo`), for the hot dispatch sites that pass one argument
|
|
5699
|
+
* and no fallback/defined callbacks.
|
|
5700
|
+
* @template T
|
|
5701
|
+
* @template R
|
|
5702
|
+
* @param {HookMap<SyncBailHook<T, R>>} hookMap hooks that should be called
|
|
5703
|
+
* @param {ExportedVariableInfo} info variable info
|
|
5704
|
+
* @param {AsArray<T>[0]} arg the single hook argument
|
|
5705
|
+
* @returns {R | undefined} result of hook
|
|
5706
|
+
*/
|
|
5707
|
+
_callHooksForInfo1(hookMap, info, arg) {
|
|
5708
|
+
/** @type {string} */
|
|
5709
|
+
let name;
|
|
5710
|
+
if (typeof info === "string") {
|
|
5711
|
+
name = info;
|
|
5712
|
+
} else {
|
|
5713
|
+
if (!(info instanceof VariableInfo)) {
|
|
5714
|
+
return;
|
|
5715
|
+
}
|
|
5716
|
+
let tagInfo = info.tagInfo;
|
|
5717
|
+
while (tagInfo !== undefined) {
|
|
5718
|
+
const hook =
|
|
5719
|
+
/** @type {SyncBailHook<[AsArray<T>[0]], R> | undefined} */
|
|
5720
|
+
(hookMap.get(tagInfo.tag));
|
|
5721
|
+
if (hook !== undefined) {
|
|
5722
|
+
this.currentTagData = tagInfo.data;
|
|
5723
|
+
const result = hook.call(arg);
|
|
5724
|
+
this.currentTagData = undefined;
|
|
5725
|
+
if (result !== undefined) return result;
|
|
5726
|
+
}
|
|
5727
|
+
tagInfo = tagInfo.next;
|
|
5728
|
+
}
|
|
5729
|
+
if (!info.isFree() && !info.isTagged()) {
|
|
5730
|
+
return;
|
|
5731
|
+
}
|
|
5732
|
+
name = /** @type {string} */ (info.name);
|
|
5733
|
+
}
|
|
5734
|
+
const hook =
|
|
5735
|
+
/** @type {SyncBailHook<[AsArray<T>[0]], R> | undefined} */
|
|
5736
|
+
(hookMap.get(name));
|
|
5737
|
+
if (hook !== undefined) {
|
|
5738
|
+
const result = hook.call(arg);
|
|
5739
|
+
if (result !== undefined) return result;
|
|
5740
|
+
}
|
|
5741
|
+
}
|
|
5742
|
+
|
|
4906
5743
|
/**
|
|
4907
5744
|
* Processes the provided param.
|
|
4908
5745
|
* @deprecated
|
|
@@ -4971,26 +5808,8 @@ class JavascriptParser extends Parser {
|
|
|
4971
5808
|
* @returns {void}
|
|
4972
5809
|
*/
|
|
4973
5810
|
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
|
-
|
|
5811
|
+
const oldScope = this._enterFunctionScope(hasThis, params);
|
|
4992
5812
|
fn();
|
|
4993
|
-
|
|
4994
5813
|
this.scope = oldScope;
|
|
4995
5814
|
}
|
|
4996
5815
|
|
|
@@ -5001,6 +5820,18 @@ class JavascriptParser extends Parser {
|
|
|
5001
5820
|
* @returns {void}
|
|
5002
5821
|
*/
|
|
5003
5822
|
inBlockScope(fn, inExecutedPath = false) {
|
|
5823
|
+
const oldScope = this._enterBlockScope();
|
|
5824
|
+
fn();
|
|
5825
|
+
this._exitBlockScope(oldScope, inExecutedPath);
|
|
5826
|
+
}
|
|
5827
|
+
|
|
5828
|
+
/**
|
|
5829
|
+
* Enters a fresh block scope: the closure-free core of `inBlockScope`, used
|
|
5830
|
+
* directly by the internal walkers so each block does not allocate a
|
|
5831
|
+
* closure and context. Pass the returned scope to `_exitBlockScope`.
|
|
5832
|
+
* @returns {ScopeInfo} the previous scope
|
|
5833
|
+
*/
|
|
5834
|
+
_enterBlockScope() {
|
|
5004
5835
|
const oldScope = this.scope;
|
|
5005
5836
|
this.scope = {
|
|
5006
5837
|
topLevelScope: oldScope.topLevelScope,
|
|
@@ -5012,18 +5843,50 @@ class JavascriptParser extends Parser {
|
|
|
5012
5843
|
terminated: oldScope.terminated,
|
|
5013
5844
|
definitions: oldScope.definitions.createChild()
|
|
5014
5845
|
};
|
|
5846
|
+
return oldScope;
|
|
5847
|
+
}
|
|
5015
5848
|
|
|
5016
|
-
|
|
5017
|
-
|
|
5849
|
+
/**
|
|
5850
|
+
* Leaves a block scope entered with `_enterBlockScope`.
|
|
5851
|
+
* @param {ScopeInfo} oldScope scope returned by `_enterBlockScope`
|
|
5852
|
+
* @param {boolean} inExecutedPath whether termination propagates to the outer scope
|
|
5853
|
+
* @returns {void}
|
|
5854
|
+
*/
|
|
5855
|
+
_exitBlockScope(oldScope, inExecutedPath) {
|
|
5018
5856
|
const terminated = this.scope.terminated;
|
|
5019
|
-
|
|
5020
5857
|
if (inExecutedPath && terminated) {
|
|
5021
5858
|
oldScope.terminated = terminated;
|
|
5022
5859
|
}
|
|
5023
|
-
|
|
5024
5860
|
this.scope = oldScope;
|
|
5025
5861
|
}
|
|
5026
5862
|
|
|
5863
|
+
/**
|
|
5864
|
+
* Enters a fresh function scope: the closure-free core of `inFunctionScope`,
|
|
5865
|
+
* used directly by the internal walkers. Restore `this.scope` to the
|
|
5866
|
+
* returned scope when leaving.
|
|
5867
|
+
* @param {boolean} hasThis true, when this is defined
|
|
5868
|
+
* @param {(Pattern | string)[]} params scope params
|
|
5869
|
+
* @returns {ScopeInfo} the previous scope
|
|
5870
|
+
*/
|
|
5871
|
+
_enterFunctionScope(hasThis, params) {
|
|
5872
|
+
const oldScope = this.scope;
|
|
5873
|
+
this.scope = {
|
|
5874
|
+
topLevelScope: oldScope.topLevelScope,
|
|
5875
|
+
inTry: false,
|
|
5876
|
+
inShorthand: false,
|
|
5877
|
+
inTaggedTemplateTag: false,
|
|
5878
|
+
isStrict: oldScope.isStrict,
|
|
5879
|
+
isAsmJs: oldScope.isAsmJs,
|
|
5880
|
+
terminated: undefined,
|
|
5881
|
+
definitions: oldScope.definitions.createChild()
|
|
5882
|
+
};
|
|
5883
|
+
if (hasThis) {
|
|
5884
|
+
this.undefineVariable("this");
|
|
5885
|
+
}
|
|
5886
|
+
this.enterPatterns(params, this._defineVariable);
|
|
5887
|
+
return oldScope;
|
|
5888
|
+
}
|
|
5889
|
+
|
|
5027
5890
|
/**
|
|
5028
5891
|
* Processes the provided statement.
|
|
5029
5892
|
* @param {(Directive | Statement | ModuleDeclaration)[]} statements statements
|
|
@@ -5103,7 +5966,7 @@ class JavascriptParser extends Parser {
|
|
|
5103
5966
|
* @param {OnIdent} onIdent callback
|
|
5104
5967
|
*/
|
|
5105
5968
|
enterIdentifier(pattern, onIdent) {
|
|
5106
|
-
if (!this.
|
|
5969
|
+
if (!this._callHooksForName1(this.hooks.pattern, pattern.name, pattern)) {
|
|
5107
5970
|
onIdent(pattern.name, pattern);
|
|
5108
5971
|
}
|
|
5109
5972
|
}
|
|
@@ -5351,6 +6214,13 @@ class JavascriptParser extends Parser {
|
|
|
5351
6214
|
const oldStrictInModuleOutput = this._strictInModuleOutput;
|
|
5352
6215
|
const oldSource = this._source;
|
|
5353
6216
|
const oldLineStarts = this._lineStarts;
|
|
6217
|
+
const oldHasParserRecord = this._hasParserRecord;
|
|
6218
|
+
// WHY: the parser's record of each scope is only the truth for a tree it
|
|
6219
|
+
// just built. A loader's AST, and whatever `module.parser.javascript.parse`
|
|
6220
|
+
// returns, may have been edited after it was read — or built by something
|
|
6221
|
+
// else entirely — so both are collected from instead of trusted.
|
|
6222
|
+
this._hasParserRecord =
|
|
6223
|
+
typeof source !== "object" && typeof this.options.parse !== "function";
|
|
5354
6224
|
// a preparsed AST carries no text, but the build passes the module
|
|
5355
6225
|
// source in the state — offsets still map for it
|
|
5356
6226
|
this._source =
|
|
@@ -5398,16 +6268,19 @@ class JavascriptParser extends Parser {
|
|
|
5398
6268
|
if (this._strictInModuleOutput && this.scope.isStrict) {
|
|
5399
6269
|
this._strictInModuleOutput = false;
|
|
5400
6270
|
}
|
|
5401
|
-
this.
|
|
6271
|
+
this._modulePreWalkDeclarations(
|
|
6272
|
+
moduleDeclarationsOf(ast, this._hasParserRecord)
|
|
6273
|
+
);
|
|
5402
6274
|
this.prevStatement = undefined;
|
|
5403
|
-
this.
|
|
6275
|
+
this._preWalkScope(ast);
|
|
5404
6276
|
this.prevStatement = undefined;
|
|
5405
|
-
this.
|
|
6277
|
+
this._blockPreWalkScope(ast, ast.body);
|
|
5406
6278
|
this.prevStatement = undefined;
|
|
5407
6279
|
this.walkStatements(ast.body);
|
|
5408
6280
|
this.destructuringAssignmentProperties = undefined;
|
|
5409
6281
|
}
|
|
5410
6282
|
this.hooks.finish.call(ast, comments);
|
|
6283
|
+
this._releaseMemberExpression();
|
|
5411
6284
|
this.scope = oldScope;
|
|
5412
6285
|
this.state = oldState;
|
|
5413
6286
|
this.comments = oldComments;
|
|
@@ -5418,6 +6291,7 @@ class JavascriptParser extends Parser {
|
|
|
5418
6291
|
// release — these retain the whole source string and its line table
|
|
5419
6292
|
this._source = oldSource;
|
|
5420
6293
|
this._lineStarts = oldLineStarts;
|
|
6294
|
+
this._hasParserRecord = oldHasParserRecord;
|
|
5421
6295
|
return state;
|
|
5422
6296
|
}
|
|
5423
6297
|
|
|
@@ -5452,6 +6326,9 @@ class JavascriptParser extends Parser {
|
|
|
5452
6326
|
`(${source})`,
|
|
5453
6327
|
{
|
|
5454
6328
|
sourceType: this.sourceType,
|
|
6329
|
+
// ranges alone take the lazy path, which serves `range` from a
|
|
6330
|
+
// getter and tracks no locations — as the module parse does
|
|
6331
|
+
ranges: true,
|
|
5455
6332
|
importPhases
|
|
5456
6333
|
},
|
|
5457
6334
|
this.options.parse
|
|
@@ -5533,10 +6410,9 @@ class JavascriptParser extends Parser {
|
|
|
5533
6410
|
});
|
|
5534
6411
|
}
|
|
5535
6412
|
case "TemplateLiteral":
|
|
5536
|
-
// Thread `commentsStartPos` through the interpolations so a
|
|
5537
|
-
//
|
|
5538
|
-
// the
|
|
5539
|
-
// the inner expression's purity is evaluated.
|
|
6413
|
+
// Thread `commentsStartPos` through the interpolations, so a
|
|
6414
|
+
// `/*#__PURE__*/` inside `${ … }`, or before the first one, is within
|
|
6415
|
+
// the range scanned when the inner expression's purity is judged.
|
|
5540
6416
|
return expr.expressions.every((e) => {
|
|
5541
6417
|
const pureFlag = this.isPure(e, commentsStartPos);
|
|
5542
6418
|
commentsStartPos = /** @type {Range} */ (e.range)[1];
|
|
@@ -5590,17 +6466,13 @@ class JavascriptParser extends Parser {
|
|
|
5590
6466
|
return this.isPure(expr.expression, commentsStartPos);
|
|
5591
6467
|
|
|
5592
6468
|
case "UnaryExpression":
|
|
5593
|
-
//
|
|
5594
|
-
//
|
|
5595
|
-
//
|
|
5596
|
-
//
|
|
5597
|
-
//
|
|
5598
|
-
//
|
|
5599
|
-
//
|
|
5600
|
-
// any user code (objects → true, etc.).
|
|
5601
|
-
// Other operators (`+`, `-`, `~`, `delete`) fall through to
|
|
5602
|
-
// the generic evaluator which can still recognize literal
|
|
5603
|
-
// cases (e.g. `-1`, `+5`).
|
|
6469
|
+
// WHY: these three produce their result without invoking user code on
|
|
6470
|
+
// the operand. `typeof` returns a type tag and never throws, even for an
|
|
6471
|
+
// undeclared identifier, and coerces nothing; `void` evaluates the
|
|
6472
|
+
// operand and discards it, so it is pure exactly when the operand is; and
|
|
6473
|
+
// `!` coerces through ToBoolean, which is defined to call no user code.
|
|
6474
|
+
// `+`, `-`, `~` and `delete` fall through to the generic evaluator, which
|
|
6475
|
+
// still recognizes literal cases such as `-1` and `+5`.
|
|
5604
6476
|
if (
|
|
5605
6477
|
expr.operator === "typeof" ||
|
|
5606
6478
|
expr.operator === "void" ||
|
|
@@ -5614,12 +6486,12 @@ class JavascriptParser extends Parser {
|
|
|
5614
6486
|
return true;
|
|
5615
6487
|
|
|
5616
6488
|
case "BinaryExpression":
|
|
5617
|
-
//
|
|
5618
|
-
//
|
|
5619
|
-
//
|
|
5620
|
-
// `
|
|
5621
|
-
//
|
|
5622
|
-
//
|
|
6489
|
+
// WHY: strict (in)equality compares without coercion and never invokes user
|
|
6490
|
+
// code on its operands, so the result is pure where both sides are. Every
|
|
6491
|
+
// other binary operator may invoke `valueOf`, `toString`,
|
|
6492
|
+
// `[Symbol.hasInstance]` or a Proxy trap, and falls through to the generic
|
|
6493
|
+
// evaluator, which still recognizes the cases where both sides evaluate
|
|
6494
|
+
// to known primitive literals.
|
|
5623
6495
|
if (expr.operator === "===" || expr.operator === "!==") {
|
|
5624
6496
|
return (
|
|
5625
6497
|
this.isPure(expr.left, commentsStartPos) &&
|
|
@@ -5753,7 +6625,15 @@ class JavascriptParser extends Parser {
|
|
|
5753
6625
|
};
|
|
5754
6626
|
}
|
|
5755
6627
|
}
|
|
5756
|
-
|
|
6628
|
+
const loc = node.loc;
|
|
6629
|
+
if (!loc) {
|
|
6630
|
+
return /** @type {DependencyLocation} */ (/** @type {unknown} */ (loc));
|
|
6631
|
+
}
|
|
6632
|
+
// a plain copy: a foreign parser's location class must not reach the cache
|
|
6633
|
+
return {
|
|
6634
|
+
start: { line: loc.start.line, column: loc.start.column },
|
|
6635
|
+
end: { line: loc.end.line, column: loc.end.column }
|
|
6636
|
+
};
|
|
5757
6637
|
}
|
|
5758
6638
|
|
|
5759
6639
|
/**
|
|
@@ -5768,6 +6648,46 @@ class JavascriptParser extends Parser {
|
|
|
5768
6648
|
);
|
|
5769
6649
|
}
|
|
5770
6650
|
|
|
6651
|
+
/**
|
|
6652
|
+
* Where the comments written for `statement` begin: the run of comments
|
|
6653
|
+
* before it that whitespace alone separates from it and from each other.
|
|
6654
|
+
* @param {StatementPathItem} statement the statement they belong to
|
|
6655
|
+
* @returns {number} the offset the run starts at, or the statement's own
|
|
6656
|
+
*/
|
|
6657
|
+
getAttachedCommentsStart(statement) {
|
|
6658
|
+
let position = /** @type {Range} */ (statement.range)[0];
|
|
6659
|
+
// what precedes `export function f() {}` is written for the export, and
|
|
6660
|
+
// the export keyword is the token the run would otherwise stop at
|
|
6661
|
+
const path = this.statementPath;
|
|
6662
|
+
if (path !== undefined && path.length > 1) {
|
|
6663
|
+
const outer = path[path.length - 2];
|
|
6664
|
+
if (
|
|
6665
|
+
(outer.type === "ExportNamedDeclaration" ||
|
|
6666
|
+
outer.type === "ExportDefaultDeclaration") &&
|
|
6667
|
+
outer.declaration === statement
|
|
6668
|
+
) {
|
|
6669
|
+
position = /** @type {Range} */ (outer.range)[0];
|
|
6670
|
+
}
|
|
6671
|
+
}
|
|
6672
|
+
const comments = this.comments;
|
|
6673
|
+
if (comments === undefined) return position;
|
|
6674
|
+
const source = this._source;
|
|
6675
|
+
for (let index = comments.length - 1; index >= 0; index--) {
|
|
6676
|
+
const range = /** @type {Range} */ (comments[index].range);
|
|
6677
|
+
if (range[1] > position) continue;
|
|
6678
|
+
// with no source to read, nothing can be ruled out, so the run is
|
|
6679
|
+
// taken to reach as far as the comments themselves do
|
|
6680
|
+
if (
|
|
6681
|
+
source !== undefined &&
|
|
6682
|
+
!onlyWhitespaceBetween(source, range[1], position)
|
|
6683
|
+
) {
|
|
6684
|
+
break;
|
|
6685
|
+
}
|
|
6686
|
+
position = range[0];
|
|
6687
|
+
}
|
|
6688
|
+
return position;
|
|
6689
|
+
}
|
|
6690
|
+
|
|
5771
6691
|
/**
|
|
5772
6692
|
* Reports whether `identifier` may occur as a word in the source text of
|
|
5773
6693
|
* `range`. A conservative pre-filter for expensive AST scans: `false` means
|
|
@@ -5995,6 +6915,7 @@ class JavascriptParser extends Parser {
|
|
|
5995
6915
|
});
|
|
5996
6916
|
}
|
|
5997
6917
|
this.scope.definitions.set(name, newInfo);
|
|
6918
|
+
this._memberExpression = undefined;
|
|
5998
6919
|
}
|
|
5999
6920
|
|
|
6000
6921
|
/**
|
|
@@ -6011,6 +6932,7 @@ class JavascriptParser extends Parser {
|
|
|
6011
6932
|
return;
|
|
6012
6933
|
}
|
|
6013
6934
|
this.scope.definitions.set(name, this.scope);
|
|
6935
|
+
this._memberExpression = undefined;
|
|
6014
6936
|
}
|
|
6015
6937
|
|
|
6016
6938
|
/**
|
|
@@ -6019,6 +6941,7 @@ class JavascriptParser extends Parser {
|
|
|
6019
6941
|
*/
|
|
6020
6942
|
undefineVariable(name) {
|
|
6021
6943
|
this.scope.definitions.delete(name);
|
|
6944
|
+
this._memberExpression = undefined;
|
|
6022
6945
|
}
|
|
6023
6946
|
|
|
6024
6947
|
/**
|
|
@@ -6071,6 +6994,7 @@ class JavascriptParser extends Parser {
|
|
|
6071
6994
|
* @returns {void}
|
|
6072
6995
|
*/
|
|
6073
6996
|
setVariable(name, variableInfo) {
|
|
6997
|
+
this._memberExpression = undefined;
|
|
6074
6998
|
if (typeof variableInfo === "string") {
|
|
6075
6999
|
if (variableInfo === name) {
|
|
6076
7000
|
this.scope.definitions.delete(name);
|
|
@@ -6242,69 +7166,219 @@ class JavascriptParser extends Parser {
|
|
|
6242
7166
|
/** @typedef {{ type: "expression", rootInfo: string | VariableInfo, name: string, getMembers: () => Members, getMembersOptionals: () => MembersOptionals, getMemberRanges: () => MemberRanges }} ExpressionExpressionInfo */
|
|
6243
7167
|
|
|
6244
7168
|
/**
|
|
6245
|
-
*
|
|
7169
|
+
* Resolves a member expression into the `_member*` slots, once per node and
|
|
7170
|
+
* scope. Returns 0 when rejected, 1 for an `expression`, 2 for a `call`.
|
|
6246
7171
|
* @param {Expression | Super} expression a member expression
|
|
6247
|
-
* @param {number} allowedTypes which types
|
|
6248
|
-
* @returns {
|
|
7172
|
+
* @param {number} allowedTypes which types may be returned, presented in bit mask
|
|
7173
|
+
* @returns {0 | 1 | 2} the kind resolved
|
|
6249
7174
|
*/
|
|
6250
|
-
|
|
7175
|
+
_resolveMemberExpression(expression, allowedTypes) {
|
|
7176
|
+
if (
|
|
7177
|
+
expression === this._memberExpression &&
|
|
7178
|
+
this._memberScope === this.scope
|
|
7179
|
+
) {
|
|
7180
|
+
const type = this._memberType;
|
|
7181
|
+
if (type !== 0) {
|
|
7182
|
+
// the root kind is a fact of the node; the mask only says whether to report it
|
|
7183
|
+
const bit =
|
|
7184
|
+
type === 2
|
|
7185
|
+
? ALLOWED_MEMBER_TYPES_CALL_EXPRESSION
|
|
7186
|
+
: ALLOWED_MEMBER_TYPES_EXPRESSION;
|
|
7187
|
+
return (allowedTypes & bit) === 0 ? 0 : type;
|
|
7188
|
+
}
|
|
7189
|
+
if ((allowedTypes & ~this._memberMask) === 0) return 0;
|
|
7190
|
+
}
|
|
7191
|
+
this._memberExpression = expression;
|
|
7192
|
+
this._memberScope = this.scope;
|
|
7193
|
+
this._memberMask = allowedTypes;
|
|
7194
|
+
this._memberType = 0;
|
|
7195
|
+
this._memberInfo = undefined;
|
|
6251
7196
|
// Resolve the root first (no allocation); most calls reject here and so
|
|
6252
|
-
// never build the member arrays
|
|
7197
|
+
// never build the member arrays
|
|
6253
7198
|
const object = this.getMemberExpressionRoot(expression);
|
|
6254
7199
|
switch (object.type) {
|
|
6255
7200
|
case "CallExpression": {
|
|
6256
|
-
if ((allowedTypes & ALLOWED_MEMBER_TYPES_CALL_EXPRESSION) === 0)
|
|
7201
|
+
if ((allowedTypes & ALLOWED_MEMBER_TYPES_CALL_EXPRESSION) === 0) {
|
|
7202
|
+
return 0;
|
|
7203
|
+
}
|
|
6257
7204
|
const calleeExpr = object.callee;
|
|
6258
7205
|
const callee =
|
|
6259
7206
|
calleeExpr.type === "MemberExpression"
|
|
6260
7207
|
? this.getMemberExpressionRoot(calleeExpr)
|
|
6261
7208
|
: calleeExpr;
|
|
6262
7209
|
const rootName = getRootName(callee);
|
|
6263
|
-
if (!rootName) return;
|
|
6264
|
-
const
|
|
6265
|
-
if (
|
|
6266
|
-
|
|
6267
|
-
|
|
6268
|
-
|
|
6269
|
-
|
|
6270
|
-
|
|
6271
|
-
|
|
6272
|
-
|
|
7210
|
+
if (!rootName) return this._rejectMemberExpression();
|
|
7211
|
+
const resolvedRoot = this._resolveMemberRoot(rootName);
|
|
7212
|
+
if (resolvedRoot === undefined) return this._rejectMemberExpression();
|
|
7213
|
+
/** @type {CalleeMembers} */
|
|
7214
|
+
let rootMembers = EMPTY_ARRAY;
|
|
7215
|
+
if (calleeExpr.type === "MemberExpression") {
|
|
7216
|
+
this._extractMembers(calleeExpr);
|
|
7217
|
+
rootMembers = this._members;
|
|
7218
|
+
}
|
|
7219
|
+
this._extractMembers(expression);
|
|
6273
7220
|
const calleeName = objectAndMembersToName(resolvedRoot, rootMembers);
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
|
|
6277
|
-
|
|
6278
|
-
|
|
6279
|
-
|
|
6280
|
-
|
|
6281
|
-
|
|
6282
|
-
|
|
6283
|
-
getMemberRanges: lazyReverse(memberRanges)
|
|
6284
|
-
};
|
|
7221
|
+
this._memberType = 2;
|
|
7222
|
+
this._memberCall = object;
|
|
7223
|
+
this._memberCalleeName = calleeName;
|
|
7224
|
+
this._memberCalleeMembers = rootMembers;
|
|
7225
|
+
this._memberName = objectAndMembersToName(
|
|
7226
|
+
`${calleeName}()`,
|
|
7227
|
+
this._members
|
|
7228
|
+
);
|
|
7229
|
+
return 2;
|
|
6285
7230
|
}
|
|
6286
7231
|
case "Identifier":
|
|
6287
7232
|
case "MetaProperty":
|
|
6288
7233
|
case "ThisExpression": {
|
|
6289
|
-
if ((allowedTypes & ALLOWED_MEMBER_TYPES_EXPRESSION) === 0) return;
|
|
7234
|
+
if ((allowedTypes & ALLOWED_MEMBER_TYPES_EXPRESSION) === 0) return 0;
|
|
6290
7235
|
const rootName = getRootName(object);
|
|
6291
|
-
if (!rootName) return;
|
|
7236
|
+
if (!rootName) return this._rejectMemberExpression();
|
|
7237
|
+
const resolvedRoot = this._resolveMemberRoot(rootName);
|
|
7238
|
+
if (resolvedRoot === undefined) return this._rejectMemberExpression();
|
|
7239
|
+
this._extractMembers(expression);
|
|
7240
|
+
this._memberType = 1;
|
|
7241
|
+
this._memberName = objectAndMembersToName(resolvedRoot, this._members);
|
|
7242
|
+
return 1;
|
|
7243
|
+
}
|
|
7244
|
+
}
|
|
7245
|
+
return this._rejectMemberExpression();
|
|
7246
|
+
}
|
|
6292
7247
|
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
7248
|
+
/**
|
|
7249
|
+
* Records that the node resolves to nothing under any mask.
|
|
7250
|
+
* @returns {0} rejected
|
|
7251
|
+
*/
|
|
7252
|
+
_rejectMemberExpression() {
|
|
7253
|
+
this._memberMask = ALLOWED_MEMBER_TYPES_ALL;
|
|
7254
|
+
return 0;
|
|
7255
|
+
}
|
|
7256
|
+
|
|
7257
|
+
/**
|
|
7258
|
+
* `getNameInfoFromVariable` for the resolver: stores the info in
|
|
7259
|
+
* `_memberRootInfo` and returns the name, or undefined when rejected.
|
|
7260
|
+
* @param {string} rootName name of the root variable
|
|
7261
|
+
* @returns {string | undefined} the resolved root name
|
|
7262
|
+
*/
|
|
7263
|
+
_resolveMemberRoot(rootName) {
|
|
7264
|
+
const info = this.getVariableInfo(rootName);
|
|
7265
|
+
if (info instanceof VariableInfo && info.name) {
|
|
7266
|
+
if (!info.isFree() && !info.isTagged()) return;
|
|
7267
|
+
this._memberRootInfo = info;
|
|
7268
|
+
return info.name;
|
|
7269
|
+
}
|
|
7270
|
+
if (typeof info !== "string") return;
|
|
7271
|
+
this._memberRootInfo = info;
|
|
7272
|
+
return info;
|
|
7273
|
+
}
|
|
7274
|
+
|
|
7275
|
+
/**
|
|
7276
|
+
* Fills `_members` and `_membersOptionals` for the chain, in source order.
|
|
7277
|
+
* @param {Expression | Super} expression a member expression
|
|
7278
|
+
* @returns {void}
|
|
7279
|
+
*/
|
|
7280
|
+
_extractMembers(expression) {
|
|
7281
|
+
/** @type {Node} */
|
|
7282
|
+
let expr = expression;
|
|
7283
|
+
/** @type {Members} */
|
|
7284
|
+
const members = [];
|
|
7285
|
+
/** @type {MembersOptionals} */
|
|
7286
|
+
const membersOptionals = [];
|
|
7287
|
+
while (expr.type === "MemberExpression") {
|
|
7288
|
+
if (expr.computed) {
|
|
7289
|
+
const prop = expr.property;
|
|
7290
|
+
if (prop.type === "Literal") {
|
|
7291
|
+
members.push(`${prop.value}`);
|
|
7292
|
+
} else if (
|
|
7293
|
+
prop.type === "TemplateLiteral" &&
|
|
7294
|
+
prop.expressions.length === 0 &&
|
|
7295
|
+
typeof prop.quasis[0].value.cooked === "string"
|
|
7296
|
+
) {
|
|
7297
|
+
members.push(prop.quasis[0].value.cooked);
|
|
7298
|
+
} else {
|
|
7299
|
+
break;
|
|
7300
|
+
}
|
|
7301
|
+
} else {
|
|
7302
|
+
if (expr.property.type !== "Identifier") break;
|
|
7303
|
+
members.push(expr.property.name);
|
|
6306
7304
|
}
|
|
7305
|
+
membersOptionals.push(expr.optional);
|
|
7306
|
+
expr = expr.object;
|
|
7307
|
+
}
|
|
7308
|
+
if (members.length > 1) {
|
|
7309
|
+
members.reverse();
|
|
7310
|
+
membersOptionals.reverse();
|
|
7311
|
+
}
|
|
7312
|
+
this._members = members;
|
|
7313
|
+
this._membersOptionals = membersOptionals;
|
|
7314
|
+
}
|
|
7315
|
+
|
|
7316
|
+
/**
|
|
7317
|
+
* Drops the resolved member expression, so no AST outlives its parse.
|
|
7318
|
+
* @returns {void}
|
|
7319
|
+
*/
|
|
7320
|
+
_releaseMemberExpression() {
|
|
7321
|
+
this._memberExpression = undefined;
|
|
7322
|
+
this._memberScope = undefined;
|
|
7323
|
+
this._memberType = 0;
|
|
7324
|
+
this._memberRootInfo = undefined;
|
|
7325
|
+
this._members = EMPTY_ARRAY;
|
|
7326
|
+
this._membersOptionals = EMPTY_MEMBERS_OPTIONALS;
|
|
7327
|
+
this._memberCall = undefined;
|
|
7328
|
+
this._memberCalleeMembers = EMPTY_ARRAY;
|
|
7329
|
+
this._memberInfo = undefined;
|
|
7330
|
+
}
|
|
7331
|
+
|
|
7332
|
+
/**
|
|
7333
|
+
* Gets member expression info.
|
|
7334
|
+
* @param {Expression | Super} expression a member expression
|
|
7335
|
+
* @param {number} allowedTypes which types should be returned, presented in bit mask
|
|
7336
|
+
* @returns {CallExpressionInfo | ExpressionExpressionInfo | undefined} expression info
|
|
7337
|
+
*/
|
|
7338
|
+
getMemberExpressionInfo(expression, allowedTypes) {
|
|
7339
|
+
const type = this._resolveMemberExpression(expression, allowedTypes);
|
|
7340
|
+
if (type === 0) return;
|
|
7341
|
+
const cached = this._memberInfo;
|
|
7342
|
+
if (cached !== undefined) return cached;
|
|
7343
|
+
const members = this._members;
|
|
7344
|
+
const membersOptionals = this._membersOptionals;
|
|
7345
|
+
/** @type {MemberRanges | undefined} */
|
|
7346
|
+
let memberRanges;
|
|
7347
|
+
const getMembers = () => members;
|
|
7348
|
+
const getMembersOptionals = () => membersOptionals;
|
|
7349
|
+
const getMemberRanges = () =>
|
|
7350
|
+
memberRanges ||
|
|
7351
|
+
(memberRanges = memberRangesOf(expression, members.length));
|
|
7352
|
+
const rootInfo = /** @type {string | VariableInfo} */ (
|
|
7353
|
+
this._memberRootInfo
|
|
7354
|
+
);
|
|
7355
|
+
/** @type {CallExpressionInfo | ExpressionExpressionInfo} */
|
|
7356
|
+
let info;
|
|
7357
|
+
if (type === 2) {
|
|
7358
|
+
const calleeMembers = this._memberCalleeMembers;
|
|
7359
|
+
info = {
|
|
7360
|
+
type: "call",
|
|
7361
|
+
call: /** @type {CallExpression} */ (this._memberCall),
|
|
7362
|
+
calleeName: this._memberCalleeName,
|
|
7363
|
+
rootInfo,
|
|
7364
|
+
getCalleeMembers: () => calleeMembers,
|
|
7365
|
+
name: this._memberName,
|
|
7366
|
+
getMembers,
|
|
7367
|
+
getMembersOptionals,
|
|
7368
|
+
getMemberRanges
|
|
7369
|
+
};
|
|
7370
|
+
} else {
|
|
7371
|
+
info = {
|
|
7372
|
+
type: "expression",
|
|
7373
|
+
name: this._memberName,
|
|
7374
|
+
rootInfo,
|
|
7375
|
+
getMembers,
|
|
7376
|
+
getMembersOptionals,
|
|
7377
|
+
getMemberRanges
|
|
7378
|
+
};
|
|
6307
7379
|
}
|
|
7380
|
+
this._memberInfo = info;
|
|
7381
|
+
return info;
|
|
6308
7382
|
}
|
|
6309
7383
|
|
|
6310
7384
|
/**
|
|
@@ -6373,7 +7447,10 @@ class JavascriptParser extends Parser {
|
|
|
6373
7447
|
// syntax so `auto` avoids a second full parse in the common case
|
|
6374
7448
|
parserOptions.moduleFallback = type === "auto";
|
|
6375
7449
|
}
|
|
6376
|
-
|
|
7450
|
+
// `locations` are acorn's to track, so the lazy path serves the callers
|
|
7451
|
+
// that ask for ranges alone — which is every one inside webpack
|
|
7452
|
+
const wantLazyNodes =
|
|
7453
|
+
parserOptions.ranges === true && parserOptions.locations !== true;
|
|
6377
7454
|
/**
|
|
6378
7455
|
* Returns parse result.
|
|
6379
7456
|
* @param {string} code source code
|
|
@@ -6388,34 +7465,27 @@ class JavascriptParser extends Parser {
|
|
|
6388
7465
|
/** @type {Comment[]} */
|
|
6389
7466
|
const comments = [];
|
|
6390
7467
|
|
|
6391
|
-
//
|
|
6392
|
-
//
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
options.lazyNodes = wantRanges;
|
|
6396
|
-
if (wantRanges) {
|
|
7468
|
+
// Ranges alone (the main parse path and the concatenation re-parse) are
|
|
7469
|
+
// served on demand; hoisted, since the auto-fallback re-enters here.
|
|
7470
|
+
options.lazyNodes = wantLazyNodes;
|
|
7471
|
+
if (wantLazyNodes) {
|
|
6397
7472
|
// the lazy plugin replaces acorn's native tracking — disabling it
|
|
6398
7473
|
// here lets WebpackParser skip its defensive options copy
|
|
6399
|
-
options.locations = false;
|
|
6400
7474
|
options.ranges = false;
|
|
6401
7475
|
}
|
|
6402
7476
|
|
|
6403
7477
|
if (options.comments) {
|
|
6404
|
-
if (
|
|
7478
|
+
if (wantLazyNodes) {
|
|
6405
7479
|
// the parser plugin collects the comments itself, deferring the
|
|
6406
7480
|
// text slice until some hook actually reads `value`
|
|
6407
7481
|
options.lazyComments = comments;
|
|
6408
7482
|
} else {
|
|
6409
|
-
/** @type {
|
|
6410
|
-
(options).onComment =
|
|
6411
|
-
/** @type {import("acorn").Comment[]} */
|
|
6412
|
-
(/** @type {unknown} */ (comments));
|
|
7483
|
+
/** @type {ParserOptions} */
|
|
7484
|
+
(options).onComment = comments;
|
|
6413
7485
|
}
|
|
6414
7486
|
}
|
|
6415
7487
|
|
|
6416
|
-
const ast =
|
|
6417
|
-
/** @type {Program} */
|
|
6418
|
-
(parser.parse(code, /** @type {AcornOptions} */ (options)));
|
|
7488
|
+
const ast = /** @type {Program} */ (parser.parse(code, options));
|
|
6419
7489
|
|
|
6420
7490
|
return { ast, comments };
|
|
6421
7491
|
};
|
|
@@ -6451,7 +7521,7 @@ class JavascriptParser extends Parser {
|
|
|
6451
7521
|
// release per-parse state retained on the (possibly reused) options
|
|
6452
7522
|
// object — the comments array retains source text slices
|
|
6453
7523
|
parserOptions.lazyComments = undefined;
|
|
6454
|
-
/** @type {
|
|
7524
|
+
/** @type {ParserOptions} */
|
|
6455
7525
|
(parserOptions).onComment = undefined;
|
|
6456
7526
|
|
|
6457
7527
|
if (threw) {
|
|
@@ -6463,7 +7533,7 @@ class JavascriptParser extends Parser {
|
|
|
6463
7533
|
|
|
6464
7534
|
/**
|
|
6465
7535
|
* Returns parser.
|
|
6466
|
-
* @param {
|
|
7536
|
+
* @param {ParserPlugin[]} plugins parser plugin
|
|
6467
7537
|
* @returns {typeof JavascriptParser} parser
|
|
6468
7538
|
*/
|
|
6469
7539
|
static extend(...plugins) {
|