@depup/webpack 5.111.1-depup.2 → 5.112.0-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 +4 -8
- package/changes.json +3 -19
- package/lib/Chunk.js +3 -966
- package/lib/Compilation.js +224 -106
- package/lib/Compiler.js +19 -19
- package/lib/Dependency.js +3 -551
- package/lib/DependencyTemplate.js +3 -70
- package/lib/EntryPlugin.js +3 -68
- package/lib/Entrypoint.js +3 -121
- package/lib/ExternalsPlugin.js +3 -92
- package/lib/FileSystemInfo.js +3 -4629
- package/lib/InitFragment.js +3 -204
- package/lib/LibraryTemplatePlugin.js +3 -46
- package/lib/ModuleFilenameHelpers.js +3 -400
- package/lib/ModuleNotFoundError.js +2 -2
- package/lib/MultiCompiler.js +37 -8
- package/lib/NormalModule.js +3 -2242
- package/lib/NullFactory.js +3 -22
- package/lib/ProgressPlugin.js +3 -908
- package/lib/RawModule.js +3 -197
- package/lib/RequestShortener.js +3 -37
- package/lib/SingleEntryPlugin.js +1 -1
- package/lib/WebpackError.js +2 -2
- package/lib/asset/AssetBytesGenerator.js +8 -8
- package/lib/asset/AssetBytesParser.js +3 -3
- package/lib/asset/AssetGenerator.js +36 -22
- package/lib/asset/AssetModule.js +2 -2
- package/lib/asset/AssetModulesPlugin.js +6 -9
- package/lib/asset/AssetParser.js +3 -3
- package/lib/asset/AssetSourceGenerator.js +8 -8
- package/lib/asset/AssetSourceParser.js +3 -3
- package/lib/asset/RawDataUrlModule.js +17 -10
- package/lib/asset/WebManifestGenerator.js +7 -7
- package/lib/asset/WebManifestParser.js +5 -5
- package/lib/async-modules/AsyncModuleHelpers.js +6 -5
- package/lib/async-modules/AwaitDependenciesInitFragment.js +4 -4
- package/lib/async-modules/InferAsyncModulesPlugin.js +4 -3
- package/lib/async-modules/isGeneratorLowered.js +3 -3
- package/lib/bun/BunTargetPlugin.js +1 -1
- package/lib/cache/AddBuildDependenciesPlugin.js +2 -19
- package/lib/{Cache.js → cache/Cache.js} +1 -1
- package/lib/{CacheFacade.js → cache/CacheFacade.js} +5 -5
- package/lib/cache/IdleFileCachePlugin.js +2 -2
- package/lib/cache/MemoryCachePlugin.js +2 -2
- package/lib/cache/MemoryWithGcCachePlugin.js +2 -2
- package/lib/cache/PackFileCacheStrategy.js +8 -10
- package/lib/cache/ResolverCachePlugin.js +8 -4
- package/lib/cache/mergeEtags.js +1 -1
- package/lib/{OptionsApply.js → config/OptionsApply.js} +3 -3
- package/lib/{PlatformPlugin.js → config/PlatformPlugin.js} +2 -2
- package/lib/{WebpackOptionsApply.js → config/WebpackOptionsApply.js} +217 -200
- package/lib/{WebpackOptionsDefaulter.js → config/WebpackOptionsDefaulter.js} +3 -3
- package/lib/config/browserslistTargetHandler.js +1 -1
- package/lib/{cli.js → config/cli.js} +5 -158
- package/lib/config/defaults.js +144 -48
- package/lib/config/getClaimedAssetTypes.js +21 -13
- package/lib/config/normalization.js +18 -7
- package/lib/config/target.js +10 -0
- package/lib/container/ContainerEntryDependency.js +1 -1
- package/lib/container/ContainerEntryModule.js +13 -11
- package/lib/container/ContainerEntryModuleFactory.js +2 -2
- package/lib/container/ContainerExposedDependency.js +1 -1
- package/lib/container/ContainerPlugin.js +178 -5
- package/lib/container/ContainerReferencePlugin.js +75 -14
- package/lib/container/FallbackDependency.js +1 -1
- package/lib/container/FallbackItemDependency.js +1 -1
- package/lib/container/FallbackModule.js +12 -10
- package/lib/container/FallbackModuleFactory.js +2 -2
- package/lib/container/HoistContainerReferencesPlugin.js +10 -11
- package/lib/container/ModuleFederationPlugin.js +306 -7
- package/lib/container/RemoteModule.js +14 -10
- package/lib/container/RemoteRuntimeModule.js +5 -5
- package/lib/container/RemoteToExternalDependency.js +1 -1
- package/lib/container/moduleFederationHooks.js +1 -1
- package/lib/context/ContextModule.js +36 -25
- package/lib/context/ContextModuleFactory.js +13 -10
- package/lib/context/ContextReplacementPlugin.js +3 -3
- package/lib/css/CssGenerator.js +38 -31
- package/lib/css/CssInjectStyleRuntimeModule.js +36 -30
- package/lib/css/CssLoadingRuntimeModule.js +77 -44
- package/lib/css/CssModule.js +27 -29
- package/lib/css/CssModulesPlugin.js +128 -44
- package/lib/css/CssParser.js +682 -291
- package/lib/css/CssServerStylesRuntimeModule.js +3 -3
- package/lib/css/cssMinify.js +110 -37
- package/lib/css/data.js +6985 -5125
- package/lib/css/syntax-parser.js +19873 -0
- package/lib/css/syntax-printer.js +6037 -0
- package/lib/css/syntax.js +37 -18686
- package/lib/debug/ProfilingPlugin.js +52 -19
- package/lib/{DefinePlugin.js → define/DefinePlugin.js} +407 -41
- package/lib/{DotenvPlugin.js → define/DotenvPlugin.js} +9 -9
- package/lib/{EnvironmentPlugin.js → define/EnvironmentPlugin.js} +2 -2
- package/lib/deno/DenoTargetPlugin.js +1 -1
- package/lib/dependencies/ConstDependency.js +3 -120
- package/lib/dependencies/ContextElementDependency.js +5 -172
- package/lib/dependencies/NullDependency.js +3 -37
- package/lib/dependencies/{AMDDefineDependency.js → amd/AMDDefineDependency.js} +12 -11
- package/lib/dependencies/{AMDDefineDependencyParserPlugin.js → amd/AMDDefineDependencyParserPlugin.js} +10 -10
- package/lib/dependencies/{AMDPlugin.js → amd/AMDPlugin.js} +11 -11
- package/lib/dependencies/{AMDRequireArrayDependency.js → amd/AMDRequireArrayDependency.js} +15 -13
- package/lib/dependencies/{AMDRequireContextDependency.js → amd/AMDRequireContextDependency.js} +11 -10
- package/lib/dependencies/{AMDRequireDependenciesBlock.js → amd/AMDRequireDependenciesBlock.js} +7 -6
- package/lib/dependencies/{AMDRequireDependenciesBlockParserPlugin.js → amd/AMDRequireDependenciesBlockParserPlugin.js} +10 -10
- package/lib/dependencies/{AMDRequireDependency.js → amd/AMDRequireDependency.js} +13 -12
- package/lib/dependencies/{AMDRequireItemDependency.js → amd/AMDRequireItemDependency.js} +8 -7
- package/lib/dependencies/{AMDRuntimeModules.js → amd/AMDRuntimeModules.js} +3 -3
- package/lib/dependencies/{LocalModule.js → amd/LocalModule.js} +8 -4
- package/lib/dependencies/{LocalModuleDependency.js → amd/LocalModuleDependency.js} +17 -10
- package/lib/dependencies/{LocalModulesHelpers.js → amd/LocalModulesHelpers.js} +1 -1
- package/lib/dependencies/{RequireJsStuffPlugin.js → amd/RequireJsStuffPlugin.js} +9 -9
- package/lib/dependencies/{UnsupportedDependency.js → amd/UnsupportedDependency.js} +11 -10
- package/lib/dependencies/{CommonJsDependencyHelpers.js → commonjs/CommonJsDependencyHelpers.js} +8 -9
- package/lib/dependencies/{CommonJsExportRequireDependency.js → commonjs/CommonJsExportRequireDependency.js} +166 -33
- package/lib/dependencies/{CommonJsExportsDependency.js → commonjs/CommonJsExportsDependency.js} +15 -14
- package/lib/dependencies/{CommonJsExportsParserPlugin.js → commonjs/CommonJsExportsParserPlugin.js} +138 -61
- package/lib/dependencies/{CommonJsFullRequireDependency.js → commonjs/CommonJsFullRequireDependency.js} +32 -24
- package/lib/dependencies/{CommonJsImportsParserPlugin.js → commonjs/CommonJsImportsParserPlugin.js} +35 -30
- package/lib/dependencies/{CommonJsObjectExportDependency.js → commonjs/CommonJsObjectExportDependency.js} +13 -12
- package/lib/dependencies/{CommonJsPlugin.js → commonjs/CommonJsPlugin.js} +47 -35
- package/lib/dependencies/{CommonJsRequireContextDependency.js → commonjs/CommonJsRequireContextDependency.js} +15 -14
- package/lib/dependencies/{CommonJsRequireDependency.js → commonjs/CommonJsRequireDependency.js} +33 -25
- package/lib/dependencies/{CommonJsSelfReferenceDependency.js → commonjs/CommonJsSelfReferenceDependency.js} +17 -16
- package/lib/dependencies/{ModuleDecoratorDependency.js → commonjs/ModuleDecoratorDependency.js} +16 -15
- package/lib/dependencies/{RequireEnsureDependenciesBlock.js → commonjs/RequireEnsureDependenciesBlock.js} +8 -7
- package/lib/dependencies/{RequireEnsureDependenciesBlockParserPlugin.js → commonjs/RequireEnsureDependenciesBlockParserPlugin.js} +5 -5
- package/lib/dependencies/{RequireEnsureDependency.js → commonjs/RequireEnsureDependency.js} +13 -12
- package/lib/dependencies/{RequireEnsureItemDependency.js → commonjs/RequireEnsureItemDependency.js} +7 -6
- package/lib/dependencies/{RequireEnsurePlugin.js → commonjs/RequireEnsurePlugin.js} +8 -8
- package/lib/dependencies/{RequireHeaderDependency.js → commonjs/RequireHeaderDependency.js} +14 -13
- package/lib/dependencies/{RequireIncludeDependency.js → commonjs/RequireIncludeDependency.js} +13 -12
- package/lib/dependencies/{RequireIncludeDependencyParserPlugin.js → commonjs/RequireIncludeDependencyParserPlugin.js} +3 -27
- package/lib/dependencies/{RequireIncludePlugin.js → commonjs/RequireIncludePlugin.js} +4 -4
- package/lib/dependencies/{RequireResolveContextDependency.js → commonjs/RequireResolveContextDependency.js} +11 -10
- package/lib/dependencies/{RequireResolveDependency.js → commonjs/RequireResolveDependency.js} +12 -11
- package/lib/dependencies/{RequireResolveHeaderDependency.js → commonjs/RequireResolveHeaderDependency.js} +13 -12
- package/lib/dependencies/commonjs/TopLevelThisParserPlugin.js +59 -0
- package/lib/dependencies/{ContextDependency.js → context/ContextDependency.js} +15 -14
- package/lib/dependencies/{ContextDependencyHelpers.js → context/ContextDependencyHelpers.js} +31 -9
- package/lib/dependencies/{ContextDependencyTemplateAsId.js → context/ContextDependencyTemplateAsId.js} +3 -3
- package/lib/dependencies/{ContextDependencyTemplateAsRequireCall.js → context/ContextDependencyTemplateAsRequireCall.js} +3 -3
- package/lib/dependencies/context/ContextElementDependency.js +198 -0
- package/lib/dependencies/{ImportMetaContextDependency.js → context/ImportMetaContextDependency.js} +7 -6
- package/lib/dependencies/{ImportMetaContextDependencyParserPlugin.js → context/ImportMetaContextDependencyParserPlugin.js} +9 -9
- package/lib/dependencies/{ImportMetaContextPlugin.js → context/ImportMetaContextPlugin.js} +5 -5
- package/lib/dependencies/{ImportMetaGlobDependency.js → context/ImportMetaGlobDependency.js} +7 -6
- package/lib/dependencies/{ImportMetaGlobDependencyParserPlugin.js → context/ImportMetaGlobDependencyParserPlugin.js} +4 -4
- package/lib/dependencies/{ImportMetaGlobHelpers.js → context/ImportMetaGlobHelpers.js} +9 -9
- package/lib/dependencies/{RequireContextDependency.js → context/RequireContextDependency.js} +7 -6
- package/lib/dependencies/{RequireContextDependencyParserPlugin.js → context/RequireContextDependencyParserPlugin.js} +2 -2
- package/lib/dependencies/{RequireContextPlugin.js → context/RequireContextPlugin.js} +5 -5
- package/lib/dependencies/{CachedConstDependency.js → core/CachedConstDependency.js} +12 -11
- package/lib/dependencies/core/ConstDependency.js +131 -0
- package/lib/dependencies/{ImportPhase.js → core/ImportPhase.js} +5 -4
- package/lib/dependencies/{ModuleDependency.js → core/ModuleDependency.js} +10 -7
- package/lib/dependencies/{ModuleDependencyTemplateAsId.js → core/ModuleDependencyTemplateAsId.js} +3 -3
- package/lib/dependencies/{ModuleDependencyTemplateAsRequireId.js → core/ModuleDependencyTemplateAsRequireId.js} +2 -2
- package/lib/dependencies/{ModuleInitFragmentDependency.js → core/ModuleInitFragmentDependency.js} +10 -9
- package/lib/dependencies/core/NullDependency.js +44 -0
- package/lib/dependencies/{RuntimeRequirementsDependency.js → core/RuntimeRequirementsDependency.js} +10 -9
- package/lib/dependencies/{StaticExportsDependency.js → core/StaticExportsDependency.js} +15 -8
- package/lib/dependencies/{CssIcssExportDependency.js → css/CssIcssExportDependency.js} +369 -92
- package/lib/dependencies/{CssIcssImportDependency.js → css/CssIcssImportDependency.js} +23 -16
- package/lib/dependencies/{CssIcssSymbolDependency.js → css/CssIcssSymbolDependency.js} +13 -12
- package/lib/dependencies/{CssImportDependency.js → css/CssImportDependency.js} +15 -11
- package/lib/dependencies/{CssUrlDependency.js → css/CssUrlDependency.js} +23 -16
- package/lib/dependencies/{CreateRequireParserPlugin.js → esm/CreateRequireParserPlugin.js} +9 -9
- package/lib/dependencies/{HarmonyAcceptDependency.js → esm/ESMAcceptDependency.js} +41 -38
- package/lib/dependencies/esm/ESMAcceptImportDependency.js +39 -0
- package/lib/dependencies/{HarmonyCompatibilityDependency.js → esm/ESMCompatibilityDependency.js} +29 -21
- package/lib/dependencies/{HarmonyDetectionParserPlugin.js → esm/ESMDetectionParserPlugin.js} +19 -17
- package/lib/dependencies/{HarmonyEvaluatedImportSpecifierDependency.js → esm/ESMEvaluatedImportSpecifierDependency.js} +33 -30
- package/lib/dependencies/{HarmonyExportDependencyParserPlugin.js → esm/ESMExportDependencyParserPlugin.js} +60 -89
- package/lib/dependencies/{HarmonyExportExpressionDependency.js → esm/ESMExportExpressionDependency.js} +80 -45
- package/lib/dependencies/{HarmonyExportHeaderDependency.js → esm/ESMExportHeaderDependency.js} +17 -15
- package/lib/dependencies/esm/ESMExportImportedSideEffectDependency.js +37 -0
- package/lib/dependencies/{HarmonyExportImportedSpecifierDependency.js → esm/ESMExportImportedSpecifierDependency.js} +133 -118
- package/lib/dependencies/{HarmonyExportInitFragment.js → esm/ESMExportInitFragment.js} +48 -30
- package/lib/dependencies/{HarmonyExportSpecifierDependency.js → esm/ESMExportSpecifierDependency.js} +60 -36
- package/lib/dependencies/{HarmonyExports.js → esm/ESMExports.js} +4 -4
- package/lib/dependencies/{HarmonyImportBareSideEffectDependency.js → esm/ESMImportBareSideEffectDependency.js} +21 -13
- package/lib/dependencies/{HarmonyImportDependency.js → esm/ESMImportDependency.js} +74 -71
- package/lib/dependencies/{HarmonyImportDependencyParserPlugin.js → esm/ESMImportDependencyParserPlugin.js} +99 -84
- package/lib/dependencies/{HarmonyImportGuard.js → esm/ESMImportGuard.js} +26 -29
- package/lib/dependencies/{HarmonyImportSideEffectDependency.js → esm/ESMImportSideEffectDependency.js} +83 -39
- package/lib/dependencies/{HarmonyImportSpecifierDependency.js → esm/ESMImportSpecifierDependency.js} +94 -59
- package/lib/dependencies/esm/ESMModulesPlugin.js +207 -0
- package/lib/dependencies/{HarmonyTopLevelThisParserPlugin.js → esm/ESMTopLevelThisParserPlugin.js} +7 -7
- package/lib/dependencies/{TopLevelAwaitDependency.js → esm/TopLevelAwaitDependency.js} +12 -11
- package/lib/dependencies/{DynamicExports.js → helpers/DynamicExports.js} +2 -2
- package/lib/{util → dependencies/helpers}/chainedImports.js +5 -5
- package/lib/dependencies/{processExportInfo.js → helpers/processExportInfo.js} +4 -4
- package/lib/{util → dependencies/helpers}/traverseDestructuringAssignmentProperties.js +1 -1
- package/lib/dependencies/{ImportMetaHotAcceptDependency.js → hmr/ImportMetaHotAcceptDependency.js} +8 -7
- package/lib/dependencies/{ImportMetaHotDeclineDependency.js → hmr/ImportMetaHotDeclineDependency.js} +8 -7
- package/lib/dependencies/{ModuleHotAcceptDependency.js → hmr/ModuleHotAcceptDependency.js} +8 -7
- package/lib/dependencies/{ModuleHotDeclineDependency.js → hmr/ModuleHotDeclineDependency.js} +8 -7
- package/lib/dependencies/{HtmlEntryDependency.js → html/HtmlEntryDependency.js} +51 -141
- package/lib/dependencies/{HtmlInlineHtmlDependency.js → html/HtmlInlineHtmlDependency.js} +13 -12
- package/lib/dependencies/{HtmlInlineScriptDependency.js → html/HtmlInlineScriptDependency.js} +69 -19
- package/lib/dependencies/{HtmlInlineStyleDependency.js → html/HtmlInlineStyleDependency.js} +50 -15
- package/lib/dependencies/{HtmlSourceDependency.js → html/HtmlSourceDependency.js} +23 -16
- package/lib/dependencies/{ImportContextDependency.js → import/ImportContextDependency.js} +24 -10
- package/lib/dependencies/{ImportDependency.js → import/ImportDependency.js} +26 -18
- package/lib/dependencies/{ImportEagerDependency.js → import/ImportEagerDependency.js} +18 -10
- package/lib/dependencies/{ImportParserPlugin.js → import/ImportParserPlugin.js} +20 -20
- package/lib/dependencies/{ImportPlugin.js → import/ImportPlugin.js} +4 -4
- package/lib/dependencies/{ImportWeakDependency.js → import/ImportWeakDependency.js} +18 -10
- package/lib/dependencies/{importOptionsCheck.js → import/importOptionsCheck.js} +2 -2
- package/lib/dependencies/{BuildTimeConstDependency.js → import-meta/BuildTimeConstDependency.js} +12 -11
- package/lib/dependencies/{ImportMetaMainDependency.js → import-meta/ImportMetaMainDependency.js} +12 -11
- package/lib/dependencies/{ImportMetaPlugin.js → import-meta/ImportMetaPlugin.js} +119 -98
- package/lib/dependencies/{SystemPlugin.js → system/SystemPlugin.js} +11 -38
- package/lib/dependencies/{SystemRuntimeModule.js → system/SystemRuntimeModule.js} +3 -3
- package/lib/dependencies/{ImportMetaResolveDependency.js → url/ImportMetaResolveDependency.js} +9 -8
- package/lib/dependencies/{URLContextDependency.js → url/URLContextDependency.js} +11 -10
- package/lib/dependencies/{URLDependency.js → url/URLDependency.js} +28 -20
- package/lib/{url → dependencies/url}/URLParserPlugin.js +16 -18
- package/lib/dependencies/{URLPlugin.js → url/URLPlugin.js} +6 -7
- package/lib/dependencies/{WebAssemblyExportImportedDependency.js → wasm/WebAssemblyExportImportedDependency.js} +18 -11
- package/lib/dependencies/{WebAssemblyImportDependency.js → wasm/WebAssemblyImportDependency.js} +19 -12
- package/lib/dependencies/{CreateScriptUrlDependency.js → worker/CreateScriptUrlDependency.js} +12 -11
- package/lib/dependencies/{WorkerAndWorkletPlugin.js → worker/WorkerAndWorkletPlugin.js} +31 -33
- package/lib/dependencies/{WorkerDependency.js → worker/WorkerDependency.js} +22 -15
- package/lib/dependencies/{WorkletDependency.js → worker/WorkletDependency.js} +19 -18
- package/lib/{EvalDevToolModulePlugin.js → devtool/EvalDevToolModulePlugin.js} +20 -6
- package/lib/{EvalSourceMapDevToolPlugin.js → devtool/EvalSourceMapDevToolPlugin.js} +32 -24
- package/lib/devtool/ModuleFilenameHelpers.js +413 -0
- package/lib/{SourceMapDevToolModuleOptionsPlugin.js → devtool/SourceMapDevToolModuleOptionsPlugin.js} +10 -3
- package/lib/{SourceMapDevToolPlugin.js → devtool/SourceMapDevToolPlugin.js} +154 -26
- package/lib/{util → devtool}/generateDebugId.js +1 -1
- package/lib/{IgnoreWarningsPlugin.js → diagnostics/IgnoreWarningsPlugin.js} +2 -2
- package/lib/{NoEmitOnErrorsPlugin.js → diagnostics/NoEmitOnErrorsPlugin.js} +1 -1
- package/lib/diagnostics/WarnCaseSensitiveModulesPlugin.js +64 -0
- package/lib/{WarnDeprecatedOptionPlugin.js → diagnostics/WarnDeprecatedOptionPlugin.js} +2 -22
- package/lib/diagnostics/WarnNoModeSetPlugin.js +27 -0
- package/lib/dll/DelegatedModule.js +20 -18
- package/lib/dll/DelegatedModuleFactoryPlugin.js +2 -2
- package/lib/dll/DelegatedPlugin.js +1 -1
- package/lib/{dependencies → dll}/DelegatedSourceDependency.js +5 -4
- package/lib/{dependencies → dll}/DllEntryDependency.js +6 -5
- package/lib/dll/DllEntryPlugin.js +3 -3
- package/lib/dll/DllModule.js +11 -9
- package/lib/dll/DllModuleFactory.js +3 -3
- package/lib/dll/DllPlugin.js +18 -6
- package/lib/dll/DllReferencePlugin.js +102 -26
- package/lib/dll/LibManifestPlugin.js +9 -7
- package/lib/electron/ElectronTargetPlugin.js +2 -2
- package/lib/{DynamicEntryPlugin.js → entry/DynamicEntryPlugin.js} +3 -3
- package/lib/{dependencies → entry}/EntryDependency.js +11 -2
- package/lib/{EntryOptionPlugin.js → entry/EntryOptionPlugin.js} +6 -6
- package/lib/entry/EntryPlugin.js +75 -0
- package/lib/{performance → errors}/AssetsOverSizeLimitWarning.js +2 -2
- package/lib/errors/AsyncDependencyToInitialChunkError.js +2 -2
- package/lib/errors/BuildCycleError.js +1 -1
- package/lib/{WarnCaseSensitiveModulesPlugin.js → errors/CaseSensitiveModulesWarning.js} +4 -56
- package/lib/errors/ChunkRenderError.js +1 -1
- package/lib/errors/CodeGenerationError.js +1 -1
- package/lib/errors/CommentCompilationWarning.js +1 -1
- package/lib/errors/ConflictingEntryExportsWarning.js +38 -0
- package/lib/{dependencies → errors}/CriticalDependencyWarning.js +4 -3
- package/lib/errors/DeprecatedOptionWarning.js +30 -0
- package/lib/errors/DllManifestError.js +26 -0
- package/lib/{performance → errors}/DuplicatePackagesWarning.js +6 -6
- package/lib/{dependencies/HarmonyLinkingError.js → errors/ESMLinkingError.js} +4 -4
- package/lib/{performance → errors}/EntrypointsOverSizeLimitWarning.js +2 -2
- package/lib/errors/EnvironmentNotSupportAsyncWarning.js +2 -2
- package/lib/{ErrorHelpers.js → errors/ErrorHelpers.js} +7 -5
- package/lib/errors/ExternalStarReexportError.js +2 -2
- package/lib/{library → errors}/FalseIIFEUmdWarning.js +1 -1
- package/lib/errors/HookWebpackError.js +4 -4
- package/lib/errors/IgnoreErrorModuleFactory.js +3 -3
- package/lib/errors/InvalidDependenciesModuleWarning.js +1 -1
- package/lib/{optimize → errors}/MinMaxSizeWarning.js +1 -1
- package/lib/errors/ModuleBuildError.js +1 -1
- package/lib/errors/ModuleDependencyError.js +2 -2
- package/lib/errors/ModuleDependencyWarning.js +2 -2
- package/lib/errors/ModuleError.js +1 -1
- package/lib/errors/ModuleHashingError.js +1 -1
- package/lib/errors/ModuleNotFoundError.js +3 -3
- package/lib/errors/ModuleParseError.js +1 -1
- package/lib/errors/ModuleRestoreError.js +1 -1
- package/lib/errors/ModuleStoreError.js +1 -1
- package/lib/errors/ModuleWarning.js +1 -1
- package/lib/{performance → errors}/NoAsyncChunksWarning.js +1 -1
- package/lib/{WarnNoModeSetPlugin.js → errors/NoModeWarning.js} +2 -19
- package/lib/errors/NodeStuffInWebError.js +7 -2
- package/lib/errors/PathVariableError.js +31 -0
- package/lib/errors/RequireIncludeDeprecationWarning.js +40 -0
- package/lib/{performance → errors}/RuntimeInLargeChunkWarning.js +1 -1
- package/lib/errors/RuntimeModuleGenerationError.js +51 -0
- package/lib/errors/SSRManifestAutoPublicPathWarning.js +24 -0
- package/lib/errors/SystemImportDeprecationWarning.js +43 -0
- package/lib/errors/UnmergeableEntryExportsError.js +34 -0
- package/lib/errors/UnsupportedFeatureWarning.js +1 -1
- package/lib/{wasm-sync → errors}/UnsupportedWebAssemblyFeatureError.js +1 -1
- package/lib/{wasm-sync → errors}/WebAssemblyInInitialChunkError.js +7 -5
- package/lib/errors/WebpackError.js +12 -3
- package/lib/esm/ExportWebpackRequireRuntimeModule.js +2 -2
- package/lib/esm/ModuleChunkFormatPlugin.js +19 -19
- package/lib/esm/ModuleChunkLoadingPlugin.js +3 -3
- package/lib/esm/ModuleChunkLoadingRuntimeModule.js +8 -8
- package/lib/{ExternalModule.js → externals/ExternalModule.js} +79 -55
- package/lib/{ExternalModuleFactoryPlugin.js → externals/ExternalModuleFactoryPlugin.js} +41 -39
- package/lib/externals/ExternalsPlugin.js +99 -0
- package/lib/fs/FileSystemInfo.js +4642 -0
- package/lib/{util → fs}/fs.js +22 -9
- package/lib/{AsyncDependenciesBlock.js → graph/AsyncDependenciesBlock.js} +27 -4
- package/lib/graph/Chunk.js +985 -0
- package/lib/{ChunkGraph.js → graph/ChunkGraph.js} +187 -80
- package/lib/{ChunkGroup.js → graph/ChunkGroup.js} +11 -3
- package/lib/{DependenciesBlock.js → graph/DependenciesBlock.js} +16 -4
- package/lib/graph/Dependency.js +628 -0
- package/lib/graph/Entrypoint.js +136 -0
- package/lib/{ExportsInfo.js → graph/ExportsInfo.js} +130 -82
- package/lib/{HotUpdateChunk.js → graph/HotUpdateChunk.js} +8 -0
- package/lib/{ModuleGraph.js → graph/ModuleGraph.js} +30 -30
- package/lib/{ModuleGraphConnection.js → graph/ModuleGraphConnection.js} +2 -2
- package/lib/{buildChunkGraph.js → graph/buildChunkGraph.js} +152 -57
- package/lib/{util → graph}/findGraphRoots.js +14 -8
- package/lib/graph/isDependencyKind.js +23 -0
- package/lib/hmr/HotModuleReplacement.runtime.js +2 -2
- package/lib/{HotModuleReplacementPlugin.js → hmr/HotModuleReplacementPlugin.js} +47 -47
- package/lib/hmr/HotModuleReplacementRuntimeModule.js +3 -3
- package/lib/hmr/JavascriptHotModuleReplacement.runtime.js +10 -8
- package/lib/hmr/JavascriptHotModuleReplacementHelper.js +2 -2
- package/lib/hmr/LazyCompilationPlugin.js +31 -21
- package/lib/html/HtmlGenerator.js +107 -43
- package/lib/html/HtmlModule.js +6 -2
- package/lib/html/HtmlModulesPlugin.js +172 -76
- package/lib/html/HtmlParser.js +503 -153
- package/lib/html/builtinEmbeddedRenderer.js +60 -13
- package/lib/html/data.js +2 -1
- package/lib/html/htmlMinify.js +111 -41
- package/lib/html/syntax-parser.js +15796 -0
- package/lib/html/syntax-printer.js +1034 -0
- package/lib/html/syntax.js +37 -13952
- package/lib/html/xmlMinify.js +67 -0
- package/lib/ids/ChunkModuleIdRangePlugin.js +2 -2
- package/lib/ids/DeterministicModuleIdsPlugin.js +1 -1
- package/lib/ids/HashedModuleIdsPlugin.js +31 -4
- package/lib/ids/IdHelpers.js +4 -4
- package/lib/ids/NaturalChunkIdsPlugin.js +1 -1
- package/lib/ids/OccurrenceChunkIdsPlugin.js +6 -5
- package/lib/ids/OccurrenceModuleIdsPlugin.js +6 -5
- package/lib/{RecordIdsPlugin.js → ids/RecordIdsPlugin.js} +5 -5
- package/lib/ids/SyncModuleIdsPlugin.js +3 -3
- package/lib/{util → ids}/numberHash.js +1 -1
- package/lib/index.js +303 -97
- package/lib/{APIPlugin.js → javascript/APIPlugin.js} +25 -25
- package/lib/javascript/ArrayPushCallbackChunkFormatPlugin.js +4 -5
- package/lib/javascript/BasicEvaluatedExpression.js +4 -4
- package/lib/javascript/ChunkHelpers.js +64 -4
- package/lib/javascript/CommonJsChunkFormatPlugin.js +4 -7
- package/lib/{CompatibilityPlugin.js → javascript/CompatibilityPlugin.js} +7 -7
- package/lib/{ConstPlugin.js → javascript/ConstPlugin.js} +74 -7
- package/lib/{ExportsInfoApiPlugin.js → javascript/ExportsInfoApiPlugin.js} +5 -5
- package/lib/{dependencies → javascript}/ExportsInfoDependency.js +10 -9
- package/lib/javascript/JavascriptGenerator.js +17 -17
- package/lib/{JavascriptMetaInfoPlugin.js → javascript/JavascriptMetaInfoPlugin.js} +7 -7
- package/lib/javascript/JavascriptModule.js +4 -3
- package/lib/javascript/JavascriptModulesPlugin.js +440 -211
- package/lib/javascript/JavascriptParser.js +220 -134
- package/lib/javascript/JavascriptParserHelpers.js +1 -1
- package/lib/javascript/MergedEntryExports.js +196 -0
- package/lib/javascript/ScopeAnalyzer.js +3840 -5
- package/lib/javascript/StartupHelpers.js +6 -6
- package/lib/{UseStrictPlugin.js → javascript/UseStrictPlugin.js} +12 -15
- package/lib/{dependencies → javascript}/WebpackIsIncludedDependency.js +10 -9
- package/lib/{WebpackIsIncludedPlugin.js → javascript/WebpackIsIncludedPlugin.js} +8 -8
- package/lib/javascript/data.js +533 -122
- package/lib/javascript/jsMinify.js +272 -0
- package/lib/javascript/regexp.js +67 -32
- package/lib/javascript/syntax-parser.js +18561 -0
- package/lib/javascript/syntax-printer-data.js +933 -0
- package/lib/javascript/syntax-printer.js +47106 -0
- package/lib/javascript/syntax.js +20 -11274
- package/lib/json/JsonData.js +1 -1
- package/lib/{dependencies → json}/JsonExportsDependency.js +8 -7
- package/lib/json/JsonGenerator.js +10 -10
- package/lib/json/JsonModule.js +2 -2
- package/lib/json/JsonModulesPlugin.js +1 -1
- package/lib/json/JsonParser.js +5 -5
- package/lib/json/jsonMinify.js +69 -0
- package/lib/library/AbstractLibraryPlugin.js +28 -15
- package/lib/library/AmdLibraryPlugin.js +4 -4
- package/lib/library/AssignLibraryPlugin.js +27 -11
- package/lib/library/EnableLibraryPlugin.js +1 -1
- package/lib/library/ExportPropertyLibraryPlugin.js +4 -4
- package/lib/library/JsonpLibraryPlugin.js +1 -1
- package/lib/library/LibraryTemplatePlugin.js +53 -0
- package/lib/library/ModuleLibraryPlugin.js +160 -166
- package/lib/library/SystemLibraryPlugin.js +6 -8
- package/lib/library/UmdLibraryPlugin.js +3 -4
- package/lib/{dependencies → loaders}/LoaderDependency.js +3 -3
- package/lib/{dependencies → loaders}/LoaderImportDependency.js +9 -3
- package/lib/{LoaderOptionsPlugin.js → loaders/LoaderOptionsPlugin.js} +30 -12
- package/lib/{dependencies → loaders}/LoaderPlugin.js +2 -2
- package/lib/loaders/LoaderRunner.js +31 -21
- package/lib/{LoaderTargetPlugin.js → loaders/LoaderTargetPlugin.js} +2 -2
- package/lib/logging/Logger.js +7 -9
- package/lib/logging/ProgressPlugin.js +957 -0
- package/lib/{CodeGenerationResults.js → module/CodeGenerationResults.js} +7 -7
- package/lib/{Generator.js → module/Generator.js} +16 -14
- package/lib/{Module.js → module/Module.js} +119 -51
- package/lib/{ModuleFactory.js → module/ModuleFactory.js} +3 -3
- package/lib/module/NormalModule.js +2348 -0
- package/lib/{NormalModuleFactory.js → module/NormalModuleFactory.js} +53 -54
- package/lib/module/NullFactory.js +29 -0
- package/lib/{Parser.js → module/Parser.js} +3 -3
- package/lib/module/RawModule.js +208 -0
- package/lib/{SelfModuleFactory.js → module/SelfModuleFactory.js} +1 -1
- package/lib/{util → module}/extractSourceMap.js +2 -2
- package/lib/{util → module}/findCaseMismatch.js +2 -2
- package/lib/node/CommonJsChunkLoadingPlugin.js +3 -3
- package/lib/{dependencies → node}/ExternalModuleDependency.js +8 -7
- package/lib/{dependencies → node}/ExternalModuleInitFragment.js +6 -5
- package/lib/{dependencies → node}/ExternalModuleInitFragmentDependency.js +14 -9
- package/lib/node/NodeEnvironmentPlugin.js +11 -1
- package/lib/{NodeStuffPlugin.js → node/NodeStuffPlugin.js} +17 -17
- package/lib/node/NodeTargetPlugin.js +1 -1
- package/lib/node/NodeWatchFileSystem.js +58 -6
- package/lib/node/ReadFileChunkLoadingRuntimeModule.js +7 -7
- package/lib/node/ReadFileCompileAsyncWasmPlugin.js +9 -7
- package/lib/node/ReadFileCompileWasmPlugin.js +7 -5
- package/lib/node/RequireChunkLoadingRuntimeModule.js +7 -7
- package/lib/node/nodeConsole.js +2 -4
- package/lib/optimize/AggressiveMergingPlugin.js +2 -2
- package/lib/optimize/AggressiveSplittingPlugin.js +12 -8
- package/lib/{CircularModulesPlugin.js → optimize/CircularModulesPlugin.js} +13 -13
- package/lib/optimize/ConcatenatedModule.js +229 -214
- package/lib/{ConcatenationScope.js → optimize/ConcatenationScope.js} +39 -6
- package/lib/optimize/ConstExportsPlugin.js +7 -7
- package/lib/optimize/EnsureChunkConditionsPlugin.js +3 -3
- package/lib/{FlagAllModulesAsUsedPlugin.js → optimize/FlagAllModulesAsUsedPlugin.js} +3 -3
- package/lib/{FlagDependencyExportsPlugin.js → optimize/FlagDependencyExportsPlugin.js} +17 -17
- package/lib/{FlagDependencyUsagePlugin.js → optimize/FlagDependencyUsagePlugin.js} +17 -17
- package/lib/{FlagEntryExportAsUsedPlugin.js → optimize/FlagEntryExportAsUsedPlugin.js} +2 -2
- package/lib/optimize/FlagIncludedChunksPlugin.js +2 -2
- package/lib/optimize/InlineExports.js +11 -3
- package/lib/optimize/InnerGraph.js +5 -13
- package/lib/optimize/InnerGraphPlugin.js +10 -10
- package/lib/optimize/LazyBarrels.js +584 -0
- package/lib/{util → optimize}/LazyBucketSortedSet.js +2 -2
- package/lib/optimize/LimitChunkCountPlugin.js +16 -7
- package/lib/optimize/MangleExportsPlugin.js +5 -5
- package/lib/optimize/MergeDuplicateChunksPlugin.js +7 -6
- package/lib/optimize/MinChunkSizePlugin.js +9 -6
- package/lib/optimize/ModuleConcatenationPlugin.js +20 -12
- package/lib/{dependencies → optimize}/PureExpressionDependency.js +11 -10
- package/lib/optimize/RealContentHashPlugin.js +16 -7
- package/lib/optimize/RemoveEmptyChunksPlugin.js +2 -2
- package/lib/optimize/RemoveParentModulesPlugin.js +4 -4
- package/lib/optimize/SideEffectsFlagPlugin.js +18 -18
- package/lib/optimize/SplitChunksPlugin.js +713 -155
- package/lib/{util → optimize}/TupleQueue.js +9 -9
- package/lib/optimize/chunkSetIntersections.js +437 -0
- package/lib/{util → optimize}/deterministicGrouping.js +17 -17
- package/lib/{BannerPlugin.js → output/BannerPlugin.js} +82 -14
- package/lib/{CleanPlugin.js → output/CleanPlugin.js} +66 -24
- package/lib/{CopyPlugin.js → output/CopyPlugin.js} +142 -67
- package/lib/{ManifestPlugin.js → output/ManifestPlugin.js} +91 -17
- package/lib/output/SSRManifestPlugin.js +349 -0
- package/lib/performance/AnalyzableBailoutsPlugin.js +1 -1
- package/lib/performance/AsyncChunkWaterfallsPlugin.js +1 -1
- package/lib/performance/BroadContextsPlugin.js +4 -4
- package/lib/performance/CacheEffectivenessPlugin.js +2 -3
- package/lib/performance/ConflictingResourceHintsPlugin.js +1 -1
- package/lib/performance/DuplicateModulesPlugin.js +3 -4
- package/lib/performance/DuplicatePackagesPlugin.js +3 -3
- package/lib/performance/DynamicExportsPlugin.js +2 -2
- package/lib/performance/EvalUsagePlugin.js +3 -3
- package/lib/performance/HotspotsPlugin.js +11 -10
- package/lib/performance/LargeModulesPlugin.js +2 -3
- package/lib/performance/LegacyJavascriptPlugin.js +1 -2
- package/lib/performance/MissingSideEffectsPlugin.js +2 -3
- package/lib/performance/MissingSourceMapsPlugin.js +5 -6
- package/lib/performance/PureAnnotationsPlugin.js +3 -3
- package/lib/performance/RedundantDynamicImportsPlugin.js +6 -8
- package/lib/performance/ScopeHoistingBailoutsPlugin.js +2 -2
- package/lib/performance/SizeLimitsPlugin.js +11 -12
- package/lib/performance/TopLevelThisPlugin.js +8 -7
- package/lib/performance/UnsplitVendorsPlugin.js +1 -2
- package/lib/performance/UnusedAliasesPlugin.js +6 -7
- package/lib/performance/UnusedAssetsPlugin.js +5 -5
- package/lib/performance/UnusedDefinesPlugin.js +2 -2
- package/lib/performance/UnusedExternalsPlugin.js +3 -4
- package/lib/performance/UnusedFederationPlugin.js +2 -4
- package/lib/performance/UnusedModulesPlugin.js +5 -4
- package/lib/performance/getModuleSize.js +1 -1
- package/lib/performance/hasOnlyUnusedExports.js +4 -4
- package/lib/performance/isOnlyReexported.js +7 -6
- package/lib/{AutomaticPrefetchPlugin.js → prefetch/AutomaticPrefetchPlugin.js} +4 -5
- package/lib/prefetch/ChunkPrefetchFunctionRuntimeModule.js +2 -2
- package/lib/prefetch/ChunkPrefetchPreloadPlugin.js +1 -1
- package/lib/prefetch/ChunkPrefetchStartupRuntimeModule.js +4 -4
- package/lib/prefetch/ChunkPrefetchTriggerRuntimeModule.js +4 -4
- package/lib/prefetch/ChunkPreloadTriggerRuntimeModule.js +4 -4
- package/lib/{dependencies → prefetch}/PrefetchDependency.js +1 -1
- package/lib/{PrefetchPlugin.js → prefetch/PrefetchPlugin.js} +2 -2
- package/lib/prefetch/ResourceHintPlugin.js +65 -44
- package/lib/prefetch/ResourceHintRuntimeModule.js +3 -3
- package/lib/prefetch/StartupAssetHintRuntimeModule.js +3 -3
- package/lib/prefetch/parseResourceHintOptions.js +4 -3
- package/lib/{ProvidePlugin.js → provide/ProvidePlugin.js} +7 -7
- package/lib/{dependencies → provide}/ProvidedDependency.js +14 -13
- package/lib/{IgnorePlugin.js → resolve/IgnorePlugin.js} +30 -13
- package/lib/{NormalModuleReplacementPlugin.js → resolve/NormalModuleReplacementPlugin.js} +4 -4
- package/lib/{ResolverFactory.js → resolve/ResolverFactory.js} +18 -5
- package/lib/resolve/getResolveOptionsKey.js +59 -0
- package/lib/rules/RuleSetCompiler.js +27 -46
- package/lib/runtime/AsyncModuleGeneratorRuntimeModule.js +2 -2
- package/lib/runtime/AsyncModuleRuntimeModule.js +7 -4
- package/lib/runtime/AutoPublicPathRuntimeModule.js +5 -5
- package/lib/runtime/BaseUriRuntimeModule.js +3 -3
- package/lib/runtime/ChunkNameRuntimeModule.js +2 -2
- package/lib/runtime/CompatGetDefaultExportRuntimeModule.js +2 -2
- package/lib/runtime/CompatRuntimeModule.js +4 -4
- package/lib/runtime/ConcatenationWrapRuntimeModule.js +2 -2
- package/lib/runtime/ConstructRequireRuntimeModule.js +2 -2
- package/lib/runtime/CreateFakeNamespaceObjectRuntimeModule.js +2 -2
- package/lib/runtime/CreateScriptRuntimeModule.js +2 -2
- package/lib/runtime/CreateScriptUrlRuntimeModule.js +2 -2
- package/lib/runtime/DefinePropertyGettersRuntimeModule.js +6 -6
- package/lib/runtime/EnsureChunkRuntimeModule.js +4 -4
- package/lib/runtime/GetChunkFilenameRuntimeModule.js +6 -6
- package/lib/runtime/GetFullHashRuntimeModule.js +2 -2
- package/lib/runtime/GetMainFilenameRuntimeModule.js +4 -4
- package/lib/runtime/GetTrustedTypesPolicyRuntimeModule.js +3 -3
- package/lib/runtime/GetWorkletBootstrapRuntimeModule.js +3 -3
- package/lib/runtime/GlobalRuntimeModule.js +3 -3
- package/lib/runtime/HasOwnPropertyRuntimeModule.js +3 -3
- package/lib/runtime/HelperRuntimeModule.js +16 -1
- package/lib/runtime/LoadScriptRuntimeModule.js +3 -3
- package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +80 -17
- package/lib/runtime/MakeNamespaceObjectRuntimeModule.js +2 -2
- package/lib/runtime/NonceRuntimeModule.js +2 -2
- package/lib/runtime/OnChunksLoadedRuntimeModule.js +4 -4
- package/lib/runtime/PublicPathRuntimeModule.js +2 -2
- package/lib/runtime/RelativeUrlRuntimeModule.js +2 -2
- package/lib/{RuntimeGlobals.js → runtime/RuntimeGlobals.js} +18 -1
- package/lib/runtime/RuntimeIdRuntimeModule.js +4 -4
- package/lib/{RuntimeModule.js → runtime/RuntimeModule.js} +36 -21
- package/lib/{RuntimePlugin.js → runtime/RuntimePlugin.js} +48 -50
- package/lib/runtime/SetAnonymousDefaultNameRuntimeModule.js +2 -2
- package/lib/runtime/SpecNamespaceObjectRuntimeModule.js +2 -2
- package/lib/runtime/StartupChunkDependenciesPlugin.js +2 -2
- package/lib/runtime/StartupChunkDependenciesRuntimeModule.js +5 -5
- package/lib/runtime/StartupEntrypointRuntimeModule.js +3 -3
- package/lib/runtime/SystemContextRuntimeModule.js +2 -2
- package/lib/runtime/ToBinaryRuntimeModule.js +3 -3
- package/lib/runtime/WorkerRuntimeModule.js +1 -1
- package/lib/runtime/baseUri.js +1 -1
- package/lib/schemes/DataUriPlugin.js +1 -1
- package/lib/schemes/HttpUriPlugin.js +67 -11
- package/lib/schemes/VirtualUrlPlugin.js +50 -16
- package/lib/serialization/AggregateErrorSerializer.js +2 -2
- package/lib/serialization/FileMiddleware.js +3 -3
- package/lib/serialization/ObjectMiddleware.js +47 -16
- package/lib/serialization/SerializerMiddleware.js +2 -2
- package/lib/serialization/SingleItemMiddleware.js +4 -2
- package/lib/sharing/ConsumeSharedFallbackDependency.js +9 -1
- package/lib/sharing/ConsumeSharedModule.js +18 -14
- package/lib/sharing/ConsumeSharedPlugin.js +148 -42
- package/lib/sharing/ConsumeSharedRuntimeModule.js +8 -8
- package/lib/sharing/ProvideForSharedDependency.js +9 -1
- package/lib/sharing/ProvideSharedDependency.js +1 -1
- package/lib/sharing/ProvideSharedModule.js +11 -9
- package/lib/sharing/ProvideSharedModuleFactory.js +2 -2
- package/lib/sharing/ProvideSharedPlugin.js +111 -20
- package/lib/sharing/SharePlugin.js +102 -9
- package/lib/sharing/ShareRuntimeModule.js +6 -6
- package/lib/sharing/resolveMatchedConfigs.js +1 -1
- package/lib/{util → sharing}/semver.js +14 -16
- package/lib/sharing/utils.js +59 -2
- package/lib/stats/DefaultStatsFactoryPlugin.js +22 -19
- package/lib/stats/DefaultStatsPresetPlugin.js +1 -1
- package/lib/stats/DefaultStatsPrinterPlugin.js +3 -3
- package/lib/{MultiStats.js → stats/MultiStats.js} +4 -4
- package/lib/{Stats.js → stats/Stats.js} +4 -4
- package/lib/stats/StatsFactory.js +14 -13
- package/lib/{ChunkTemplate.js → template/ChunkTemplate.js} +7 -7
- package/lib/{ConditionalInitFragment.js → template/ConditionalInitFragment.js} +3 -3
- package/lib/template/DependencyTemplate.js +77 -0
- package/lib/{DependencyTemplates.js → template/DependencyTemplates.js} +9 -4
- package/lib/template/InitFragment.js +223 -0
- package/lib/{MainTemplate.js → template/MainTemplate.js} +11 -11
- package/lib/{ModuleInfoHeaderPlugin.js → template/ModuleInfoHeaderPlugin.js} +30 -8
- package/lib/{ModuleTemplate.js → template/ModuleTemplate.js} +6 -6
- package/lib/{RuntimeTemplate.js → template/RuntimeTemplate.js} +145 -63
- package/lib/{Template.js → template/Template.js} +13 -11
- package/lib/{TemplatedPathPlugin.js → template/TemplatedPathPlugin.js} +19 -23
- package/lib/typescript/TypeScriptPlugin.js +3 -3
- package/lib/util/RequestShortener.js +44 -0
- package/lib/util/SortableSet.js +87 -22
- package/lib/util/SourceProcessor.js +349 -44
- package/lib/util/TupleSet.js +27 -27
- package/lib/util/WeakTupleMap.js +10 -12
- package/lib/util/buildDiagnostics.js +2 -2
- package/lib/util/comparators.js +10 -10
- package/lib/util/concatenate.js +28 -147
- package/lib/util/createMappings.js +111 -0
- package/lib/util/dataURL.js +94 -15
- package/lib/util/deprecation.js +1 -1
- package/lib/util/extractComments.js +118 -0
- package/lib/util/formatLocation.js +1 -1
- package/lib/util/globUtils.js +197 -16
- package/lib/util/haltVisitors.js +51 -0
- package/lib/util/handlerKeys.js +2 -2
- package/lib/util/identifier.js +117 -1
- package/lib/util/implicitTypeLoaderFallback.js +6 -4
- package/lib/util/internalSerializables.js +294 -102
- package/lib/util/magicComment.js +12 -7
- package/lib/util/makeSerializable.js +23 -4
- package/lib/util/parseJson.js +1 -1
- package/lib/util/preloadModuleType.js +5 -2
- package/lib/util/registerExternalSerializer.js +2 -2
- package/lib/util/removeBOM.js +1 -1
- package/lib/util/runtime.js +1 -1
- package/lib/util/serialization.js +4 -1
- package/lib/util/source.js +2 -2
- package/lib/util/terminalColors.js +161 -0
- package/lib/{wasm-async → wasm}/AsyncWasmCompileRuntimeModule.js +5 -5
- package/lib/{wasm-async → wasm}/AsyncWasmLoadingRuntimeModule.js +5 -5
- package/lib/{wasm-async → wasm}/AsyncWasmModule.js +9 -5
- package/lib/{wasm-async → wasm}/AsyncWebAssemblyGenerator.js +5 -5
- package/lib/{wasm-async → wasm}/AsyncWebAssemblyJavascriptGenerator.js +11 -10
- package/lib/{wasm-async → wasm}/AsyncWebAssemblyModulesPlugin.js +26 -10
- package/lib/{wasm-async → wasm}/AsyncWebAssemblyParser.js +8 -8
- package/lib/wasm/EnableWasmLoadingPlugin.js +1 -1
- package/lib/{wasm-async → wasm}/UniversalCompileAsyncWasmPlugin.js +9 -7
- package/lib/wasm/wasmModuleFilename.js +2 -2
- package/lib/wasm-sync/SyncWasmModule.js +3 -3
- package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +8 -8
- package/lib/wasm-sync/WasmFinalizeExportsPlugin.js +3 -3
- package/lib/wasm-sync/WebAssemblyGenerator.js +9 -8
- package/lib/wasm-sync/WebAssemblyJavascriptGenerator.js +14 -15
- package/lib/wasm-sync/WebAssemblyModulesPlugin.js +9 -7
- package/lib/wasm-sync/WebAssemblyParser.js +6 -6
- package/lib/wasm-sync/WebAssemblyUtils.js +6 -5
- package/lib/{MultiWatching.js → watch/MultiWatching.js} +3 -3
- package/lib/{WatchIgnorePlugin.js → watch/WatchIgnorePlugin.js} +43 -9
- package/lib/{Watching.js → watch/Watching.js} +8 -8
- package/lib/web/FetchCompileAsyncWasmPlugin.js +8 -6
- package/lib/web/FetchCompileWasmPlugin.js +6 -4
- package/lib/web/JsonpChunkLoadingPlugin.js +3 -3
- package/lib/web/JsonpChunkLoadingRuntimeModule.js +6 -6
- package/lib/web/JsonpTemplatePlugin.js +1 -1
- package/lib/webpack.js +27 -17
- package/lib/webworker/ImportScriptsChunkLoadingPlugin.js +3 -3
- package/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js +6 -6
- package/package.json +48 -41
- package/schemas/WebpackOptions.check.js +2 -1
- package/schemas/WebpackOptions.d.json.ts +2 -0
- package/schemas/WebpackOptions.json +294 -74
- package/schemas/plugins/BannerPlugin.check.js +2 -1
- package/schemas/plugins/BannerPlugin.json +29 -2
- package/schemas/plugins/HtmlGeneratorOptions.check.js +1 -0
- package/schemas/plugins/HtmlParserOptions.check.js +2 -1
- package/schemas/plugins/IgnorePlugin.check.js +1 -0
- package/schemas/plugins/IgnorePlugin.d.json.ts +2 -0
- package/schemas/plugins/IgnorePlugin.json +1 -1
- package/schemas/plugins/LoaderOptionsPlugin.check.js +1 -0
- package/schemas/plugins/ManifestPlugin.check.js +1 -0
- package/schemas/plugins/ManifestPlugin.json +3 -3
- package/schemas/plugins/ProgressPlugin.check.js +2 -1
- package/schemas/plugins/ProgressPlugin.json +2 -7
- package/schemas/plugins/SSRManifestPlugin.check.js +7 -0
- package/schemas/plugins/SSRManifestPlugin.json +20 -0
- package/schemas/plugins/SourceMapDevToolPlugin.check.js +2 -1
- package/schemas/plugins/SourceMapDevToolPlugin.json +44 -12
- package/schemas/plugins/WatchIgnorePlugin.check.js +2 -1
- package/schemas/plugins/WatchIgnorePlugin.json +12 -3
- package/schemas/plugins/asset/AssetGeneratorOptions.check.js +1 -0
- package/schemas/plugins/asset/AssetInlineGeneratorOptions.check.js +1 -0
- package/schemas/plugins/asset/AssetParserOptions.check.js +1 -0
- package/schemas/plugins/asset/AssetResourceGeneratorOptions.check.js +1 -0
- package/schemas/plugins/container/ContainerPlugin.check.js +2 -1
- package/schemas/plugins/container/ContainerPlugin.json +8 -0
- package/schemas/plugins/container/ContainerReferencePlugin.check.js +1 -0
- package/schemas/plugins/container/ExternalsType.check.js +1 -0
- package/schemas/plugins/container/ModuleFederationPlugin.check.js +2 -1
- package/schemas/plugins/container/ModuleFederationPlugin.json +40 -0
- package/schemas/plugins/css/CssAutoOrModuleParserOptions.check.js +1 -0
- package/schemas/plugins/css/CssGeneratorOptions.check.js +1 -0
- package/schemas/plugins/css/CssModuleGeneratorOptions.check.js +1 -0
- package/schemas/plugins/css/CssModuleParserOptions.check.js +1 -0
- package/schemas/plugins/css/CssParserOptions.check.js +1 -0
- package/schemas/plugins/debug/ProfilingPlugin.check.js +1 -0
- package/schemas/plugins/dll/DllPlugin.check.js +1 -0
- package/schemas/plugins/dll/DllReferencePlugin.check.js +2 -1
- package/schemas/plugins/dll/DllReferencePlugin.json +3 -18
- package/schemas/plugins/ids/HashedModuleIdsPlugin.check.js +1 -0
- package/schemas/plugins/ids/OccurrenceChunkIdsPlugin.check.js +1 -0
- package/schemas/plugins/ids/OccurrenceModuleIdsPlugin.check.js +1 -0
- package/schemas/plugins/json/JsonModulesPluginGenerator.check.js +1 -0
- package/schemas/plugins/json/JsonModulesPluginParser.check.js +1 -0
- package/schemas/plugins/optimize/AggressiveSplittingPlugin.check.js +1 -0
- package/schemas/plugins/optimize/LimitChunkCountPlugin.check.js +1 -0
- package/schemas/plugins/optimize/MergeDuplicateChunksPlugin.check.js +1 -0
- package/schemas/plugins/optimize/MinChunkSizePlugin.check.js +1 -0
- package/schemas/plugins/schemes/HttpUriPlugin.check.js +1 -0
- package/schemas/plugins/schemes/VirtualUrlPlugin.check.js +1 -0
- package/schemas/plugins/sharing/ConsumeSharedPlugin.check.js +2 -1
- package/schemas/plugins/sharing/ConsumeSharedPlugin.json +32 -0
- package/schemas/plugins/sharing/ProvideSharedPlugin.check.js +2 -1
- package/schemas/plugins/sharing/ProvideSharedPlugin.json +32 -0
- package/schemas/plugins/sharing/SharePlugin.check.js +2 -1
- package/schemas/plugins/sharing/SharePlugin.json +32 -0
- package/types.d.ts +19355 -13873
- package/lib/LazyBarrel.js +0 -388
- package/lib/dependencies/HarmonyAcceptImportDependency.js +0 -39
- package/lib/dependencies/HarmonyModulesPlugin.js +0 -192
- package/lib/javascript/ChunkFormatHelpers.js +0 -72
- package/lib/javascript/grammar.js +0 -5546
- package/lib/javascript/parser.js +0 -1500
- package/lib/javascript/regexpData.js +0 -51
- package/lib/performance/getSourceModules.js +0 -22
- package/lib/util/Semaphore.js +0 -65
- package/lib/util/objectToMap.js +0 -15
- package/schemas/WebpackOptions.check.d.ts +0 -7
- package/schemas/_container.json +0 -155
- package/schemas/_sharing.json +0 -118
- package/schemas/plugins/BannerPlugin.check.d.ts +0 -7
- package/schemas/plugins/HtmlGeneratorOptions.check.d.ts +0 -7
- package/schemas/plugins/HtmlParserOptions.check.d.ts +0 -7
- package/schemas/plugins/IgnorePlugin.check.d.ts +0 -7
- package/schemas/plugins/LoaderOptionsPlugin.check.d.ts +0 -7
- package/schemas/plugins/ManifestPlugin.check.d.ts +0 -7
- package/schemas/plugins/ProgressPlugin.check.d.ts +0 -7
- package/schemas/plugins/SourceMapDevToolPlugin.check.d.ts +0 -7
- package/schemas/plugins/WatchIgnorePlugin.check.d.ts +0 -7
- package/schemas/plugins/asset/AssetGeneratorOptions.check.d.ts +0 -7
- package/schemas/plugins/asset/AssetInlineGeneratorOptions.check.d.ts +0 -7
- package/schemas/plugins/asset/AssetParserOptions.check.d.ts +0 -7
- package/schemas/plugins/asset/AssetResourceGeneratorOptions.check.d.ts +0 -7
- package/schemas/plugins/container/ContainerPlugin.check.d.ts +0 -7
- package/schemas/plugins/container/ContainerReferencePlugin.check.d.ts +0 -7
- package/schemas/plugins/container/ExternalsType.check.d.ts +0 -7
- package/schemas/plugins/container/ModuleFederationPlugin.check.d.ts +0 -7
- package/schemas/plugins/css/CssAutoOrModuleParserOptions.check.d.ts +0 -7
- package/schemas/plugins/css/CssGeneratorOptions.check.d.ts +0 -7
- package/schemas/plugins/css/CssModuleGeneratorOptions.check.d.ts +0 -7
- package/schemas/plugins/css/CssModuleParserOptions.check.d.ts +0 -7
- package/schemas/plugins/css/CssParserOptions.check.d.ts +0 -7
- package/schemas/plugins/debug/ProfilingPlugin.check.d.ts +0 -7
- package/schemas/plugins/dll/DllPlugin.check.d.ts +0 -7
- package/schemas/plugins/dll/DllReferencePlugin.check.d.ts +0 -7
- package/schemas/plugins/ids/HashedModuleIdsPlugin.check.d.ts +0 -7
- package/schemas/plugins/ids/OccurrenceChunkIdsPlugin.check.d.ts +0 -7
- package/schemas/plugins/ids/OccurrenceModuleIdsPlugin.check.d.ts +0 -7
- package/schemas/plugins/json/JsonModulesPluginGenerator.check.d.ts +0 -7
- package/schemas/plugins/json/JsonModulesPluginParser.check.d.ts +0 -7
- package/schemas/plugins/optimize/AggressiveSplittingPlugin.check.d.ts +0 -7
- package/schemas/plugins/optimize/LimitChunkCountPlugin.check.d.ts +0 -7
- package/schemas/plugins/optimize/MergeDuplicateChunksPlugin.check.d.ts +0 -7
- package/schemas/plugins/optimize/MinChunkSizePlugin.check.d.ts +0 -7
- package/schemas/plugins/schemes/HttpUriPlugin.check.d.ts +0 -7
- package/schemas/plugins/schemes/VirtualUrlPlugin.check.d.ts +0 -7
- package/schemas/plugins/sharing/ConsumeSharedPlugin.check.d.ts +0 -7
- package/schemas/plugins/sharing/ProvideSharedPlugin.check.d.ts +0 -7
- package/schemas/plugins/sharing/SharePlugin.check.d.ts +0 -7
- /package/lib/{validateSchema.js → config/validateSchema.js} +0 -0
- /package/lib/{util → css}/conventions.js +0 -0
- /package/lib/{util → css}/topologicalSort.js +0 -0
- /package/lib/dependencies/{getFunctionExpression.js → helpers/getFunctionExpression.js} +0 -0
- /package/lib/{util → externals}/extractUrlAndGlobal.js +0 -0
- /package/lib/{util → fs}/StackedCacheMap.js +0 -0
- /package/lib/{util → javascript}/StackedMap.js +0 -0
- /package/lib/{ModuleProfile.js → module/ModuleProfile.js} +0 -0
- /package/lib/{ModuleSourceTypeConstants.js → module/ModuleSourceTypeConstants.js} +0 -0
- /package/lib/{ModuleTypeConstants.js → module/ModuleTypeConstants.js} +0 -0
- /package/lib/{OptimizationStages.js → optimize/OptimizationStages.js} +0 -0
- /package/lib/{util → optimize}/Queue.js +0 -0
- /package/lib/{util → stats}/smartGrouping.js +0 -0
|
@@ -5,12 +5,15 @@
|
|
|
5
5
|
|
|
6
6
|
"use strict";
|
|
7
7
|
|
|
8
|
+
// cspell:ignore defun, fnames, funarg
|
|
9
|
+
|
|
8
10
|
/**
|
|
9
11
|
* @import {
|
|
10
12
|
* Function as ESTreeFunction,
|
|
11
13
|
* Identifier,
|
|
12
14
|
* Node,
|
|
13
|
-
* Program
|
|
15
|
+
* Program,
|
|
16
|
+
* Property
|
|
14
17
|
* } from "estree"
|
|
15
18
|
*/
|
|
16
19
|
|
|
@@ -116,7 +119,7 @@ const CHILD_KEYS = {
|
|
|
116
119
|
class Scope {
|
|
117
120
|
/**
|
|
118
121
|
* @param {ScopeType} type what opened this scope
|
|
119
|
-
* @param {Node} block the node that opened this scope
|
|
122
|
+
* @param {Node} block the node that opened this scope, read but not kept
|
|
120
123
|
* @param {Scope | null} upper the enclosing scope
|
|
121
124
|
* @param {boolean} isVarScope whether `var` and function declarations hoist to here
|
|
122
125
|
* @param {boolean} recordEveryReference whether every binding collects its references, not only the ones webpack reads
|
|
@@ -124,8 +127,10 @@ class Scope {
|
|
|
124
127
|
constructor(type, block, upper, isVarScope, recordEveryReference) {
|
|
125
128
|
/** @type {ScopeType} */
|
|
126
129
|
this.type = type;
|
|
127
|
-
/** @type {
|
|
128
|
-
this.
|
|
130
|
+
/** @type {string} the type of the node that opened this scope */
|
|
131
|
+
this.blockType = block.type;
|
|
132
|
+
/** @type {number} where that node starts */
|
|
133
|
+
this.blockStart = /** @type {Node & Offset} */ (block).start;
|
|
129
134
|
/** @type {Scope | null} */
|
|
130
135
|
this.upper = upper;
|
|
131
136
|
/** @type {Scope[]} */
|
|
@@ -389,10 +394,26 @@ class ScopeAnalyzer {
|
|
|
389
394
|
this.pendingIdentifiers = [];
|
|
390
395
|
/** @type {Scope[]} the scope each pending identifier was seen in */
|
|
391
396
|
this.pendingScopes = [];
|
|
397
|
+
/** @type {Set<number>} where each shorthand property's identifier starts */
|
|
398
|
+
this.shorthandIdentifierStarts = new Set();
|
|
392
399
|
/** @type {boolean} */
|
|
393
400
|
this.recordEveryReference = recordEveryReference;
|
|
394
401
|
}
|
|
395
402
|
|
|
403
|
+
/**
|
|
404
|
+
* Records where a shorthand property's identifier starts, so renaming it
|
|
405
|
+
* later needs the offset rather than the tree it was read from.
|
|
406
|
+
* @param {Property} property a property whose `shorthand` is set
|
|
407
|
+
* @returns {void}
|
|
408
|
+
*/
|
|
409
|
+
_recordShorthandIdentifier(property) {
|
|
410
|
+
const value = property.value;
|
|
411
|
+
const identifier = value.type === "AssignmentPattern" ? value.left : value;
|
|
412
|
+
this.shorthandIdentifierStarts.add(
|
|
413
|
+
/** @type {Identifier & Offset} */ (identifier).start
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
|
|
396
417
|
/**
|
|
397
418
|
* @param {ScopeType} type scope kind
|
|
398
419
|
* @param {Node} block node opening the scope
|
|
@@ -512,6 +533,7 @@ class ScopeAnalyzer {
|
|
|
512
533
|
}
|
|
513
534
|
return;
|
|
514
535
|
case "Property":
|
|
536
|
+
if (node.shorthand) this._recordShorthandIdentifier(node);
|
|
515
537
|
if (node.computed) rightHandNodes.push(node.key);
|
|
516
538
|
this._patternWalk(node.value, mode, target, defaults, rightHandNodes);
|
|
517
539
|
return;
|
|
@@ -794,6 +816,11 @@ class ScopeAnalyzer {
|
|
|
794
816
|
return;
|
|
795
817
|
|
|
796
818
|
case "Property":
|
|
819
|
+
if (node.shorthand) this._recordShorthandIdentifier(node);
|
|
820
|
+
if (node.computed) this._visit(node.key);
|
|
821
|
+
this._visit(node.value);
|
|
822
|
+
return;
|
|
823
|
+
|
|
797
824
|
case "MethodDefinition":
|
|
798
825
|
if (node.computed) this._visit(node.key);
|
|
799
826
|
this._visit(node.value);
|
|
@@ -1068,6 +1095,7 @@ class ScopeAnalyzer {
|
|
|
1068
1095
|
* @property {Scope} globalScope the outermost scope
|
|
1069
1096
|
* @property {Scope} moduleScope the module body scope, where top-level declarations live
|
|
1070
1097
|
* @property {Reference[]} unresolvedReferences every identifier that resolved to no binding — the module's free names
|
|
1098
|
+
* @property {Set<number>} shorthandIdentifierStarts where each shorthand property's identifier starts, so a rename can write `name: newName` without the tree
|
|
1071
1099
|
*/
|
|
1072
1100
|
|
|
1073
1101
|
/**
|
|
@@ -1084,11 +1112,3818 @@ const analyzeScope = (ast, recordEveryReference = false) => {
|
|
|
1084
1112
|
const moduleScope = analyzer._push("module", ast, true);
|
|
1085
1113
|
analyzer._visitAll(ast.body);
|
|
1086
1114
|
const unresolvedReferences = analyzer._resolve();
|
|
1087
|
-
return {
|
|
1115
|
+
return {
|
|
1116
|
+
globalScope,
|
|
1117
|
+
moduleScope,
|
|
1118
|
+
unresolvedReferences,
|
|
1119
|
+
shorthandIdentifierStarts: analyzer.shorthandIdentifierStarts
|
|
1120
|
+
};
|
|
1121
|
+
};
|
|
1122
|
+
|
|
1123
|
+
/**
|
|
1124
|
+
* @typedef {import("./syntax-printer").PrintNode} PrintNode
|
|
1125
|
+
* @typedef {import("./syntax-printer").PrintProgram} PrintProgram
|
|
1126
|
+
* @typedef {import("./syntax-printer").PrintIdentifier} PrintIdentifier
|
|
1127
|
+
* @typedef {import("./syntax-printer").PrintLiteral} PrintLiteral
|
|
1128
|
+
* @typedef {import("./syntax-printer").PrintFunction} PrintFunction
|
|
1129
|
+
* @typedef {import("./syntax-printer").PrintClass} PrintClass
|
|
1130
|
+
* @typedef {import("./syntax-printer").PrintProperty} PrintProperty
|
|
1131
|
+
* @typedef {import("./syntax-printer").PrintObject} PrintObject
|
|
1132
|
+
* @typedef {import("./syntax-printer").PrintArray} PrintArray
|
|
1133
|
+
* @typedef {import("./syntax-printer").PrintCallExpression} PrintCallExpression
|
|
1134
|
+
* @typedef {import("./syntax-printer").PrintNewExpression} PrintNewExpression
|
|
1135
|
+
* @typedef {import("./syntax-printer").PrintForStatement} PrintForStatement
|
|
1136
|
+
* @typedef {import("./syntax-printer").PrintForInStatement} PrintForInStatement
|
|
1137
|
+
* @typedef {import("./syntax-printer").PrintForOfStatement} PrintForOfStatement
|
|
1138
|
+
* @typedef {import("./syntax-printer").PrintWhileStatement} PrintWhileStatement
|
|
1139
|
+
* @typedef {import("./syntax-printer").PrintVariableDeclaration} PrintVariableDeclaration
|
|
1140
|
+
* @typedef {import("./syntax-printer").PrintVariableDeclarator} PrintVariableDeclarator
|
|
1141
|
+
* @typedef {import("./syntax-printer").PrintExport} PrintExport
|
|
1142
|
+
* @typedef {import("./syntax-printer").Token} Token
|
|
1143
|
+
* @typedef {NonNullable<PrintProgram["tokenTables"]>} TokenTables
|
|
1144
|
+
* @typedef {import("./syntax-printer").Node} CompressorNode
|
|
1145
|
+
* @typedef {import("./syntax-printer").Scope} CompressorScopeShape
|
|
1146
|
+
* @typedef {import("./syntax-printer").Definition} CompressorDefinition
|
|
1147
|
+
*/
|
|
1148
|
+
|
|
1149
|
+
// How a minifier definition's name was declared, one code per kind of
|
|
1150
|
+
// terser's declaring symbol; a global is a name nothing declares.
|
|
1151
|
+
const DECLARES_VAR = 1;
|
|
1152
|
+
const DECLARES_FUNARG = 2;
|
|
1153
|
+
const DECLARES_LET = 3;
|
|
1154
|
+
const DECLARES_CONST = 4;
|
|
1155
|
+
const DECLARES_USING = 5;
|
|
1156
|
+
const DECLARES_CATCH = 6;
|
|
1157
|
+
const DECLARES_IMPORT = 7;
|
|
1158
|
+
|
|
1159
|
+
// What a name one long saves taking the name spelled beside it: a key's `:`
|
|
1160
|
+
// and the name, or an import's or export's ` as ` and the name.
|
|
1161
|
+
const SHORTHAND_SAVING = 2;
|
|
1162
|
+
const AS_SAVING = 5;
|
|
1163
|
+
// `spelledNames` collecting the names a key spells too, not only a module's.
|
|
1164
|
+
const SPELLED_KEYS = 2;
|
|
1165
|
+
// A name the mangler may hand out as it is spelled: one ASCII identifier, so it
|
|
1166
|
+
// prints bare and costs a byte a character.
|
|
1167
|
+
const SPELLABLE_NAME = /^[A-Za-z_$][\w$]*$/;
|
|
1168
|
+
// Names no binding may take in strict code, a module's, beyond the keywords.
|
|
1169
|
+
const NAMES_NO_BINDING_TAKES = new Set([
|
|
1170
|
+
"arguments",
|
|
1171
|
+
"await",
|
|
1172
|
+
"enum",
|
|
1173
|
+
"eval",
|
|
1174
|
+
"implements",
|
|
1175
|
+
"interface",
|
|
1176
|
+
"let",
|
|
1177
|
+
"package",
|
|
1178
|
+
"private",
|
|
1179
|
+
"protected",
|
|
1180
|
+
"public",
|
|
1181
|
+
"static",
|
|
1182
|
+
"yield"
|
|
1183
|
+
]);
|
|
1184
|
+
const DECLARES_DEFUN = 8;
|
|
1185
|
+
const DECLARES_LAMBDA = 9;
|
|
1186
|
+
const DECLARES_CLASS = 10;
|
|
1187
|
+
const DECLARES_DEF_CLASS = 11;
|
|
1188
|
+
const DECLARES_GLOBAL = 12;
|
|
1189
|
+
|
|
1190
|
+
// The declarations a `var` or a parameter may not join, as `declarations` bits.
|
|
1191
|
+
const LEXICAL_DECLARATIONS =
|
|
1192
|
+
(1 << DECLARES_LET) | (1 << DECLARES_CONST) | (1 << DECLARES_USING);
|
|
1193
|
+
|
|
1194
|
+
// What the minifier's analysis records of a name read, replayed once all is
|
|
1195
|
+
// declared.
|
|
1196
|
+
const REFERENCE_CALLED = 1;
|
|
1197
|
+
const REFERENCE_EXPORTED = 1 << 1;
|
|
1198
|
+
const REFERENCE_FROM_MODULE = 1 << 2;
|
|
1199
|
+
const REFERENCE_CATCH = 1 << 3;
|
|
1200
|
+
|
|
1201
|
+
// How an `export` naming a definition keeps its name.
|
|
1202
|
+
const EXPORT_KEEP_NAME = 1;
|
|
1203
|
+
const EXPORT_WANT_MANGLE = 2;
|
|
1204
|
+
|
|
1205
|
+
// Past this many definitions a scope's `enclosed` is also held as a set, so
|
|
1206
|
+
// adding one stops scanning the list: a bundle's toplevel reaches thousands.
|
|
1207
|
+
const ENCLOSED_INDEX_THRESHOLD = 16;
|
|
1208
|
+
/** @type {WeakMap<MinifierVariable[], Set<MinifierVariable>>} */
|
|
1209
|
+
const enclosedIndexes = new WeakMap();
|
|
1210
|
+
|
|
1211
|
+
/**
|
|
1212
|
+
* Adds a definition to a scope's `enclosed` unless it is there. The list is
|
|
1213
|
+
* the record, since a cloned scope copies it; the set only answers membership.
|
|
1214
|
+
* @param {MinifierScope} scope a scope
|
|
1215
|
+
* @param {MinifierVariable} definition a definition it reaches
|
|
1216
|
+
* @returns {void}
|
|
1217
|
+
*/
|
|
1218
|
+
const encloseUnique = (scope, definition) => {
|
|
1219
|
+
const { enclosed } = scope;
|
|
1220
|
+
if (enclosed.length < ENCLOSED_INDEX_THRESHOLD) {
|
|
1221
|
+
if (!enclosed.includes(definition)) enclosed.push(definition);
|
|
1222
|
+
return;
|
|
1223
|
+
}
|
|
1224
|
+
let index = enclosedIndexes.get(enclosed);
|
|
1225
|
+
if (index === undefined || index.size !== enclosed.length) {
|
|
1226
|
+
index = new Set(enclosed);
|
|
1227
|
+
enclosedIndexes.set(enclosed, index);
|
|
1228
|
+
}
|
|
1229
|
+
if (index.has(definition)) return;
|
|
1230
|
+
index.add(definition);
|
|
1231
|
+
enclosed.push(definition);
|
|
1232
|
+
};
|
|
1233
|
+
|
|
1234
|
+
/**
|
|
1235
|
+
* A scope as the minifier reads it: terser's, which opens one for every block
|
|
1236
|
+
* and loop, besides what it names in.
|
|
1237
|
+
*/
|
|
1238
|
+
class MinifierScope extends Scope {
|
|
1239
|
+
/**
|
|
1240
|
+
* @param {ScopeType} type what opened this scope
|
|
1241
|
+
* @param {PrintNode} node the node opening it
|
|
1242
|
+
* @param {MinifierScope | null} upper the enclosing scope
|
|
1243
|
+
* @param {boolean} isVarScope whether `var` and function declarations hoist to here
|
|
1244
|
+
*/
|
|
1245
|
+
constructor(type, node, upper, isVarScope) {
|
|
1246
|
+
super(type, /** @type {Node} */ (node), upper, isVarScope, false);
|
|
1247
|
+
/** @type {PrintNode} */
|
|
1248
|
+
this.node = node;
|
|
1249
|
+
/** @type {MinifierVariable[]} the definitions it or a scope inside it reads, in the order first read */
|
|
1250
|
+
this.enclosed = [];
|
|
1251
|
+
/** @type {number} how many names it has handed out, less one */
|
|
1252
|
+
this.cname = -1;
|
|
1253
|
+
/** @type {boolean} whether a direct `eval` can reach its names */
|
|
1254
|
+
this.usesEval = false;
|
|
1255
|
+
/** @type {boolean} whether a `with` can reach its names */
|
|
1256
|
+
this.usesWith = false;
|
|
1257
|
+
/** @type {MinifierVariable | null} a function expression's own name */
|
|
1258
|
+
this.functionName = null;
|
|
1259
|
+
/** @type {number} the first name its parameter list reads, as the analysis counts them, or -1 */
|
|
1260
|
+
this.parameterStart = -1;
|
|
1261
|
+
/** @type {number} the name after the last its parameter list reads, or -1 */
|
|
1262
|
+
this.parameterEnd = -1;
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
/**
|
|
1266
|
+
* terser's `is_block_scope`.
|
|
1267
|
+
* @returns {boolean} whether a block or a loop opens it
|
|
1268
|
+
*/
|
|
1269
|
+
isBlockScope() {
|
|
1270
|
+
return this.variableScope !== this;
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
/**
|
|
1274
|
+
* terser's `get_defun_scope`.
|
|
1275
|
+
* @returns {MinifierScope} the nearest scope around it, or it, that is not a block's
|
|
1276
|
+
*/
|
|
1277
|
+
getDefunScope() {
|
|
1278
|
+
return /** @type {MinifierScope} */ (this.variableScope);
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
/**
|
|
1282
|
+
* terser's `pinned`.
|
|
1283
|
+
* @returns {boolean} whether `eval` or `with` can reach its names
|
|
1284
|
+
*/
|
|
1285
|
+
isPinned() {
|
|
1286
|
+
return this.usesEval || this.usesWith;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
/**
|
|
1290
|
+
* terser's `find_variable`.
|
|
1291
|
+
* @param {string} name a name
|
|
1292
|
+
* @returns {MinifierVariable | undefined} what it resolves to from here
|
|
1293
|
+
*/
|
|
1294
|
+
findVariable(name) {
|
|
1295
|
+
return findMinifierVariable(this, name);
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
/**
|
|
1299
|
+
* terser's `conflicting_def_shallow`.
|
|
1300
|
+
* @param {string} name a name
|
|
1301
|
+
* @returns {boolean} whether it is declared here or names a definition read here
|
|
1302
|
+
*/
|
|
1303
|
+
conflictingDefinitionShallow(name) {
|
|
1304
|
+
const { enclosed } = this;
|
|
1305
|
+
for (let i = 0; i < enclosed.length; i++) {
|
|
1306
|
+
if (enclosed[i].name === name) return true;
|
|
1307
|
+
}
|
|
1308
|
+
return this.getBinding(name) !== undefined;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
/**
|
|
1312
|
+
* terser's `conflicting_def`.
|
|
1313
|
+
* @param {string} name a name
|
|
1314
|
+
* @returns {boolean} whether it is taken here or further out
|
|
1315
|
+
*/
|
|
1316
|
+
conflictingDefinition(name) {
|
|
1317
|
+
for (
|
|
1318
|
+
let scope = /** @type {MinifierScope | null} */ (this);
|
|
1319
|
+
scope !== null;
|
|
1320
|
+
scope = /** @type {MinifierScope | null} */ (scope.upper)
|
|
1321
|
+
) {
|
|
1322
|
+
if (scope.conflictingDefinitionShallow(name)) return true;
|
|
1323
|
+
}
|
|
1324
|
+
return false;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
/**
|
|
1328
|
+
* terser's `mark_enclosed`: records that each scope from this one out to a
|
|
1329
|
+
* definition's reads it.
|
|
1330
|
+
* @param {MinifierVariable} variable the definition
|
|
1331
|
+
* @returns {void}
|
|
1332
|
+
*/
|
|
1333
|
+
markEnclosed(variable) {
|
|
1334
|
+
encloseVariable(this, variable);
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
|
|
1338
|
+
/**
|
|
1339
|
+
* One name declared in one scope, or a global: terser's `SymbolDef`, less
|
|
1340
|
+
* what only the compressor reads.
|
|
1341
|
+
*/
|
|
1342
|
+
class MinifierVariable extends Variable {
|
|
1343
|
+
/**
|
|
1344
|
+
* @param {string} name the declared name
|
|
1345
|
+
* @param {MinifierScope} scope the declaring scope, the toplevel for a global
|
|
1346
|
+
* @param {number} kind how it was first declared, as a `DECLARES_*` code
|
|
1347
|
+
*/
|
|
1348
|
+
constructor(name, scope, kind) {
|
|
1349
|
+
super(name, scope);
|
|
1350
|
+
/** @type {number} how it was first declared, as a `DECLARES_*` code */
|
|
1351
|
+
this.kind = kind;
|
|
1352
|
+
/** @type {number} every way it was declared, one bit per `DECLARES_*` code */
|
|
1353
|
+
this.declarations = 1 << kind;
|
|
1354
|
+
/** @type {boolean} whether the toplevel declares it */
|
|
1355
|
+
this.global = false;
|
|
1356
|
+
/** @type {boolean} whether nothing declares it */
|
|
1357
|
+
this.undeclared = false;
|
|
1358
|
+
/** @type {number} how an `export` naming it keeps its name, as `EXPORT_*` */
|
|
1359
|
+
this.export = 0;
|
|
1360
|
+
/** @type {string | null} the name mangling gives it */
|
|
1361
|
+
// eslint-disable-next-line camelcase -- terser's name, which the printer reads
|
|
1362
|
+
this.mangled_name = null;
|
|
1363
|
+
/** @type {number} how many names read or write it, which the mangler gives the short names by */
|
|
1364
|
+
this.referenceCount = 0;
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
/**
|
|
1369
|
+
* Whether a definition is a variable rather than a label or a compressor's own definition.
|
|
1370
|
+
* @param {unknown} value a definition
|
|
1371
|
+
* @returns {value is MinifierVariable} true when the value is a variable
|
|
1372
|
+
*/
|
|
1373
|
+
const isMinifierVariable = (value) => value instanceof MinifierVariable;
|
|
1374
|
+
|
|
1375
|
+
/** A label: a statement's, its `break`s and `continue`s naming it too. */
|
|
1376
|
+
class MinifierLabel {
|
|
1377
|
+
/**
|
|
1378
|
+
* @param {string} name the name
|
|
1379
|
+
* @param {MinifierLabel | null} parent the label of the nearest labeled statement around, across functions
|
|
1380
|
+
*/
|
|
1381
|
+
constructor(name, parent) {
|
|
1382
|
+
/** @type {string} */
|
|
1383
|
+
this.name = name;
|
|
1384
|
+
/** @type {string | null} the name mangling gives it */
|
|
1385
|
+
// eslint-disable-next-line camelcase -- terser's name, which the printer reads
|
|
1386
|
+
this.mangled_name = null;
|
|
1387
|
+
/** @type {MinifierLabel | null} */
|
|
1388
|
+
this.parent = parent;
|
|
1389
|
+
/** @type {number} where the mangler's label names stood when it named this one */
|
|
1390
|
+
this.counter = -1;
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
/**
|
|
1395
|
+
* A scope as the compressor reads it: the minifier's, and what terser's
|
|
1396
|
+
* compressor records of it besides. The node opening it holds it as its
|
|
1397
|
+
* `block_scope`, a function's or the program's as a block's does.
|
|
1398
|
+
*/
|
|
1399
|
+
class CompressorScope extends MinifierScope {
|
|
1400
|
+
/**
|
|
1401
|
+
* @param {ScopeType} type what opened this scope
|
|
1402
|
+
* @param {CompressorNode} node the node opening it
|
|
1403
|
+
* @param {CompressorScopeShape | null} upper the enclosing scope
|
|
1404
|
+
* @param {boolean} isVarScope whether `var` and function declarations hoist to here
|
|
1405
|
+
*/
|
|
1406
|
+
constructor(type, node, upper, isVarScope) {
|
|
1407
|
+
// Made with no parent, so the parent lists no child: the compressor never
|
|
1408
|
+
// reads `childScopes`, and its tree moves, copies and drops scopes.
|
|
1409
|
+
super(
|
|
1410
|
+
type,
|
|
1411
|
+
/** @type {PrintNode} */ (/** @type {unknown} */ (node)),
|
|
1412
|
+
null,
|
|
1413
|
+
true
|
|
1414
|
+
);
|
|
1415
|
+
this.upper = /** @type {Scope | null} */ (/** @type {unknown} */ (upper));
|
|
1416
|
+
if (!isVarScope) {
|
|
1417
|
+
this.variableScope = /** @type {Scope} */ (this.upper).variableScope;
|
|
1418
|
+
}
|
|
1419
|
+
/** @type {boolean} whether a function reads its own `arguments` */
|
|
1420
|
+
this.usesArguments = false;
|
|
1421
|
+
/** @type {import("./syntax-printer").UnusedScanLog | null} what `drop_unused` found scanning the function, for the scopes around it */
|
|
1422
|
+
this.unusedScan = null;
|
|
1423
|
+
/** @type {number} where the symbols under this scope's node start in the reduce phase's symbol order */
|
|
1424
|
+
this.hoistStart = 0;
|
|
1425
|
+
/** @type {number} where they end, exclusive */
|
|
1426
|
+
this.hoistEnd = 0;
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
/**
|
|
1430
|
+
* The scope of a node made of this scope's node: as terser's node was a
|
|
1431
|
+
* scope, it is a scope of its own, holding and reading the same definitions.
|
|
1432
|
+
* @param {CompressorNode} node the node made of this scope's
|
|
1433
|
+
* @returns {CompressorScopeShape} the scope
|
|
1434
|
+
*/
|
|
1435
|
+
share(node) {
|
|
1436
|
+
const shared = new CompressorScope(
|
|
1437
|
+
this.type,
|
|
1438
|
+
node,
|
|
1439
|
+
/** @type {CompressorScopeShape | null} */ (
|
|
1440
|
+
/** @type {unknown} */ (this.upper)
|
|
1441
|
+
),
|
|
1442
|
+
this.variableScope === this
|
|
1443
|
+
);
|
|
1444
|
+
shared.variables = this.variables;
|
|
1445
|
+
shared._index = this._index;
|
|
1446
|
+
shared.enclosed = this.enclosed;
|
|
1447
|
+
shared.usesEval = this.usesEval;
|
|
1448
|
+
shared.usesWith = this.usesWith;
|
|
1449
|
+
shared.usesArguments = this.usesArguments;
|
|
1450
|
+
return /** @type {CompressorScopeShape} */ (
|
|
1451
|
+
/** @type {unknown} */ (shared)
|
|
1452
|
+
);
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
/**
|
|
1456
|
+
* Takes copies of what this scope shares with the scope it was made of, as
|
|
1457
|
+
* terser's `clone` of a scope does.
|
|
1458
|
+
* @returns {void}
|
|
1459
|
+
*/
|
|
1460
|
+
detach() {
|
|
1461
|
+
if (this.variables !== NO_VARIABLE_LIST) {
|
|
1462
|
+
this.variables = [...this.variables];
|
|
1463
|
+
}
|
|
1464
|
+
if (this._index !== undefined) this._index = new Map(this._index);
|
|
1465
|
+
this.enclosed = [...this.enclosed];
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
/**
|
|
1469
|
+
* A copy of this scope for a copy of its node.
|
|
1470
|
+
* @param {CompressorNode} node the copy of its node
|
|
1471
|
+
* @returns {CompressorScopeShape} the copy
|
|
1472
|
+
*/
|
|
1473
|
+
copyFor(node) {
|
|
1474
|
+
const copy = this.share(node);
|
|
1475
|
+
copy.detach();
|
|
1476
|
+
return copy;
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
/**
|
|
1480
|
+
* Adds a definition this scope declares under its name.
|
|
1481
|
+
* @param {CompressorDefinition} variable the definition
|
|
1482
|
+
* @returns {void}
|
|
1483
|
+
*/
|
|
1484
|
+
bind(variable) {
|
|
1485
|
+
addBinding(
|
|
1486
|
+
this,
|
|
1487
|
+
/** @type {Variable} */ (/** @type {unknown} */ (variable))
|
|
1488
|
+
);
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
/**
|
|
1492
|
+
* terser's `def_variable`: declares a symbol's name here.
|
|
1493
|
+
* @param {CompressorNode} symbol the declaring symbol
|
|
1494
|
+
* @param {CompressorNode | null | undefined} init what it is initialized to
|
|
1495
|
+
* @param {(node: CompressorNode) => boolean} isFunction whether a node is a function expression
|
|
1496
|
+
* @returns {CompressorDefinition} its definition, made or joined
|
|
1497
|
+
*/
|
|
1498
|
+
defineVariable(symbol, init, isFunction) {
|
|
1499
|
+
const name = /** @type {string} */ (symbol.name);
|
|
1500
|
+
let variable = /** @type {CompressorDefinition | undefined} */ (
|
|
1501
|
+
/** @type {unknown} */ (this.getBinding(name))
|
|
1502
|
+
);
|
|
1503
|
+
if (variable !== undefined) {
|
|
1504
|
+
variable.identifiers.push(symbol);
|
|
1505
|
+
if (
|
|
1506
|
+
variable.init &&
|
|
1507
|
+
(variable.scope !== /** @type {unknown} */ (symbol.scope) ||
|
|
1508
|
+
isFunction(variable.init))
|
|
1509
|
+
) {
|
|
1510
|
+
variable.init = init;
|
|
1511
|
+
}
|
|
1512
|
+
} else {
|
|
1513
|
+
variable = createCompressorDefinition(
|
|
1514
|
+
name,
|
|
1515
|
+
/** @type {CompressorScopeShape} */ (/** @type {unknown} */ (this)),
|
|
1516
|
+
0,
|
|
1517
|
+
symbol,
|
|
1518
|
+
init
|
|
1519
|
+
);
|
|
1520
|
+
this.bind(variable);
|
|
1521
|
+
variable.global = this.upper === null;
|
|
1522
|
+
}
|
|
1523
|
+
return (symbol.definition = variable);
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
/**
|
|
1527
|
+
* terser's `add_child_scope`: moves a function's or class's scope into this
|
|
1528
|
+
* one, which with each scope around it reads what the moved one reads from
|
|
1529
|
+
* them. Nothing lists a compressor scope's children, so nothing else moves.
|
|
1530
|
+
* @param {CompressorScopeShape} child the scope moved in
|
|
1531
|
+
* @param {(() => boolean) | null} readsArguments for an arrow, whether it reads the `arguments` of the function it moves into
|
|
1532
|
+
* @returns {void}
|
|
1533
|
+
*/
|
|
1534
|
+
adopt(child, readsArguments) {
|
|
1535
|
+
const self = /** @type {CompressorScopeShape} */ (
|
|
1536
|
+
/** @type {unknown} */ (this)
|
|
1537
|
+
);
|
|
1538
|
+
if (child.upper === self) return;
|
|
1539
|
+
child.upper = self;
|
|
1540
|
+
if (
|
|
1541
|
+
readsArguments !== null &&
|
|
1542
|
+
this.type === "function" &&
|
|
1543
|
+
!this.usesArguments
|
|
1544
|
+
) {
|
|
1545
|
+
this.usesArguments = readsArguments();
|
|
1546
|
+
}
|
|
1547
|
+
this.usesWith = this.usesWith || child.usesWith;
|
|
1548
|
+
this.usesEval = this.usesEval || child.usesEval;
|
|
1549
|
+
/** @type {CompressorScopeShape[]} */
|
|
1550
|
+
const ancestry = [];
|
|
1551
|
+
for (
|
|
1552
|
+
let current = /** @type {CompressorScopeShape | null} */ (self);
|
|
1553
|
+
current !== null;
|
|
1554
|
+
current = current.upper
|
|
1555
|
+
) {
|
|
1556
|
+
ancestry.push(current);
|
|
1557
|
+
}
|
|
1558
|
+
ancestry.reverse();
|
|
1559
|
+
const enclosedByChild = new Set(child.enclosed);
|
|
1560
|
+
/** @type {CompressorDefinition[]} */
|
|
1561
|
+
const toEnclose = [];
|
|
1562
|
+
for (const ancestor of ancestry) {
|
|
1563
|
+
const scope = /** @type {MinifierScope} */ (
|
|
1564
|
+
/** @type {unknown} */ (ancestor)
|
|
1565
|
+
);
|
|
1566
|
+
for (const definition of toEnclose) {
|
|
1567
|
+
encloseUnique(
|
|
1568
|
+
scope,
|
|
1569
|
+
/** @type {MinifierVariable} */ (/** @type {unknown} */ (definition))
|
|
1570
|
+
);
|
|
1571
|
+
}
|
|
1572
|
+
const { variables } = ancestor;
|
|
1573
|
+
// Where the moved scope encloses fewer names than this one declares,
|
|
1574
|
+
// they are looked up here, and the variables read in order only to
|
|
1575
|
+
// order two or more of them.
|
|
1576
|
+
let left = variables.length;
|
|
1577
|
+
/** @type {CompressorDefinition | undefined} */
|
|
1578
|
+
let declared;
|
|
1579
|
+
if (left > enclosedByChild.size) {
|
|
1580
|
+
left = 0;
|
|
1581
|
+
for (const definition of enclosedByChild) {
|
|
1582
|
+
if (ancestor.getBinding(definition.name) !== definition) continue;
|
|
1583
|
+
declared = definition;
|
|
1584
|
+
left++;
|
|
1585
|
+
}
|
|
1586
|
+
if (left === 0) continue;
|
|
1587
|
+
if (left === 1) {
|
|
1588
|
+
const only = /** @type {CompressorDefinition} */ (declared);
|
|
1589
|
+
if (!toEnclose.includes(only)) toEnclose.push(only);
|
|
1590
|
+
encloseUnique(
|
|
1591
|
+
scope,
|
|
1592
|
+
/** @type {MinifierVariable} */ (/** @type {unknown} */ (only))
|
|
1593
|
+
);
|
|
1594
|
+
continue;
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
for (let i = 0; i < variables.length; i++) {
|
|
1598
|
+
const definition = variables[i];
|
|
1599
|
+
if (enclosedByChild.has(definition)) {
|
|
1600
|
+
if (!toEnclose.includes(definition)) toEnclose.push(definition);
|
|
1601
|
+
encloseUnique(
|
|
1602
|
+
scope,
|
|
1603
|
+
/** @type {MinifierVariable} */ (
|
|
1604
|
+
/** @type {unknown} */ (definition)
|
|
1605
|
+
)
|
|
1606
|
+
);
|
|
1607
|
+
if (--left === 0) break;
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
/**
|
|
1614
|
+
* terser's `add_reference`: a symbol in this scope reads its definition.
|
|
1615
|
+
* @param {CompressorNode} symbol the symbol
|
|
1616
|
+
* @returns {void}
|
|
1617
|
+
*/
|
|
1618
|
+
addReference(symbol) {
|
|
1619
|
+
const variable = symbol.definition;
|
|
1620
|
+
variable.references.push(symbol);
|
|
1621
|
+
encloseVariable(
|
|
1622
|
+
this,
|
|
1623
|
+
/** @type {MinifierVariable} */ (/** @type {unknown} */ (variable))
|
|
1624
|
+
);
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
let nextCompressorVariableId = 1;
|
|
1629
|
+
|
|
1630
|
+
/**
|
|
1631
|
+
* One name declared in one scope, or a global: terser's `SymbolDef`, its
|
|
1632
|
+
* `orig` the base's `identifiers`, with what the compressor records of it.
|
|
1633
|
+
*/
|
|
1634
|
+
class CompressorVariable extends MinifierVariable {
|
|
1635
|
+
/**
|
|
1636
|
+
* @param {string} name the declared name
|
|
1637
|
+
* @param {CompressorScopeShape | null} scope the declaring scope, the toplevel for a global
|
|
1638
|
+
* @param {number} kind how it was first declared, as a `DECLARES_*` code, 0 where the compressor declares it
|
|
1639
|
+
* @param {CompressorNode | { name: string }} orig its first declaring symbol
|
|
1640
|
+
* @param {CompressorNode | null | undefined} init what it is initialized to
|
|
1641
|
+
*/
|
|
1642
|
+
constructor(name, scope, kind, orig, init) {
|
|
1643
|
+
super(
|
|
1644
|
+
name,
|
|
1645
|
+
/** @type {MinifierScope} */ (/** @type {unknown} */ (scope)),
|
|
1646
|
+
kind
|
|
1647
|
+
);
|
|
1648
|
+
this.identifiers = [
|
|
1649
|
+
/** @type {Identifier} */ (/** @type {unknown} */ (orig))
|
|
1650
|
+
];
|
|
1651
|
+
/** @type {CompressorNode | null | undefined} what it is initialized to */
|
|
1652
|
+
this.init = init;
|
|
1653
|
+
/** @type {number} a number no other definition has, in the order made */
|
|
1654
|
+
this.id = nextCompressorVariableId++;
|
|
1655
|
+
/* eslint-disable camelcase -- terser's names, which the compressor reads */
|
|
1656
|
+
/** @type {number} how many of its declarations were dropped */
|
|
1657
|
+
this.eliminated = 0;
|
|
1658
|
+
/** @type {number} how many times it is assigned */
|
|
1659
|
+
this.assignments = 0;
|
|
1660
|
+
/** @type {number} how many times a destructuring pattern or a loop head names it, each a write `assignments` misses */
|
|
1661
|
+
this.patternWrites = 0;
|
|
1662
|
+
/** @type {number} how many of its reads were replaced by its value */
|
|
1663
|
+
this.replaced = 0;
|
|
1664
|
+
/** @type {boolean} whether it is assigned in a chain */
|
|
1665
|
+
this.chained = false;
|
|
1666
|
+
/** @type {boolean} whether its value is read where it may be changed */
|
|
1667
|
+
this.direct_access = false;
|
|
1668
|
+
/** @type {number} how many properties are read off it before its value escapes, 0 where it does not */
|
|
1669
|
+
this.escaped = 0;
|
|
1670
|
+
/** @type {boolean} whether its value itself escapes, not only a property read off it */
|
|
1671
|
+
this.leaked = false;
|
|
1672
|
+
/** @type {number} how many of its reads are its own function's calls of itself */
|
|
1673
|
+
this.recursive_refs = 0;
|
|
1674
|
+
/** @type {boolean | string | undefined} whether it is read once, "m" where that read may change it */
|
|
1675
|
+
this.single_use = false;
|
|
1676
|
+
/** @type {CompressorNode | (() => CompressorNode) | false | null | undefined} its value, as `reduce_vars` worked it out, false where unknown */
|
|
1677
|
+
this.fixed = false;
|
|
1678
|
+
/* eslint-enable camelcase */
|
|
1679
|
+
/** @type {Reference[]} the symbols reading it, which `SymbolDefinition` types as nodes */
|
|
1680
|
+
this.references = [];
|
|
1681
|
+
/** @type {number} the last `drop_unused` run to find it in use, 0 for none */
|
|
1682
|
+
this.inUseRun = 0;
|
|
1683
|
+
/** @type {CompressorNode | undefined} the name a copy of it was set from, kept where a write through the copy dropped `fixed` */
|
|
1684
|
+
this.copyOf = undefined;
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
/**
|
|
1689
|
+
* A definition the compressor reads, typed as it reads the shared model.
|
|
1690
|
+
* @param {string} name the declared name
|
|
1691
|
+
* @param {CompressorScopeShape | null} scope the declaring scope, the toplevel for a global
|
|
1692
|
+
* @param {number} kind how it was first declared, as a `DECLARES_*` code, 0 where the compressor declares it
|
|
1693
|
+
* @param {CompressorNode | { name: string }} orig its first declaring symbol
|
|
1694
|
+
* @param {CompressorNode | null | undefined} init what it is initialized to
|
|
1695
|
+
* @returns {CompressorDefinition} the definition
|
|
1696
|
+
*/
|
|
1697
|
+
const createCompressorDefinition = (name, scope, kind, orig, init) =>
|
|
1698
|
+
/** @type {CompressorDefinition} */ (
|
|
1699
|
+
/** @type {unknown} */ (
|
|
1700
|
+
new CompressorVariable(name, scope, kind, orig, init)
|
|
1701
|
+
)
|
|
1702
|
+
);
|
|
1703
|
+
|
|
1704
|
+
/**
|
|
1705
|
+
* A scope the compressor reads, typed as it reads the shared model.
|
|
1706
|
+
* @param {ScopeType} type what opened this scope
|
|
1707
|
+
* @param {CompressorNode} node the node opening it
|
|
1708
|
+
* @param {CompressorScopeShape | null} upper the enclosing scope
|
|
1709
|
+
* @param {boolean} isVarScope whether `var` and function declarations hoist to here
|
|
1710
|
+
* @returns {CompressorScopeShape} the scope
|
|
1711
|
+
*/
|
|
1712
|
+
const createCompressorScope = (type, node, upper, isVarScope) =>
|
|
1713
|
+
/** @type {CompressorScopeShape} */ (
|
|
1714
|
+
/** @type {unknown} */ (new CompressorScope(type, node, upper, isVarScope))
|
|
1715
|
+
);
|
|
1716
|
+
|
|
1717
|
+
/**
|
|
1718
|
+
* The options the minifier's analysis reads, its mangle options among them.
|
|
1719
|
+
* @typedef {object} MinifierScopeOptions
|
|
1720
|
+
* @property {boolean=} module whether the program is a module, so strict
|
|
1721
|
+
* @property {boolean=} ie8 whether catch parameters belong to their function
|
|
1722
|
+
* @property {boolean=} safari10 whether a loop's scope reads its parent's names, and catch parameters belong to their function
|
|
1723
|
+
* @property {boolean | RegExp=} keep_fnames which function names survive, collecting the declarators naming one
|
|
1724
|
+
* @property {boolean | RegExp=} keep_classnames which class names survive, collecting the declarators naming one under `classDeclarators`
|
|
1725
|
+
* @property {boolean=} classDeclarators whether, under `keep_classnames`, the names declarators give anonymous classes are kept as `keep_fnames` keeps a function's
|
|
1726
|
+
* @property {boolean=} parameterScopes whether names are scoped as the spec scopes them where terser does not: a parameter list's or a catch parameter's reads skip what the body declares, and a block's async or generator function stays in the block
|
|
1727
|
+
* @property {number=} spelledNames which names to collect that the mangler may give the name beside them to write less: 1 for an import's or export's, 2 for a key's too
|
|
1728
|
+
*/
|
|
1729
|
+
|
|
1730
|
+
/**
|
|
1731
|
+
* @typedef {object} MinifierScopeAnalysis
|
|
1732
|
+
* @property {MinifierScope} toplevel the program's scope, its `childScopes` in the order the mangler walks them
|
|
1733
|
+
* @property {MinifierLabel[]} labels every label, in the same order
|
|
1734
|
+
* @property {Map<string, MinifierVariable>} globals the names nothing declares, in the order first read
|
|
1735
|
+
* @property {Set<MinifierScope>} blockDefunScopes the function scopes holding a function declared in a block
|
|
1736
|
+
* @property {PrintIdentifier[] | null} functionDeclarators under `keep_fnames`, the names declarators give anonymous functions, in the order the mangler asks `keep_fnames` of them
|
|
1737
|
+
* @property {PrintIdentifier[] | null} classDeclarators under `classDeclarators` and `keep_classnames`, the names declarators give anonymous classes
|
|
1738
|
+
* @property {PrintIdentifier[]} catchParameters unless `ie8` or `safari10` move them, the catch parameters, each named where the mangler's walk meets its scope
|
|
1739
|
+
* @property {boolean} namesPrivate whether the program names a private member, which renaming walks it for
|
|
1740
|
+
* @property {SpelledNames | null} spelledNames under `spelledNames`, the names a key or an import or export spells for a name beside it
|
|
1741
|
+
*/
|
|
1742
|
+
|
|
1743
|
+
/**
|
|
1744
|
+
* Where a name stands beside one spelled for it: a property's key, which the
|
|
1745
|
+
* name as its value lets print alone, or an import's or export's other name.
|
|
1746
|
+
* @typedef {object} SpelledNames
|
|
1747
|
+
* @property {PrintIdentifier[]} identifiers each name, its `definition` read once the analysis resolves
|
|
1748
|
+
* @property {string[]} spellings the name spelled beside each
|
|
1749
|
+
* @property {number[]} savings the characters each saves, its own name one long, where it takes the name spelled
|
|
1750
|
+
*/
|
|
1751
|
+
|
|
1752
|
+
/**
|
|
1753
|
+
* @param {PrintNode} node a node
|
|
1754
|
+
* @returns {boolean} whether terser holds it as a scope its statements sit in directly
|
|
1755
|
+
*/
|
|
1756
|
+
const isStatementScope = (node) =>
|
|
1757
|
+
node.type === "Program" ||
|
|
1758
|
+
node.type === "FunctionDeclaration" ||
|
|
1759
|
+
node.type === "FunctionExpression" ||
|
|
1760
|
+
node.type === "ArrowFunctionExpression" ||
|
|
1761
|
+
node.type === "StaticBlock";
|
|
1762
|
+
|
|
1763
|
+
/**
|
|
1764
|
+
* @param {PrintNode | null} node a binding pattern, `null` for an array's hole
|
|
1765
|
+
* @param {string} name a name
|
|
1766
|
+
* @returns {boolean} whether the pattern binds the name
|
|
1767
|
+
*/
|
|
1768
|
+
const bindsName = (node, name) => {
|
|
1769
|
+
if (node === null) return false;
|
|
1770
|
+
switch (node.type) {
|
|
1771
|
+
case "ObjectPattern":
|
|
1772
|
+
return node.properties.some((property) =>
|
|
1773
|
+
bindsName(
|
|
1774
|
+
property.type === "Property" ? property.value : property,
|
|
1775
|
+
name
|
|
1776
|
+
)
|
|
1777
|
+
);
|
|
1778
|
+
case "ArrayPattern":
|
|
1779
|
+
return node.elements.some((element) => bindsName(element, name));
|
|
1780
|
+
case "AssignmentPattern":
|
|
1781
|
+
return bindsName(node.left, name);
|
|
1782
|
+
case "RestElement":
|
|
1783
|
+
return bindsName(node.argument, name);
|
|
1784
|
+
default:
|
|
1785
|
+
return /** @type {PrintIdentifier} */ (node).name === name;
|
|
1786
|
+
}
|
|
1787
|
+
};
|
|
1788
|
+
|
|
1789
|
+
/**
|
|
1790
|
+
* @param {PrintNode | null} node a statement, or a loop's head
|
|
1791
|
+
* @param {string} name a name
|
|
1792
|
+
* @returns {boolean} whether it declares the name with `let`, `const`, `using` or a class
|
|
1793
|
+
*/
|
|
1794
|
+
const declaresLexically = (node, name) =>
|
|
1795
|
+
node !== null &&
|
|
1796
|
+
(node.type === "VariableDeclaration"
|
|
1797
|
+
? node.kind !== "var" &&
|
|
1798
|
+
node.declarations.some((declarator) =>
|
|
1799
|
+
bindsName(/** @type {PrintVariableDeclarator} */ (declarator).id, name)
|
|
1800
|
+
)
|
|
1801
|
+
: node.type === "ClassDeclaration" &&
|
|
1802
|
+
/** @type {PrintIdentifier} */ (node.id).name === name);
|
|
1803
|
+
|
|
1804
|
+
/**
|
|
1805
|
+
* @param {PrintNode} node a node
|
|
1806
|
+
* @returns {node is PrintExport} whether it is an `export`
|
|
1807
|
+
*/
|
|
1808
|
+
const isExport = (node) =>
|
|
1809
|
+
node.type === "ExportNamedDeclaration" ||
|
|
1810
|
+
node.type === "ExportDefaultDeclaration" ||
|
|
1811
|
+
node.type === "ExportAllDeclaration";
|
|
1812
|
+
|
|
1813
|
+
/**
|
|
1814
|
+
* @param {MinifierScope} scope the scope declaring it
|
|
1815
|
+
* @param {MinifierVariable} variable a definition
|
|
1816
|
+
* @param {number} read the read's place in the analysis's count
|
|
1817
|
+
* @returns {boolean} whether the read sits in the scope's parameter list and the definition in its body, which the list cannot see
|
|
1818
|
+
*/
|
|
1819
|
+
const isHiddenFromParameters = (scope, variable, read) =>
|
|
1820
|
+
read < scope.parameterEnd &&
|
|
1821
|
+
read >= scope.parameterStart &&
|
|
1822
|
+
variable.kind !== DECLARES_FUNARG &&
|
|
1823
|
+
variable.kind !== DECLARES_LAMBDA &&
|
|
1824
|
+
variable.kind !== DECLARES_CATCH;
|
|
1825
|
+
|
|
1826
|
+
/**
|
|
1827
|
+
* @param {MinifierScope} from the scope a name is read in
|
|
1828
|
+
* @param {string} name the name
|
|
1829
|
+
* @param {number=} read the read's place in the analysis's count, under `parameterScopes`
|
|
1830
|
+
* @returns {MinifierVariable | undefined} what it resolves to from there
|
|
1831
|
+
*/
|
|
1832
|
+
const findMinifierVariable = (from, name, read = -1) => {
|
|
1833
|
+
for (let scope = /** @type {Scope | null} */ (from); scope !== null;) {
|
|
1834
|
+
// `getBinding`, inlined: the interpreter pays a call per scope climbed
|
|
1835
|
+
const index = scope._index;
|
|
1836
|
+
/** @type {MinifierVariable | undefined} */
|
|
1837
|
+
let variable;
|
|
1838
|
+
if (index !== undefined) {
|
|
1839
|
+
variable = /** @type {MinifierVariable | undefined} */ (index.get(name));
|
|
1840
|
+
} else {
|
|
1841
|
+
const variables = scope.variables;
|
|
1842
|
+
for (let i = 0; i < variables.length; i++) {
|
|
1843
|
+
if (variables[i].name === name) {
|
|
1844
|
+
variable = /** @type {MinifierVariable} */ (variables[i]);
|
|
1845
|
+
break;
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
if (
|
|
1850
|
+
variable !== undefined &&
|
|
1851
|
+
!isHiddenFromParameters(
|
|
1852
|
+
/** @type {MinifierScope} */ (scope),
|
|
1853
|
+
variable,
|
|
1854
|
+
read
|
|
1855
|
+
)
|
|
1856
|
+
) {
|
|
1857
|
+
return variable;
|
|
1858
|
+
}
|
|
1859
|
+
scope = scope.upper;
|
|
1860
|
+
}
|
|
1861
|
+
return undefined;
|
|
1862
|
+
};
|
|
1863
|
+
|
|
1864
|
+
/**
|
|
1865
|
+
* terser's `mark_enclosed`: each scope from one out to a definition's reads it.
|
|
1866
|
+
* @param {MinifierScope} from the scope reading it
|
|
1867
|
+
* @param {MinifierVariable} variable the definition
|
|
1868
|
+
* @returns {void}
|
|
1869
|
+
*/
|
|
1870
|
+
const encloseVariable = (from, variable) => {
|
|
1871
|
+
for (let scope = /** @type {Scope | null} */ (from); scope !== null;) {
|
|
1872
|
+
encloseUnique(/** @type {MinifierScope} */ (scope), variable);
|
|
1873
|
+
if (scope === variable.scope) break;
|
|
1874
|
+
scope = scope.upper;
|
|
1875
|
+
}
|
|
1876
|
+
};
|
|
1877
|
+
|
|
1878
|
+
/**
|
|
1879
|
+
* Analyses the minifier's tree as terser's `figure_out_scope` does for its
|
|
1880
|
+
* mangler: the same scopes, definitions, enclosed lists and errors, in the
|
|
1881
|
+
* same orders, which the names it hands out depend on. Every name's
|
|
1882
|
+
* `definition` is set: its definition, its label, or null.
|
|
1883
|
+
*/
|
|
1884
|
+
class MinifierScopeAnalyzer extends ScopeAnalyzer {
|
|
1885
|
+
/**
|
|
1886
|
+
* @param {PrintProgram} program the tree, its names as written
|
|
1887
|
+
* @param {MinifierScopeOptions} options the mangle options
|
|
1888
|
+
* @param {(node: PrintNode, message: string, tables?: TokenTables) => never} raise throws the parse error a misplaced declaration is
|
|
1889
|
+
* @param {((node: PrintNode) => void) | undefined} release drops what only the compressor read off each node read, where nobody keeps the tree
|
|
1890
|
+
*/
|
|
1891
|
+
constructor(program, options, raise, release) {
|
|
1892
|
+
super(false);
|
|
1893
|
+
/** @type {(node: PrintNode, message: string, tables?: TokenTables) => never} */
|
|
1894
|
+
this.raise = raise;
|
|
1895
|
+
/** @type {((node: PrintNode) => void) | undefined} */
|
|
1896
|
+
this.release = release;
|
|
1897
|
+
// What the tree's token numbers are read through, for a message's place.
|
|
1898
|
+
/** @type {TokenTables | undefined} */
|
|
1899
|
+
this.tokenTables = program.tokenTables || undefined;
|
|
1900
|
+
/** @type {boolean} */
|
|
1901
|
+
this.legacyCatch = Boolean(options.ie8 || options.safari10);
|
|
1902
|
+
/** @type {boolean} */
|
|
1903
|
+
this.safari10 = Boolean(options.safari10);
|
|
1904
|
+
/** @type {boolean} */
|
|
1905
|
+
this.parameterScopes = Boolean(options.parameterScopes);
|
|
1906
|
+
// Only this analysis's reads are counted against a range, so each is
|
|
1907
|
+
// cleared once they resolve, before an analysis of a copy counts anew.
|
|
1908
|
+
/** @type {MinifierScope[]} the scopes holding a range of parameter reads */
|
|
1909
|
+
this.parameterRanges = [];
|
|
1910
|
+
/** @type {MinifierScope} */
|
|
1911
|
+
this.toplevel = new MinifierScope("global", program, null, true);
|
|
1912
|
+
this.scope = this.toplevel;
|
|
1913
|
+
/** @type {MinifierLabel[]} */
|
|
1914
|
+
this.labels = [];
|
|
1915
|
+
/** @type {Map<string, MinifierVariable>} */
|
|
1916
|
+
this.globals = new Map();
|
|
1917
|
+
/** @type {Set<MinifierScope>} */
|
|
1918
|
+
this.blockDefunScopes = new Set();
|
|
1919
|
+
/** @type {PrintIdentifier[] | null} */
|
|
1920
|
+
this.functionDeclarators = options.keep_fnames ? [] : null;
|
|
1921
|
+
/** @type {PrintIdentifier[] | null} */
|
|
1922
|
+
this.classDeclarators =
|
|
1923
|
+
options.classDeclarators && options.keep_classnames ? [] : null;
|
|
1924
|
+
/** @type {MinifierScope[]} */
|
|
1925
|
+
this.forScopes = [];
|
|
1926
|
+
// The names read, and catch parameters, in the order terser's walk meets them.
|
|
1927
|
+
/** @type {(PrintIdentifier | PrintLiteral)[]} */
|
|
1928
|
+
this.referenceNodes = [];
|
|
1929
|
+
/** @type {MinifierScope[]} */
|
|
1930
|
+
this.referenceScopes = [];
|
|
1931
|
+
/** @type {number[]} */
|
|
1932
|
+
this.referenceFlags = [];
|
|
1933
|
+
// Under `ie8` or `safari10`, the catch parameters in `walk`'s order.
|
|
1934
|
+
/** @type {PrintIdentifier[]} */
|
|
1935
|
+
this.catchNames = [];
|
|
1936
|
+
/** @type {MinifierScope[]} */
|
|
1937
|
+
this.catchScopes = [];
|
|
1938
|
+
// Otherwise the catch parameters, which the mangler names with their scope.
|
|
1939
|
+
/** @type {PrintIdentifier[]} */
|
|
1940
|
+
this.catchParameters = [];
|
|
1941
|
+
/** @type {boolean} whether the program names a private member */
|
|
1942
|
+
this.namesPrivate = false;
|
|
1943
|
+
/** @type {PrintNode[]} the nodes terser's walk has pushed, the node visited last */
|
|
1944
|
+
this.stack = [];
|
|
1945
|
+
/** @type {boolean} */
|
|
1946
|
+
this.strict = Boolean(options.module);
|
|
1947
|
+
/** @type {Map<string, MinifierLabel>} the labels of the statements around, up to the nearest function */
|
|
1948
|
+
this.labelsInScope = new Map();
|
|
1949
|
+
/** @type {MinifierLabel | null} */
|
|
1950
|
+
this.currentLabel = null;
|
|
1951
|
+
/** @type {PrintNode | null} the pattern the walk is inside, which `_markExport` counts from */
|
|
1952
|
+
this.inDestructuring = null;
|
|
1953
|
+
/** @type {SpelledNames | null} */
|
|
1954
|
+
this.spelledNames = options.spelledNames
|
|
1955
|
+
? { identifiers: [], spellings: [], savings: [] }
|
|
1956
|
+
: null;
|
|
1957
|
+
/** @type {boolean} whether a key spells a name, which prints alone where it is its value's */
|
|
1958
|
+
this.spelledKeys = options.spelledNames === SPELLED_KEYS;
|
|
1959
|
+
}
|
|
1960
|
+
|
|
1961
|
+
/**
|
|
1962
|
+
* Collects a name and one spelled beside it, under `spelledNames`.
|
|
1963
|
+
* @param {PrintNode | null} identifier the name, if it is one
|
|
1964
|
+
* @param {PrintNode | null} spelled what spells the other, if a name
|
|
1965
|
+
* @param {number} saving the characters it saves taking that name
|
|
1966
|
+
* @returns {void}
|
|
1967
|
+
*/
|
|
1968
|
+
_spell(identifier, spelled, saving) {
|
|
1969
|
+
const names = this.spelledNames;
|
|
1970
|
+
if (
|
|
1971
|
+
names === null ||
|
|
1972
|
+
identifier === null ||
|
|
1973
|
+
spelled === null ||
|
|
1974
|
+
identifier.type !== "Identifier"
|
|
1975
|
+
) {
|
|
1976
|
+
return;
|
|
1977
|
+
}
|
|
1978
|
+
const spelling =
|
|
1979
|
+
spelled.type === "Identifier"
|
|
1980
|
+
? spelled.name
|
|
1981
|
+
: spelled.type !== "Literal"
|
|
1982
|
+
? undefined
|
|
1983
|
+
: typeof spelled.value === "string"
|
|
1984
|
+
? spelled.value
|
|
1985
|
+
: // A module's quoted name holds its text as its name.
|
|
1986
|
+
/** @type {{ name?: string }} */ (spelled).name;
|
|
1987
|
+
if (
|
|
1988
|
+
spelling === undefined ||
|
|
1989
|
+
!SPELLABLE_NAME.test(spelling) ||
|
|
1990
|
+
NAMES_NO_BINDING_TAKES.has(spelling) ||
|
|
1991
|
+
// A shorthand `__proto__` is an own property; `__proto__:` sets the prototype.
|
|
1992
|
+
spelling === "__proto__"
|
|
1993
|
+
) {
|
|
1994
|
+
return;
|
|
1995
|
+
}
|
|
1996
|
+
names.identifiers.push(/** @type {PrintIdentifier} */ (identifier));
|
|
1997
|
+
names.spellings.push(spelling);
|
|
1998
|
+
names.savings.push(saving);
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
/**
|
|
2002
|
+
* Collects a property's value named as its key could be, under `spelledNames`.
|
|
2003
|
+
* @param {PrintProperty} property a property of an object or a pattern
|
|
2004
|
+
* @returns {void}
|
|
2005
|
+
*/
|
|
2006
|
+
_spellProperty(property) {
|
|
2007
|
+
if (!this.spelledKeys || property.computed) return;
|
|
2008
|
+
const { value } = property;
|
|
2009
|
+
this._spell(
|
|
2010
|
+
value.type === "AssignmentPattern" ? value.left : value,
|
|
2011
|
+
property.key,
|
|
2012
|
+
SHORTHAND_SAVING
|
|
2013
|
+
);
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
/**
|
|
2017
|
+
* @param {Token | number | null | undefined} token a node's token, or its number
|
|
2018
|
+
* @returns {Token | null | undefined} the token itself
|
|
2019
|
+
*/
|
|
2020
|
+
tokenOf(token) {
|
|
2021
|
+
return this.tokenTables === undefined
|
|
2022
|
+
? /** @type {Token | null | undefined} */ (token)
|
|
2023
|
+
: this.tokenTables.of(token);
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
/**
|
|
2027
|
+
* @param {ScopeType} type what opens it
|
|
2028
|
+
* @param {PrintNode} node the node opening it
|
|
2029
|
+
* @param {boolean} isVarScope whether `var` hoists to here
|
|
2030
|
+
* @returns {MinifierScope} the scope, now current
|
|
2031
|
+
*/
|
|
2032
|
+
_open(type, node, isVarScope) {
|
|
2033
|
+
const scope = new MinifierScope(
|
|
2034
|
+
type,
|
|
2035
|
+
node,
|
|
2036
|
+
/** @type {MinifierScope} */ (this.scope),
|
|
2037
|
+
isVarScope
|
|
2038
|
+
);
|
|
2039
|
+
this.scope = scope;
|
|
2040
|
+
return scope;
|
|
2041
|
+
}
|
|
2042
|
+
|
|
2043
|
+
/**
|
|
2044
|
+
* Opens a block's scope, which inherits whether a `with` reaches it.
|
|
2045
|
+
* @param {ScopeType} type what opens it
|
|
2046
|
+
* @param {PrintNode} node a block's node
|
|
2047
|
+
* @returns {MinifierScope} the scope it leaves, now the new scope's parent
|
|
2048
|
+
*/
|
|
2049
|
+
_enterBlock(type, node) {
|
|
2050
|
+
const outer = /** @type {MinifierScope} */ (this.scope);
|
|
2051
|
+
this._open(type, node, false).usesWith = outer.usesWith;
|
|
2052
|
+
return outer;
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
/**
|
|
2056
|
+
* terser's `def_variable`.
|
|
2057
|
+
* @param {MinifierScope} target the scope declaring it
|
|
2058
|
+
* @param {PrintIdentifier | null} identifier the name declaring it, if written
|
|
2059
|
+
* @param {string} name the name
|
|
2060
|
+
* @param {number} kind how it is declared
|
|
2061
|
+
* @returns {MinifierVariable} its definition, made or joined
|
|
2062
|
+
*/
|
|
2063
|
+
_defineVariable(target, identifier, name, kind) {
|
|
2064
|
+
return this._addDeclaration(
|
|
2065
|
+
target,
|
|
2066
|
+
/** @type {MinifierVariable | undefined} */ (target.getBinding(name)),
|
|
2067
|
+
identifier,
|
|
2068
|
+
name,
|
|
2069
|
+
kind
|
|
2070
|
+
);
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
/**
|
|
2074
|
+
* terser's `def_variable`, the scope's binding of the name already looked up.
|
|
2075
|
+
* @param {MinifierScope} target the scope declaring it
|
|
2076
|
+
* @param {MinifierVariable | undefined} variable what the scope binds the name to, if anything
|
|
2077
|
+
* @param {PrintIdentifier | null} identifier the name declaring it, if written
|
|
2078
|
+
* @param {string} name the name
|
|
2079
|
+
* @param {number} kind how it is declared
|
|
2080
|
+
* @returns {MinifierVariable} its definition, made or joined
|
|
2081
|
+
*/
|
|
2082
|
+
_addDeclaration(target, variable, identifier, name, kind) {
|
|
2083
|
+
if (variable !== undefined) {
|
|
2084
|
+
variable.declarations |= 1 << kind;
|
|
2085
|
+
} else {
|
|
2086
|
+
variable = new MinifierVariable(name, target, kind);
|
|
2087
|
+
variable.global = target.upper === null;
|
|
2088
|
+
if (this.legacyCatch && kind === DECLARES_CATCH) {
|
|
2089
|
+
variable.references = [];
|
|
2090
|
+
}
|
|
2091
|
+
addBinding(target, variable);
|
|
2092
|
+
}
|
|
2093
|
+
if (identifier !== null) {
|
|
2094
|
+
if (this.release !== undefined) this.release(identifier);
|
|
2095
|
+
identifier.definition = variable;
|
|
2096
|
+
}
|
|
2097
|
+
return variable;
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
/**
|
|
2101
|
+
* terser's `reference`.
|
|
2102
|
+
* @param {PrintIdentifier} identifier the name read
|
|
2103
|
+
* @param {MinifierScope} from the scope reading it
|
|
2104
|
+
* @param {MinifierVariable} variable what it reads
|
|
2105
|
+
* @returns {void}
|
|
2106
|
+
*/
|
|
2107
|
+
_referenceVariable(identifier, from, variable) {
|
|
2108
|
+
variable.referenceCount++;
|
|
2109
|
+
if (variable.references !== NO_REFERENCES) {
|
|
2110
|
+
variable.references.push(
|
|
2111
|
+
new Reference(/** @type {Identifier} */ (identifier), from)
|
|
2112
|
+
);
|
|
2113
|
+
}
|
|
2114
|
+
encloseVariable(from, variable);
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
/**
|
|
2118
|
+
* terser's `mark_export`, which counts its levels on terser's stack.
|
|
2119
|
+
* @param {MinifierVariable} variable a definition just made
|
|
2120
|
+
* @param {number} level where its declaration's statement is
|
|
2121
|
+
* @returns {void}
|
|
2122
|
+
*/
|
|
2123
|
+
_markExport(variable, level) {
|
|
2124
|
+
const stack = this.stack;
|
|
2125
|
+
if (this.inDestructuring !== null) {
|
|
2126
|
+
let i = 0;
|
|
2127
|
+
do {
|
|
2128
|
+
level++;
|
|
2129
|
+
} while (stack[stack.length - 1 - i++] !== this.inDestructuring);
|
|
2130
|
+
}
|
|
2131
|
+
const node = stack[stack.length - 1 - level];
|
|
2132
|
+
if (node === undefined || !isExport(node)) {
|
|
2133
|
+
variable.export = 0;
|
|
2134
|
+
return;
|
|
2135
|
+
}
|
|
2136
|
+
// An ESTree tree read in makes a declaration a value terser keeps named.
|
|
2137
|
+
const declaration = /** @type {PrintNode} */ (
|
|
2138
|
+
node.exported_value || node.exported_definition
|
|
2139
|
+
);
|
|
2140
|
+
variable.export =
|
|
2141
|
+
node.type === "ExportDefaultDeclaration" &&
|
|
2142
|
+
Boolean(node.exported_definition) &&
|
|
2143
|
+
(declaration.type === "FunctionDeclaration" ||
|
|
2144
|
+
declaration.type === "ClassDeclaration")
|
|
2145
|
+
? EXPORT_WANT_MANGLE
|
|
2146
|
+
: EXPORT_KEEP_NAME;
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
/**
|
|
2150
|
+
* @param {PrintNode} node an import or export
|
|
2151
|
+
* @param {string} type terser's name for it
|
|
2152
|
+
* @returns {void}
|
|
2153
|
+
*/
|
|
2154
|
+
_checkModuleStatement(node, type) {
|
|
2155
|
+
if (this.scope !== this.toplevel) {
|
|
2156
|
+
this.raise(
|
|
2157
|
+
node,
|
|
2158
|
+
`"${type}" statement may only appear at the top level`,
|
|
2159
|
+
this.tokenTables
|
|
2160
|
+
);
|
|
2161
|
+
}
|
|
2162
|
+
}
|
|
2163
|
+
|
|
2164
|
+
/**
|
|
2165
|
+
* @param {PrintIdentifier | PrintLiteral} node a name read, or a re-exported string
|
|
2166
|
+
* @param {number} flags what else is known of it, as `REFERENCE_*` bits
|
|
2167
|
+
* @returns {void}
|
|
2168
|
+
*/
|
|
2169
|
+
_addReference(node, flags) {
|
|
2170
|
+
if (this.release !== undefined) this.release(node);
|
|
2171
|
+
this.referenceNodes.push(node);
|
|
2172
|
+
this.referenceScopes.push(/** @type {MinifierScope} */ (this.scope));
|
|
2173
|
+
this.referenceFlags.push(flags);
|
|
2174
|
+
}
|
|
2175
|
+
|
|
2176
|
+
/**
|
|
2177
|
+
* A name a declaration or a pattern binds, or reads where `kind` is 0.
|
|
2178
|
+
* @param {PrintNode} node the name or pattern
|
|
2179
|
+
* @param {number} kind how it declares, as a `DECLARES_*` code, or 0
|
|
2180
|
+
* @returns {void}
|
|
2181
|
+
*/
|
|
2182
|
+
_visitBinding(node, kind) {
|
|
2183
|
+
const stack = this.stack;
|
|
2184
|
+
switch (node.type) {
|
|
2185
|
+
case "Identifier":
|
|
2186
|
+
if (kind === 0) this._visitPrint(node);
|
|
2187
|
+
else this._declare(node, kind);
|
|
2188
|
+
return;
|
|
2189
|
+
case "ObjectPattern":
|
|
2190
|
+
this._visitPattern(node, node.properties, kind);
|
|
2191
|
+
return;
|
|
2192
|
+
case "ArrayPattern":
|
|
2193
|
+
this._visitPattern(node, node.elements, kind);
|
|
2194
|
+
return;
|
|
2195
|
+
case "AssignmentPattern":
|
|
2196
|
+
stack.push(node);
|
|
2197
|
+
this._visitBinding(node.left, kind);
|
|
2198
|
+
this._visitPrint(node.right);
|
|
2199
|
+
stack.pop();
|
|
2200
|
+
return;
|
|
2201
|
+
case "RestElement":
|
|
2202
|
+
stack.push(node);
|
|
2203
|
+
this._visitBinding(node.argument, kind);
|
|
2204
|
+
stack.pop();
|
|
2205
|
+
return;
|
|
2206
|
+
default:
|
|
2207
|
+
this._visitPrint(node);
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
|
|
2211
|
+
/**
|
|
2212
|
+
* @param {PrintObject | PrintArray} pattern an object or array pattern
|
|
2213
|
+
* @param {(PrintNode | null)[]} elements its properties or elements, holes null
|
|
2214
|
+
* @param {number} kind how it declares, as a `DECLARES_*` code, or 0
|
|
2215
|
+
* @returns {void}
|
|
2216
|
+
*/
|
|
2217
|
+
_visitPattern(pattern, elements, kind) {
|
|
2218
|
+
const stack = this.stack;
|
|
2219
|
+
const outer = this.inDestructuring;
|
|
2220
|
+
this.inDestructuring = pattern;
|
|
2221
|
+
stack.push(pattern);
|
|
2222
|
+
for (let i = 0; i < elements.length; i++) {
|
|
2223
|
+
const element = elements[i];
|
|
2224
|
+
if (!element) continue;
|
|
2225
|
+
if (element.type !== "Property") {
|
|
2226
|
+
this._visitBinding(element, kind);
|
|
2227
|
+
continue;
|
|
2228
|
+
}
|
|
2229
|
+
stack.push(element);
|
|
2230
|
+
if (element.computed) this._visitPrint(element.key);
|
|
2231
|
+
this._visitBinding(element.value, kind);
|
|
2232
|
+
this._spellProperty(element);
|
|
2233
|
+
stack.pop();
|
|
2234
|
+
}
|
|
2235
|
+
stack.pop();
|
|
2236
|
+
this.inDestructuring = outer;
|
|
2237
|
+
}
|
|
2238
|
+
|
|
2239
|
+
/**
|
|
2240
|
+
* A `var`, parameter, `let`, `const`, `using`, catch parameter or import.
|
|
2241
|
+
* @param {PrintIdentifier} identifier the name declared
|
|
2242
|
+
* @param {number} kind how, as a `DECLARES_*` code
|
|
2243
|
+
* @returns {void}
|
|
2244
|
+
*/
|
|
2245
|
+
_declare(identifier, kind) {
|
|
2246
|
+
const { name } = identifier;
|
|
2247
|
+
const scope = /** @type {MinifierScope} */ (this.scope);
|
|
2248
|
+
if (kind === DECLARES_IMPORT) {
|
|
2249
|
+
this._defineVariable(scope, identifier, name, kind);
|
|
2250
|
+
return;
|
|
2251
|
+
}
|
|
2252
|
+
const blockDeclaration =
|
|
2253
|
+
kind === DECLARES_LET ||
|
|
2254
|
+
kind === DECLARES_CONST ||
|
|
2255
|
+
kind === DECLARES_USING ||
|
|
2256
|
+
kind === DECLARES_CATCH;
|
|
2257
|
+
const defun = /** @type {MinifierScope} */ (scope.variableScope);
|
|
2258
|
+
const target = blockDeclaration ? scope : defun;
|
|
2259
|
+
const before = /** @type {MinifierVariable | undefined} */ (
|
|
2260
|
+
target.getBinding(name)
|
|
2261
|
+
);
|
|
2262
|
+
const earlier = before === undefined ? 0 : before.declarations;
|
|
2263
|
+
const variable = this._addDeclaration(
|
|
2264
|
+
target,
|
|
2265
|
+
before,
|
|
2266
|
+
identifier,
|
|
2267
|
+
name,
|
|
2268
|
+
kind
|
|
2269
|
+
);
|
|
2270
|
+
// A body's lexical `arguments` shadows the function's own, which is declared
|
|
2271
|
+
// as a parameter here; a parameter so named beside it the parser refuses.
|
|
2272
|
+
const shadowsOwnArguments =
|
|
2273
|
+
this.parameterScopes &&
|
|
2274
|
+
name === "arguments" &&
|
|
2275
|
+
earlier === 1 << DECLARES_FUNARG;
|
|
2276
|
+
if (
|
|
2277
|
+
!shadowsOwnArguments &&
|
|
2278
|
+
(blockDeclaration
|
|
2279
|
+
? (earlier & ~(1 << DECLARES_LAMBDA)) !== 0
|
|
2280
|
+
: (earlier & LEXICAL_DECLARATIONS) !== 0)
|
|
2281
|
+
) {
|
|
2282
|
+
this.raise(identifier, `"${name}" is redeclared`, this.tokenTables);
|
|
2283
|
+
}
|
|
2284
|
+
if (kind !== DECLARES_FUNARG) this._markExport(variable, 2);
|
|
2285
|
+
if (defun !== scope) {
|
|
2286
|
+
encloseVariable(scope, variable);
|
|
2287
|
+
const found = /** @type {MinifierVariable} */ (
|
|
2288
|
+
findMinifierVariable(scope, name)
|
|
2289
|
+
);
|
|
2290
|
+
if (found !== variable) {
|
|
2291
|
+
identifier.definition = found;
|
|
2292
|
+
this._referenceVariable(identifier, scope, found);
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
if (kind === DECLARES_CATCH) {
|
|
2296
|
+
this._addReference(identifier, REFERENCE_CATCH);
|
|
2297
|
+
if (this.legacyCatch) {
|
|
2298
|
+
this.catchNames.push(identifier);
|
|
2299
|
+
this.catchScopes.push(scope);
|
|
2300
|
+
} else {
|
|
2301
|
+
this.catchParameters.push(identifier);
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
}
|
|
2305
|
+
|
|
2306
|
+
/**
|
|
2307
|
+
* @param {PrintNode[]} nodes statements, arguments or a template's segments
|
|
2308
|
+
* @returns {void}
|
|
2309
|
+
*/
|
|
2310
|
+
_visitList(nodes) {
|
|
2311
|
+
for (let i = 0; i < nodes.length; i++) this._visitPrint(nodes[i]);
|
|
2312
|
+
}
|
|
2313
|
+
|
|
2314
|
+
/**
|
|
2315
|
+
* Annex B's test for a sloppy block's function: a `var` of its name would be
|
|
2316
|
+
* an early error, which keeps the function in its block.
|
|
2317
|
+
* @param {MinifierScope} scope the scope the function is declared in
|
|
2318
|
+
* @param {string} name the function's name
|
|
2319
|
+
* @returns {boolean} true for `f` in `{ let f; { function f() {} } }`
|
|
2320
|
+
*/
|
|
2321
|
+
_keepsInBlock(scope, name) {
|
|
2322
|
+
while (scope !== scope.variableScope) {
|
|
2323
|
+
const node = scope.node;
|
|
2324
|
+
switch (node.type) {
|
|
2325
|
+
case "BlockStatement":
|
|
2326
|
+
if (
|
|
2327
|
+
node.body.some((statement) => declaresLexically(statement, name))
|
|
2328
|
+
) {
|
|
2329
|
+
return true;
|
|
2330
|
+
}
|
|
2331
|
+
break;
|
|
2332
|
+
case "SwitchStatement":
|
|
2333
|
+
if (
|
|
2334
|
+
node.cases.some((branch) =>
|
|
2335
|
+
branch.consequent.some((statement) =>
|
|
2336
|
+
declaresLexically(statement, name)
|
|
2337
|
+
)
|
|
2338
|
+
)
|
|
2339
|
+
) {
|
|
2340
|
+
return true;
|
|
2341
|
+
}
|
|
2342
|
+
break;
|
|
2343
|
+
case "ForStatement":
|
|
2344
|
+
if (declaresLexically(node.init, name)) return true;
|
|
2345
|
+
break;
|
|
2346
|
+
case "ForInStatement":
|
|
2347
|
+
case "ForOfStatement":
|
|
2348
|
+
if (declaresLexically(node.left, name)) return true;
|
|
2349
|
+
break;
|
|
2350
|
+
case "CatchClause":
|
|
2351
|
+
// B.3.5 lets a `var` redeclare a plain catch parameter, not a pattern's.
|
|
2352
|
+
// The body's statements sit in this scope, with no block of their own.
|
|
2353
|
+
if (
|
|
2354
|
+
(node.param &&
|
|
2355
|
+
node.param.type !== "Identifier" &&
|
|
2356
|
+
bindsName(node.param, name)) ||
|
|
2357
|
+
node.body.body.some((statement) =>
|
|
2358
|
+
declaresLexically(statement, name)
|
|
2359
|
+
)
|
|
2360
|
+
) {
|
|
2361
|
+
return true;
|
|
2362
|
+
}
|
|
2363
|
+
break;
|
|
2364
|
+
}
|
|
2365
|
+
scope = /** @type {MinifierScope} */ (scope.upper);
|
|
2366
|
+
}
|
|
2367
|
+
const node = scope.node;
|
|
2368
|
+
if (node.type === "Program") {
|
|
2369
|
+
return node.body.some((statement) => declaresLexically(statement, name));
|
|
2370
|
+
}
|
|
2371
|
+
const owner = /** @type {PrintFunction} */ (node);
|
|
2372
|
+
return (
|
|
2373
|
+
owner.params.some((param) => bindsName(param, name)) ||
|
|
2374
|
+
owner.body.body.some((statement) => declaresLexically(statement, name))
|
|
2375
|
+
);
|
|
2376
|
+
}
|
|
2377
|
+
|
|
2378
|
+
/**
|
|
2379
|
+
* @param {PrintFunction} node a function
|
|
2380
|
+
* @returns {void}
|
|
2381
|
+
*/
|
|
2382
|
+
_visitMinifierFunction(node) {
|
|
2383
|
+
const outerStrict = this.strict;
|
|
2384
|
+
const outer = /** @type {MinifierScope} */ (this.scope);
|
|
2385
|
+
const outerLabels = this.labelsInScope;
|
|
2386
|
+
const stack = this.stack;
|
|
2387
|
+
const inBlock =
|
|
2388
|
+
node.type === "FunctionDeclaration" &&
|
|
2389
|
+
!isStatementScope(stack[stack.length - 1]);
|
|
2390
|
+
if (inBlock) {
|
|
2391
|
+
this.blockDefunScopes.add(
|
|
2392
|
+
/** @type {MinifierScope} */ (outer.variableScope)
|
|
2393
|
+
);
|
|
2394
|
+
}
|
|
2395
|
+
stack.push(node);
|
|
2396
|
+
const lambda = this._open("function", node, true);
|
|
2397
|
+
if (node.type !== "ArrowFunctionExpression") {
|
|
2398
|
+
this._defineVariable(lambda, null, "arguments", DECLARES_FUNARG);
|
|
2399
|
+
}
|
|
2400
|
+
this.labelsInScope = new Map();
|
|
2401
|
+
const { id } = node;
|
|
2402
|
+
if (!id) {
|
|
2403
|
+
// An arrow or a method has no name of its own.
|
|
2404
|
+
} else if (id.role === "defun") {
|
|
2405
|
+
this._markExport(
|
|
2406
|
+
this._defineVariable(
|
|
2407
|
+
// Annex B hoists a sloppy block's plain function only.
|
|
2408
|
+
this.strict ||
|
|
2409
|
+
(this.parameterScopes &&
|
|
2410
|
+
(node.async ||
|
|
2411
|
+
node.generator ||
|
|
2412
|
+
(inBlock && this._keepsInBlock(outer, id.name))))
|
|
2413
|
+
? outer
|
|
2414
|
+
: /** @type {MinifierScope} */ (outer.variableScope),
|
|
2415
|
+
id,
|
|
2416
|
+
id.name,
|
|
2417
|
+
DECLARES_DEFUN
|
|
2418
|
+
),
|
|
2419
|
+
1
|
|
2420
|
+
);
|
|
2421
|
+
} else {
|
|
2422
|
+
this._defineVariable(lambda, id, id.name, DECLARES_LAMBDA);
|
|
2423
|
+
}
|
|
2424
|
+
if (id && node.type === "FunctionExpression") {
|
|
2425
|
+
lambda.functionName = /** @type {MinifierVariable} */ (id.definition);
|
|
2426
|
+
}
|
|
2427
|
+
const { params } = node;
|
|
2428
|
+
const ranged = this.parameterScopes && params.length !== 0;
|
|
2429
|
+
if (ranged) {
|
|
2430
|
+
lambda.parameterStart = this.referenceNodes.length;
|
|
2431
|
+
this.parameterRanges.push(lambda);
|
|
2432
|
+
}
|
|
2433
|
+
for (let i = 0; i < params.length; i++) {
|
|
2434
|
+
this._visitBinding(params[i], DECLARES_FUNARG);
|
|
2435
|
+
}
|
|
2436
|
+
if (ranged) lambda.parameterEnd = this.referenceNodes.length;
|
|
2437
|
+
if (this.release !== undefined) this.release(node.body);
|
|
2438
|
+
this._visitList(node.body.body);
|
|
2439
|
+
this.scope = outer;
|
|
2440
|
+
this.labelsInScope = outerLabels;
|
|
2441
|
+
this.strict = outerStrict;
|
|
2442
|
+
stack.pop();
|
|
2443
|
+
}
|
|
2444
|
+
|
|
2445
|
+
/**
|
|
2446
|
+
* @param {PrintClass} node a class
|
|
2447
|
+
* @returns {void}
|
|
2448
|
+
*/
|
|
2449
|
+
_visitMinifierClass(node) {
|
|
2450
|
+
const outerStrict = this.strict;
|
|
2451
|
+
const outer = /** @type {MinifierScope} */ (this.scope);
|
|
2452
|
+
const outerLabels = this.labelsInScope;
|
|
2453
|
+
this.stack.push(node);
|
|
2454
|
+
this.strict = true;
|
|
2455
|
+
const classScope = this._open("class", node, true);
|
|
2456
|
+
this.labelsInScope = new Map();
|
|
2457
|
+
const { id } = node;
|
|
2458
|
+
if (id) {
|
|
2459
|
+
this._markExport(
|
|
2460
|
+
id.role === "defClass"
|
|
2461
|
+
? this._defineVariable(outer, id, id.name, DECLARES_DEF_CLASS)
|
|
2462
|
+
: this._defineVariable(classScope, id, id.name, DECLARES_CLASS),
|
|
2463
|
+
1
|
|
2464
|
+
);
|
|
2465
|
+
}
|
|
2466
|
+
if (node.superClass) this._visitPrint(node.superClass);
|
|
2467
|
+
this._visitList(node.body.body);
|
|
2468
|
+
this.scope = outer;
|
|
2469
|
+
this.labelsInScope = outerLabels;
|
|
2470
|
+
this.strict = outerStrict;
|
|
2471
|
+
this.stack.pop();
|
|
2472
|
+
}
|
|
2473
|
+
|
|
2474
|
+
/**
|
|
2475
|
+
* A call under `ie8` or `safari10`, whose catch parameters terser's
|
|
2476
|
+
* `walk` meets callee first, where its `_walk` meets the arguments first.
|
|
2477
|
+
* @param {PrintCallExpression | PrintNewExpression} node the call
|
|
2478
|
+
* @returns {void}
|
|
2479
|
+
*/
|
|
2480
|
+
_visitLegacyCall(node) {
|
|
2481
|
+
const { catchNames, catchScopes } = this;
|
|
2482
|
+
this.stack.push(node);
|
|
2483
|
+
const argumentsStart = catchNames.length;
|
|
2484
|
+
this._visitList(node.arguments);
|
|
2485
|
+
const calleeStart = catchNames.length;
|
|
2486
|
+
this._visitPrint(node.callee);
|
|
2487
|
+
if (argumentsStart < calleeStart && calleeStart < catchNames.length) {
|
|
2488
|
+
catchNames.splice(argumentsStart, 0, ...catchNames.splice(calleeStart));
|
|
2489
|
+
catchScopes.splice(argumentsStart, 0, ...catchScopes.splice(calleeStart));
|
|
2490
|
+
}
|
|
2491
|
+
this.stack.pop();
|
|
2492
|
+
}
|
|
2493
|
+
|
|
2494
|
+
/**
|
|
2495
|
+
* A loop's children, its scope entered.
|
|
2496
|
+
* @param {PrintForStatement | PrintForInStatement | PrintForOfStatement | PrintWhileStatement} node the loop
|
|
2497
|
+
* @returns {void}
|
|
2498
|
+
*/
|
|
2499
|
+
_visitLoop(node) {
|
|
2500
|
+
switch (node.type) {
|
|
2501
|
+
case "ForStatement":
|
|
2502
|
+
if (node.init) this._visitPrint(node.init);
|
|
2503
|
+
if (node.test) this._visitPrint(node.test);
|
|
2504
|
+
if (node.update) this._visitPrint(node.update);
|
|
2505
|
+
break;
|
|
2506
|
+
case "WhileStatement":
|
|
2507
|
+
this._visitPrint(node.test);
|
|
2508
|
+
break;
|
|
2509
|
+
case "DoWhileStatement":
|
|
2510
|
+
this._visitPrint(node.body);
|
|
2511
|
+
this._visitPrint(node.test);
|
|
2512
|
+
return;
|
|
2513
|
+
default:
|
|
2514
|
+
this._visitBinding(node.left, 0);
|
|
2515
|
+
this._visitPrint(node.right);
|
|
2516
|
+
}
|
|
2517
|
+
this._visitPrint(node.body);
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
/**
|
|
2521
|
+
* @param {PrintVariableDeclaration} node a `var`, `let`, `const` or `using`
|
|
2522
|
+
* @returns {void}
|
|
2523
|
+
*/
|
|
2524
|
+
_visitDeclaration(node) {
|
|
2525
|
+
const kind =
|
|
2526
|
+
node.kind === "var"
|
|
2527
|
+
? DECLARES_VAR
|
|
2528
|
+
: node.kind === "let"
|
|
2529
|
+
? DECLARES_LET
|
|
2530
|
+
: node.kind === "const"
|
|
2531
|
+
? DECLARES_CONST
|
|
2532
|
+
: DECLARES_USING;
|
|
2533
|
+
const { stack, functionDeclarators, classDeclarators } = this;
|
|
2534
|
+
stack.push(node);
|
|
2535
|
+
const { declarations } = node;
|
|
2536
|
+
for (let i = 0; i < declarations.length; i++) {
|
|
2537
|
+
const declarator = /** @type {PrintVariableDeclarator} */ (
|
|
2538
|
+
declarations[i]
|
|
2539
|
+
);
|
|
2540
|
+
const { id, init } = declarator;
|
|
2541
|
+
if (
|
|
2542
|
+
functionDeclarators !== null &&
|
|
2543
|
+
kind !== DECLARES_USING &&
|
|
2544
|
+
id.type === "Identifier" &&
|
|
2545
|
+
init &&
|
|
2546
|
+
(init.type === "FunctionExpression" ||
|
|
2547
|
+
init.type === "ArrowFunctionExpression") &&
|
|
2548
|
+
!init.id
|
|
2549
|
+
) {
|
|
2550
|
+
functionDeclarators.push(id);
|
|
2551
|
+
} else if (
|
|
2552
|
+
classDeclarators !== null &&
|
|
2553
|
+
kind !== DECLARES_USING &&
|
|
2554
|
+
id.type === "Identifier" &&
|
|
2555
|
+
init &&
|
|
2556
|
+
init.type === "ClassExpression" &&
|
|
2557
|
+
!init.id
|
|
2558
|
+
) {
|
|
2559
|
+
classDeclarators.push(id);
|
|
2560
|
+
}
|
|
2561
|
+
stack.push(declarator);
|
|
2562
|
+
this._visitBinding(id, kind);
|
|
2563
|
+
if (init) this._visitPrint(init);
|
|
2564
|
+
stack.pop();
|
|
2565
|
+
}
|
|
2566
|
+
stack.pop();
|
|
2567
|
+
}
|
|
2568
|
+
|
|
2569
|
+
/**
|
|
2570
|
+
* @param {Node} node node to visit
|
|
2571
|
+
* @returns {void}
|
|
2572
|
+
*/
|
|
2573
|
+
_visit(node) {
|
|
2574
|
+
// the shared walk's way back in, for the children of what it reads
|
|
2575
|
+
this._visitPrint(/** @type {PrintNode} */ (/** @type {unknown} */ (node)));
|
|
2576
|
+
}
|
|
2577
|
+
|
|
2578
|
+
/**
|
|
2579
|
+
* Reads what is scoped as webpack does with the shared walk, pushed as
|
|
2580
|
+
* terser's walk pushes it, and the rest as terser's analysis does.
|
|
2581
|
+
* @param {PrintNode} current node to visit
|
|
2582
|
+
* @returns {void}
|
|
2583
|
+
*/
|
|
2584
|
+
_visitPrint(current) {
|
|
2585
|
+
if (this.release !== undefined) this.release(current);
|
|
2586
|
+
const stack = this.stack;
|
|
2587
|
+
switch (current.type) {
|
|
2588
|
+
case "Identifier": {
|
|
2589
|
+
if (current.atom === true) return;
|
|
2590
|
+
const parent = stack[stack.length - 1];
|
|
2591
|
+
this._addReference(
|
|
2592
|
+
current,
|
|
2593
|
+
current.name === "eval" &&
|
|
2594
|
+
(parent.type === "CallExpression" ||
|
|
2595
|
+
parent.type === "NewExpression")
|
|
2596
|
+
? REFERENCE_CALLED
|
|
2597
|
+
: 0
|
|
2598
|
+
);
|
|
2599
|
+
return;
|
|
2600
|
+
}
|
|
2601
|
+
// the commonest kinds first: the chain is a sequence of comparisons
|
|
2602
|
+
case "MemberExpression":
|
|
2603
|
+
stack.push(current);
|
|
2604
|
+
this._visitPrint(current.object);
|
|
2605
|
+
if (current.computed) {
|
|
2606
|
+
this._visitPrint(current.property);
|
|
2607
|
+
} else if (current.property.type === "PrivateIdentifier") {
|
|
2608
|
+
this.namesPrivate = true;
|
|
2609
|
+
}
|
|
2610
|
+
stack.pop();
|
|
2611
|
+
return;
|
|
2612
|
+
case "CallExpression":
|
|
2613
|
+
case "NewExpression":
|
|
2614
|
+
if (this.legacyCatch) {
|
|
2615
|
+
this._visitLegacyCall(current);
|
|
2616
|
+
return;
|
|
2617
|
+
}
|
|
2618
|
+
// terser's walk reaches the arguments first.
|
|
2619
|
+
stack.push(current);
|
|
2620
|
+
this._visitList(current.arguments);
|
|
2621
|
+
this._visitPrint(current.callee);
|
|
2622
|
+
stack.pop();
|
|
2623
|
+
return;
|
|
2624
|
+
case "Literal":
|
|
2625
|
+
case "ThisExpression":
|
|
2626
|
+
return;
|
|
2627
|
+
case "ExpressionStatement":
|
|
2628
|
+
if (typeof current.directive === "string") {
|
|
2629
|
+
if (current.directive === "use strict") this.strict = true;
|
|
2630
|
+
return;
|
|
2631
|
+
}
|
|
2632
|
+
stack.push(current);
|
|
2633
|
+
this._visitPrint(current.expression);
|
|
2634
|
+
stack.pop();
|
|
2635
|
+
return;
|
|
2636
|
+
case "BinaryExpression":
|
|
2637
|
+
case "LogicalExpression":
|
|
2638
|
+
case "AssignmentExpression":
|
|
2639
|
+
stack.push(current);
|
|
2640
|
+
this._visitPrint(current.left);
|
|
2641
|
+
this._visitPrint(current.right);
|
|
2642
|
+
stack.pop();
|
|
2643
|
+
return;
|
|
2644
|
+
case "BlockStatement": {
|
|
2645
|
+
stack.push(current);
|
|
2646
|
+
const outer = this._enterBlock("block", current);
|
|
2647
|
+
this._visitList(current.body);
|
|
2648
|
+
this.scope = outer;
|
|
2649
|
+
stack.pop();
|
|
2650
|
+
return;
|
|
2651
|
+
}
|
|
2652
|
+
case "ReturnStatement":
|
|
2653
|
+
case "UnaryExpression":
|
|
2654
|
+
case "UpdateExpression":
|
|
2655
|
+
case "ThrowStatement":
|
|
2656
|
+
case "AwaitExpression":
|
|
2657
|
+
case "SpreadElement":
|
|
2658
|
+
case "YieldExpression":
|
|
2659
|
+
stack.push(current);
|
|
2660
|
+
if (current.argument) this._visitPrint(current.argument);
|
|
2661
|
+
stack.pop();
|
|
2662
|
+
return;
|
|
2663
|
+
case "VariableDeclaration":
|
|
2664
|
+
this._visitDeclaration(current);
|
|
2665
|
+
return;
|
|
2666
|
+
case "FunctionDeclaration":
|
|
2667
|
+
case "FunctionExpression":
|
|
2668
|
+
case "ArrowFunctionExpression":
|
|
2669
|
+
this._visitMinifierFunction(current);
|
|
2670
|
+
return;
|
|
2671
|
+
case "ClassDeclaration":
|
|
2672
|
+
case "ClassExpression":
|
|
2673
|
+
this._visitMinifierClass(current);
|
|
2674
|
+
return;
|
|
2675
|
+
case "ForStatement":
|
|
2676
|
+
case "ForInStatement":
|
|
2677
|
+
case "ForOfStatement":
|
|
2678
|
+
case "WhileStatement":
|
|
2679
|
+
case "DoWhileStatement": {
|
|
2680
|
+
stack.push(current);
|
|
2681
|
+
const outer = this._enterBlock(
|
|
2682
|
+
current.type.startsWith("For") ? "for" : "block",
|
|
2683
|
+
current
|
|
2684
|
+
);
|
|
2685
|
+
if (this.safari10 && current.type.startsWith("For")) {
|
|
2686
|
+
this.forScopes.push(/** @type {MinifierScope} */ (this.scope));
|
|
2687
|
+
}
|
|
2688
|
+
this._visitLoop(current);
|
|
2689
|
+
this.scope = outer;
|
|
2690
|
+
stack.pop();
|
|
2691
|
+
return;
|
|
2692
|
+
}
|
|
2693
|
+
case "SwitchStatement": {
|
|
2694
|
+
stack.push(current);
|
|
2695
|
+
const outer = this._enterBlock("switch", current);
|
|
2696
|
+
// The switched expression belongs to the scope around the switch.
|
|
2697
|
+
const block = this.scope;
|
|
2698
|
+
this.scope = outer;
|
|
2699
|
+
this._visitPrint(current.discriminant);
|
|
2700
|
+
this.scope = block;
|
|
2701
|
+
this._visitList(current.cases);
|
|
2702
|
+
this.scope = outer;
|
|
2703
|
+
stack.pop();
|
|
2704
|
+
return;
|
|
2705
|
+
}
|
|
2706
|
+
case "CatchClause": {
|
|
2707
|
+
stack.push(current);
|
|
2708
|
+
const outer = this._enterBlock("catch", current);
|
|
2709
|
+
const catchScope = /** @type {MinifierScope} */ (this.scope);
|
|
2710
|
+
const ranged = this.parameterScopes && Boolean(current.param);
|
|
2711
|
+
if (ranged) {
|
|
2712
|
+
catchScope.parameterStart = this.referenceNodes.length;
|
|
2713
|
+
this.parameterRanges.push(catchScope);
|
|
2714
|
+
}
|
|
2715
|
+
if (current.param) this._visitBinding(current.param, DECLARES_CATCH);
|
|
2716
|
+
if (ranged) catchScope.parameterEnd = this.referenceNodes.length;
|
|
2717
|
+
if (this.release !== undefined) this.release(current.body);
|
|
2718
|
+
this._visitList(current.body.body);
|
|
2719
|
+
this.scope = outer;
|
|
2720
|
+
stack.pop();
|
|
2721
|
+
return;
|
|
2722
|
+
}
|
|
2723
|
+
case "StaticBlock": {
|
|
2724
|
+
const outer = this.scope;
|
|
2725
|
+
const outerLabels = this.labelsInScope;
|
|
2726
|
+
stack.push(current);
|
|
2727
|
+
this._open("class-static-block", current, true);
|
|
2728
|
+
this.labelsInScope = new Map();
|
|
2729
|
+
this._visitList(current.body);
|
|
2730
|
+
this.scope = outer;
|
|
2731
|
+
this.labelsInScope = outerLabels;
|
|
2732
|
+
stack.pop();
|
|
2733
|
+
return;
|
|
2734
|
+
}
|
|
2735
|
+
case "LabeledStatement": {
|
|
2736
|
+
const labelName = /** @type {PrintIdentifier} */ (current.label);
|
|
2737
|
+
const { name } = labelName;
|
|
2738
|
+
if (this.labelsInScope.has(name)) {
|
|
2739
|
+
throw new Error(`Label ${name} defined twice`);
|
|
2740
|
+
}
|
|
2741
|
+
const label = new MinifierLabel(name, this.currentLabel);
|
|
2742
|
+
this.labels.push(label);
|
|
2743
|
+
if (this.release !== undefined) this.release(labelName);
|
|
2744
|
+
labelName.definition = label;
|
|
2745
|
+
this.labelsInScope.set(name, label);
|
|
2746
|
+
stack.push(current);
|
|
2747
|
+
this.currentLabel = label;
|
|
2748
|
+
this._visitPrint(current.body);
|
|
2749
|
+
this.currentLabel = label.parent;
|
|
2750
|
+
stack.pop();
|
|
2751
|
+
this.labelsInScope.delete(name);
|
|
2752
|
+
return;
|
|
2753
|
+
}
|
|
2754
|
+
case "BreakStatement":
|
|
2755
|
+
case "ContinueStatement": {
|
|
2756
|
+
const name = /** @type {PrintIdentifier | null} */ (current.label);
|
|
2757
|
+
if (!name) return;
|
|
2758
|
+
const label = this.labelsInScope.get(name.name);
|
|
2759
|
+
if (label === undefined) {
|
|
2760
|
+
const start = /** @type {Token} */ (this.tokenOf(name.startToken));
|
|
2761
|
+
throw new Error(
|
|
2762
|
+
`Undefined label ${name.name} [${start.line},${start.col}]`
|
|
2763
|
+
);
|
|
2764
|
+
}
|
|
2765
|
+
if (this.release !== undefined) this.release(name);
|
|
2766
|
+
name.definition = label;
|
|
2767
|
+
return;
|
|
2768
|
+
}
|
|
2769
|
+
case "WithStatement":
|
|
2770
|
+
for (
|
|
2771
|
+
let outer = /** @type {MinifierScope | null} */ (this.scope);
|
|
2772
|
+
outer !== null;
|
|
2773
|
+
outer = /** @type {MinifierScope | null} */ (outer.upper)
|
|
2774
|
+
) {
|
|
2775
|
+
outer.usesWith = true;
|
|
2776
|
+
}
|
|
2777
|
+
stack.push(current);
|
|
2778
|
+
this._visitPrint(current.object);
|
|
2779
|
+
this._visitPrint(current.body);
|
|
2780
|
+
stack.pop();
|
|
2781
|
+
return;
|
|
2782
|
+
case "Property":
|
|
2783
|
+
case "PropertyDefinition":
|
|
2784
|
+
if (current.key.type === "PrivateIdentifier") this.namesPrivate = true;
|
|
2785
|
+
stack.push(current);
|
|
2786
|
+
if (current.computed) this._visitPrint(current.key);
|
|
2787
|
+
if (current.value) this._visitPrint(current.value);
|
|
2788
|
+
if (
|
|
2789
|
+
current.type === "Property" &&
|
|
2790
|
+
current.kind === "init" &&
|
|
2791
|
+
!current.method
|
|
2792
|
+
) {
|
|
2793
|
+
this._spellProperty(current);
|
|
2794
|
+
}
|
|
2795
|
+
stack.pop();
|
|
2796
|
+
return;
|
|
2797
|
+
case "ObjectPattern":
|
|
2798
|
+
case "ArrayPattern":
|
|
2799
|
+
case "AssignmentPattern":
|
|
2800
|
+
case "RestElement":
|
|
2801
|
+
this._visitBinding(current, 0);
|
|
2802
|
+
return;
|
|
2803
|
+
case "TemplateLiteral":
|
|
2804
|
+
stack.push(current);
|
|
2805
|
+
this._visitList(current.segments);
|
|
2806
|
+
stack.pop();
|
|
2807
|
+
return;
|
|
2808
|
+
case "ImportExpression":
|
|
2809
|
+
stack.push(current);
|
|
2810
|
+
this._visitList(current.args);
|
|
2811
|
+
stack.pop();
|
|
2812
|
+
return;
|
|
2813
|
+
case "MethodDefinition":
|
|
2814
|
+
if (current.key.type === "PrivateIdentifier") this.namesPrivate = true;
|
|
2815
|
+
// falls through
|
|
2816
|
+
case "IfStatement":
|
|
2817
|
+
case "ConditionalExpression":
|
|
2818
|
+
case "SwitchCase":
|
|
2819
|
+
case "ArrayExpression":
|
|
2820
|
+
case "ObjectExpression":
|
|
2821
|
+
case "SequenceExpression":
|
|
2822
|
+
case "TaggedTemplateExpression":
|
|
2823
|
+
case "ChainExpression":
|
|
2824
|
+
case "TryStatement":
|
|
2825
|
+
// scoped alike, so read by the shared walk, pushed as terser's walk does
|
|
2826
|
+
stack.push(current);
|
|
2827
|
+
super._visit(/** @type {Node} */ (/** @type {unknown} */ (current)));
|
|
2828
|
+
stack.pop();
|
|
2829
|
+
return;
|
|
2830
|
+
case "PrivateIdentifier":
|
|
2831
|
+
this.namesPrivate = true;
|
|
2832
|
+
return;
|
|
2833
|
+
case "Super":
|
|
2834
|
+
case "EmptyStatement":
|
|
2835
|
+
case "DebuggerStatement":
|
|
2836
|
+
case "MetaProperty":
|
|
2837
|
+
case "TemplateElement":
|
|
2838
|
+
return;
|
|
2839
|
+
case "ImportDeclaration": {
|
|
2840
|
+
this._checkModuleStatement(current, "Import");
|
|
2841
|
+
stack.push(current);
|
|
2842
|
+
// terser holds a default import's name with no node around it.
|
|
2843
|
+
if (current.imported_name) {
|
|
2844
|
+
this._declare(current.imported_name, DECLARES_IMPORT);
|
|
2845
|
+
}
|
|
2846
|
+
const names = current.imported_names;
|
|
2847
|
+
if (names) {
|
|
2848
|
+
for (let i = 0; i < names.length; i++) {
|
|
2849
|
+
const specifier = names[i];
|
|
2850
|
+
stack.push(specifier);
|
|
2851
|
+
this._declare(
|
|
2852
|
+
/** @type {PrintIdentifier} */ (specifier.local),
|
|
2853
|
+
DECLARES_IMPORT
|
|
2854
|
+
);
|
|
2855
|
+
if (specifier.type === "ImportSpecifier") {
|
|
2856
|
+
this._spell(specifier.local, specifier.imported, AS_SAVING);
|
|
2857
|
+
}
|
|
2858
|
+
stack.pop();
|
|
2859
|
+
}
|
|
2860
|
+
}
|
|
2861
|
+
stack.pop();
|
|
2862
|
+
return;
|
|
2863
|
+
}
|
|
2864
|
+
case "ExportNamedDeclaration": {
|
|
2865
|
+
this._checkModuleStatement(current, "Export");
|
|
2866
|
+
stack.push(current);
|
|
2867
|
+
const declaration =
|
|
2868
|
+
current.exported_value || current.exported_definition;
|
|
2869
|
+
if (declaration) this._visitPrint(declaration);
|
|
2870
|
+
const fromModule = Boolean(current.source);
|
|
2871
|
+
const specifiers = current.exported_names;
|
|
2872
|
+
if (specifiers) {
|
|
2873
|
+
for (let i = 0; i < specifiers.length; i++) {
|
|
2874
|
+
const specifier = specifiers[i];
|
|
2875
|
+
stack.push(specifier);
|
|
2876
|
+
this._addReference(
|
|
2877
|
+
/** @type {PrintIdentifier | PrintLiteral} */ (specifier.local),
|
|
2878
|
+
fromModule
|
|
2879
|
+
? REFERENCE_EXPORTED | REFERENCE_FROM_MODULE
|
|
2880
|
+
: REFERENCE_EXPORTED
|
|
2881
|
+
);
|
|
2882
|
+
if (!fromModule) {
|
|
2883
|
+
this._spell(specifier.local, specifier.exported, AS_SAVING);
|
|
2884
|
+
}
|
|
2885
|
+
stack.pop();
|
|
2886
|
+
}
|
|
2887
|
+
}
|
|
2888
|
+
stack.pop();
|
|
2889
|
+
return;
|
|
2890
|
+
}
|
|
2891
|
+
case "ExportDefaultDeclaration":
|
|
2892
|
+
this._checkModuleStatement(current, "Export");
|
|
2893
|
+
stack.push(current);
|
|
2894
|
+
this._visitPrint(
|
|
2895
|
+
/** @type {PrintNode} */ (
|
|
2896
|
+
current.exported_value || current.exported_definition
|
|
2897
|
+
)
|
|
2898
|
+
);
|
|
2899
|
+
stack.pop();
|
|
2900
|
+
return;
|
|
2901
|
+
case "ExportAllDeclaration":
|
|
2902
|
+
// terser's `*` reads a global no name in the output depends on.
|
|
2903
|
+
this._checkModuleStatement(current, "Export");
|
|
2904
|
+
return;
|
|
2905
|
+
default:
|
|
2906
|
+
throw new Error(
|
|
2907
|
+
`The minifier's scope analysis cannot read a ${current.type} node`
|
|
2908
|
+
);
|
|
2909
|
+
}
|
|
2910
|
+
}
|
|
2911
|
+
|
|
2912
|
+
/**
|
|
2913
|
+
* Drops the ranges of parameter reads this analysis counted.
|
|
2914
|
+
* @returns {void}
|
|
2915
|
+
*/
|
|
2916
|
+
_clearParameterRanges() {
|
|
2917
|
+
const { parameterRanges } = this;
|
|
2918
|
+
for (let i = 0; i < parameterRanges.length; i++) {
|
|
2919
|
+
parameterRanges[i].parameterStart = -1;
|
|
2920
|
+
parameterRanges[i].parameterEnd = -1;
|
|
2921
|
+
}
|
|
2922
|
+
parameterRanges.length = 0;
|
|
2923
|
+
}
|
|
2924
|
+
|
|
2925
|
+
/**
|
|
2926
|
+
* Resolves each name read, finds `eval`, and encloses what a catch
|
|
2927
|
+
* parameter redefines, then moves the catch parameters old engines scope
|
|
2928
|
+
* to their function.
|
|
2929
|
+
* @returns {void}
|
|
2930
|
+
*/
|
|
2931
|
+
_resolveMinifier() {
|
|
2932
|
+
const { referenceNodes, referenceScopes, referenceFlags, globals } = this;
|
|
2933
|
+
for (let i = 0; i < referenceNodes.length; i++) {
|
|
2934
|
+
const node = referenceNodes[i];
|
|
2935
|
+
const from = referenceScopes[i];
|
|
2936
|
+
const flags = referenceFlags[i];
|
|
2937
|
+
if (flags & REFERENCE_CATCH) {
|
|
2938
|
+
// The definition a catch parameter redefines in its function's scope.
|
|
2939
|
+
const redefinition = /** @type {MinifierVariable | undefined} */ (
|
|
2940
|
+
from.variableScope.getBinding(
|
|
2941
|
+
/** @type {PrintIdentifier} */ (node).name
|
|
2942
|
+
)
|
|
2943
|
+
);
|
|
2944
|
+
if (redefinition !== undefined) encloseVariable(from, redefinition);
|
|
2945
|
+
continue;
|
|
2946
|
+
}
|
|
2947
|
+
const { name } = node;
|
|
2948
|
+
if (flags & REFERENCE_CALLED) {
|
|
2949
|
+
for (
|
|
2950
|
+
let outer = /** @type {MinifierScope | null} */ (from);
|
|
2951
|
+
outer !== null && !outer.usesEval;
|
|
2952
|
+
outer = /** @type {MinifierScope | null} */ (outer.upper)
|
|
2953
|
+
) {
|
|
2954
|
+
outer.usesEval = true;
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
let variable =
|
|
2958
|
+
flags & REFERENCE_FROM_MODULE
|
|
2959
|
+
? undefined
|
|
2960
|
+
: findMinifierVariable(from, name, i);
|
|
2961
|
+
if (variable === undefined) {
|
|
2962
|
+
variable = globals.get(name);
|
|
2963
|
+
if (variable === undefined) {
|
|
2964
|
+
variable = new MinifierVariable(name, this.toplevel, DECLARES_GLOBAL);
|
|
2965
|
+
variable.undeclared = true;
|
|
2966
|
+
variable.global = true;
|
|
2967
|
+
globals.set(name, variable);
|
|
2968
|
+
}
|
|
2969
|
+
if (flags & REFERENCE_EXPORTED) variable.export = EXPORT_KEEP_NAME;
|
|
2970
|
+
}
|
|
2971
|
+
if (node.type === "Identifier") {
|
|
2972
|
+
node.definition = variable;
|
|
2973
|
+
this._referenceVariable(node, from, variable);
|
|
2974
|
+
} else {
|
|
2975
|
+
// A re-exported string reads a global, which keeps no references.
|
|
2976
|
+
encloseVariable(from, variable);
|
|
2977
|
+
}
|
|
2978
|
+
}
|
|
2979
|
+
|
|
2980
|
+
this._clearParameterRanges();
|
|
2981
|
+
|
|
2982
|
+
// Passes 3 and 4: work around old engines' catch and loop scopes.
|
|
2983
|
+
const { catchNames, catchScopes } = this;
|
|
2984
|
+
for (let i = 0; i < catchNames.length; i++) {
|
|
2985
|
+
const identifier = catchNames[i];
|
|
2986
|
+
const { name } = identifier;
|
|
2987
|
+
const references = /** @type {MinifierVariable} */ (identifier.definition)
|
|
2988
|
+
.references;
|
|
2989
|
+
const defunScope = /** @type {MinifierScope} */ (
|
|
2990
|
+
catchScopes[i].variableScope
|
|
2991
|
+
);
|
|
2992
|
+
const variable =
|
|
2993
|
+
findMinifierVariable(defunScope, name) ||
|
|
2994
|
+
globals.get(name) ||
|
|
2995
|
+
this._defineVariable(defunScope, null, name, DECLARES_CATCH);
|
|
2996
|
+
// As terser's `forEach`: referencing appends to the list it reads.
|
|
2997
|
+
const { length } = references;
|
|
2998
|
+
for (let j = 0; j < length; j++) {
|
|
2999
|
+
const read = /** @type {PrintIdentifier} */ (
|
|
3000
|
+
/** @type {unknown} */ (references[j].identifier)
|
|
3001
|
+
);
|
|
3002
|
+
read.definition = variable;
|
|
3003
|
+
this._referenceVariable(
|
|
3004
|
+
read,
|
|
3005
|
+
/** @type {MinifierScope} */ (references[j].from),
|
|
3006
|
+
variable
|
|
3007
|
+
);
|
|
3008
|
+
}
|
|
3009
|
+
identifier.definition = variable;
|
|
3010
|
+
this._referenceVariable(identifier, catchScopes[i], variable);
|
|
3011
|
+
}
|
|
3012
|
+
const { forScopes } = this;
|
|
3013
|
+
for (let i = 0; i < forScopes.length; i++) {
|
|
3014
|
+
const forScope = forScopes[i];
|
|
3015
|
+
const variables = /** @type {MinifierScope} */ (forScope.upper).variables;
|
|
3016
|
+
for (let j = 0; j < variables.length; j++) {
|
|
3017
|
+
encloseUnique(forScope, /** @type {MinifierVariable} */ (variables[j]));
|
|
3018
|
+
}
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
}
|
|
3022
|
+
|
|
3023
|
+
/**
|
|
3024
|
+
* Analyses the minifier's tree with terser's scoping, which the names it
|
|
3025
|
+
* hands out depend on: see `MinifierScopeAnalyzer`.
|
|
3026
|
+
* @param {PrintProgram} program the tree, its names as written
|
|
3027
|
+
* @param {MinifierScopeOptions} options the mangle options
|
|
3028
|
+
* @param {(node: PrintNode, message: string, tables?: TokenTables) => never} raise throws the parse error a misplaced declaration is
|
|
3029
|
+
* @param {((node: PrintNode) => void)=} release drops what only the compressor read off each node read, where nobody keeps the tree
|
|
3030
|
+
* @returns {MinifierScopeAnalysis} the scopes
|
|
3031
|
+
*/
|
|
3032
|
+
const analyzeMinifierScope = (program, options, raise, release) => {
|
|
3033
|
+
const analyzer = new MinifierScopeAnalyzer(program, options, raise, release);
|
|
3034
|
+
if (release !== undefined) release(program);
|
|
3035
|
+
analyzer.stack.push(program);
|
|
3036
|
+
analyzer._visitList(program.body);
|
|
3037
|
+
analyzer.stack.pop();
|
|
3038
|
+
analyzer._resolveMinifier();
|
|
3039
|
+
return {
|
|
3040
|
+
toplevel: analyzer.toplevel,
|
|
3041
|
+
labels: analyzer.labels,
|
|
3042
|
+
globals: analyzer.globals,
|
|
3043
|
+
blockDefunScopes: analyzer.blockDefunScopes,
|
|
3044
|
+
functionDeclarators: analyzer.functionDeclarators,
|
|
3045
|
+
classDeclarators: analyzer.classDeclarators,
|
|
3046
|
+
catchParameters: analyzer.catchParameters,
|
|
3047
|
+
namesPrivate: analyzer.namesPrivate,
|
|
3048
|
+
spelledNames: analyzer.spelledNames
|
|
3049
|
+
};
|
|
3050
|
+
};
|
|
3051
|
+
|
|
3052
|
+
/**
|
|
3053
|
+
* @typedef {import("./syntax-parser").SyntaxTree} SyntaxTree
|
|
3054
|
+
* @typedef {MinifierVariable | MinifierLabel | null} TreeDefinition
|
|
3055
|
+
*/
|
|
3056
|
+
|
|
3057
|
+
/**
|
|
3058
|
+
* The scopes the minifier's analysis reads off a `SyntaxTree`: each name's
|
|
3059
|
+
* definition is held by its node's number.
|
|
3060
|
+
* @typedef {MinifierScopeAnalysis & { definitions: TreeDefinition[] }} MinifierTreeScopeAnalysis
|
|
3061
|
+
*/
|
|
3062
|
+
|
|
3063
|
+
// The tree's tables, read when a first tree is analysed: wherever webpack
|
|
3064
|
+
// reads a scope, requiring them would load the parser's data too.
|
|
3065
|
+
/** @type {typeof import("./data").NodeType} */
|
|
3066
|
+
let NodeType;
|
|
3067
|
+
/** @type {typeof import("./data").Field} */
|
|
3068
|
+
let Field;
|
|
3069
|
+
/** @type {typeof import("./data").Flag} */
|
|
3070
|
+
let Flag;
|
|
3071
|
+
/** @type {typeof import("./data").Part} */
|
|
3072
|
+
let Part;
|
|
3073
|
+
|
|
3074
|
+
/**
|
|
3075
|
+
* `MinifierScopeAnalyzer` over a `SyntaxTree` of the source terser's tree
|
|
3076
|
+
* was read from: the same walk, pushing the same nodes, so the same scopes,
|
|
3077
|
+
* definitions and orders. Neither `ie8` nor `safari10` is read.
|
|
3078
|
+
*/
|
|
3079
|
+
class MinifierTreeScopeAnalyzer {
|
|
3080
|
+
/**
|
|
3081
|
+
* @param {SyntaxTree} tree the tree
|
|
3082
|
+
* @param {number} program its program
|
|
3083
|
+
* @param {Uint8Array} types each node's type, as terser's tree types it
|
|
3084
|
+
* @param {MinifierScopeOptions} options the mangle options
|
|
3085
|
+
* @param {(node: number, message: string) => never} raise throws the parse error a misplaced import or export is
|
|
3086
|
+
*/
|
|
3087
|
+
constructor(tree, program, types, options, raise) {
|
|
3088
|
+
/** @type {SyntaxTree} */
|
|
3089
|
+
this.tree = tree;
|
|
3090
|
+
/** @type {Uint8Array} */
|
|
3091
|
+
this.types = types;
|
|
3092
|
+
/** @type {(node: number, message: string) => never} */
|
|
3093
|
+
this.raise = raise;
|
|
3094
|
+
/** @type {boolean} */
|
|
3095
|
+
this.parameterScopes = Boolean(options.parameterScopes);
|
|
3096
|
+
/** @type {MinifierScope[]} */
|
|
3097
|
+
this.parameterRanges = [];
|
|
3098
|
+
/** @type {MinifierScope} */
|
|
3099
|
+
this.toplevel = new MinifierScope(
|
|
3100
|
+
"global",
|
|
3101
|
+
/** @type {PrintNode} */ (/** @type {unknown} */ (program)),
|
|
3102
|
+
null,
|
|
3103
|
+
true
|
|
3104
|
+
);
|
|
3105
|
+
/** @type {MinifierScope} */
|
|
3106
|
+
this.scope = this.toplevel;
|
|
3107
|
+
/** @type {MinifierLabel[]} */
|
|
3108
|
+
this.labels = [];
|
|
3109
|
+
/** @type {Map<string, MinifierVariable>} */
|
|
3110
|
+
this.globals = new Map();
|
|
3111
|
+
/** @type {Set<MinifierScope>} */
|
|
3112
|
+
this.blockDefunScopes = new Set();
|
|
3113
|
+
/** @type {number[] | null} */
|
|
3114
|
+
this.functionDeclarators = options.keep_fnames ? [] : null;
|
|
3115
|
+
/** @type {number[] | null} */
|
|
3116
|
+
this.classDeclarators =
|
|
3117
|
+
options.classDeclarators && options.keep_classnames ? [] : null;
|
|
3118
|
+
/** @type {number[]} */
|
|
3119
|
+
this.referenceNodes = [];
|
|
3120
|
+
/** @type {MinifierScope[]} */
|
|
3121
|
+
this.referenceScopes = [];
|
|
3122
|
+
/** @type {number[]} */
|
|
3123
|
+
this.referenceFlags = [];
|
|
3124
|
+
/** @type {number[]} */
|
|
3125
|
+
this.catchParameters = [];
|
|
3126
|
+
/** @type {boolean} */
|
|
3127
|
+
this.namesPrivate = false;
|
|
3128
|
+
/** @type {number[]} the nodes terser's walk has pushed, 0 for an arrow's implicit `return` */
|
|
3129
|
+
this.stack = [];
|
|
3130
|
+
/** @type {boolean} */
|
|
3131
|
+
this.strict = Boolean(options.module);
|
|
3132
|
+
/** @type {Map<string, MinifierLabel>} */
|
|
3133
|
+
this.labelsInScope = new Map();
|
|
3134
|
+
/** @type {MinifierLabel | null} */
|
|
3135
|
+
this.currentLabel = null;
|
|
3136
|
+
/** @type {number} the pattern the walk is inside, 0 for none */
|
|
3137
|
+
this.inDestructuring = 0;
|
|
3138
|
+
// Filled in place: `Array.from` takes four times as long on a large tree.
|
|
3139
|
+
/** @type {TreeDefinition[]} */
|
|
3140
|
+
// eslint-disable-next-line unicorn/no-new-array
|
|
3141
|
+
this.definitions = new Array(types.length).fill(null);
|
|
3142
|
+
/** @type {number[] | null} each name with one spelled beside it */
|
|
3143
|
+
this.spelledIdentifiers = options.spelledNames ? [] : null;
|
|
3144
|
+
/** @type {string[]} the name spelled beside each */
|
|
3145
|
+
this.spellings = [];
|
|
3146
|
+
/** @type {number[]} the characters each pair saves */
|
|
3147
|
+
this.spelledSavings = [];
|
|
3148
|
+
/** @type {boolean} whether a key spells a name, which prints alone where it is its value's */
|
|
3149
|
+
this.spelledKeys = options.spelledNames === SPELLED_KEYS;
|
|
3150
|
+
}
|
|
3151
|
+
|
|
3152
|
+
/**
|
|
3153
|
+
* Collects a name and one spelled beside it, under `spelledNames`.
|
|
3154
|
+
* @param {number} identifier the name, 0 for none
|
|
3155
|
+
* @param {number} spelled what spells the other, 0 for none
|
|
3156
|
+
* @param {number} saving the characters it saves taking that name
|
|
3157
|
+
* @returns {void}
|
|
3158
|
+
*/
|
|
3159
|
+
_spell(identifier, spelled, saving) {
|
|
3160
|
+
const identifiers = this.spelledIdentifiers;
|
|
3161
|
+
const { types, tree } = this;
|
|
3162
|
+
if (
|
|
3163
|
+
identifiers === null ||
|
|
3164
|
+
identifier === 0 ||
|
|
3165
|
+
spelled === 0 ||
|
|
3166
|
+
types[identifier] !== NodeType.Identifier
|
|
3167
|
+
) {
|
|
3168
|
+
return;
|
|
3169
|
+
}
|
|
3170
|
+
/** @type {unknown} */
|
|
3171
|
+
let spelling;
|
|
3172
|
+
if (types[spelled] === NodeType.Identifier) {
|
|
3173
|
+
spelling = tree.name(spelled);
|
|
3174
|
+
} else if (types[spelled] === NodeType.Literal) {
|
|
3175
|
+
spelling = tree.value(spelled);
|
|
3176
|
+
}
|
|
3177
|
+
if (
|
|
3178
|
+
typeof spelling !== "string" ||
|
|
3179
|
+
!SPELLABLE_NAME.test(spelling) ||
|
|
3180
|
+
NAMES_NO_BINDING_TAKES.has(spelling) ||
|
|
3181
|
+
// A shorthand `__proto__` is an own property; `__proto__:` sets the prototype.
|
|
3182
|
+
spelling === "__proto__"
|
|
3183
|
+
) {
|
|
3184
|
+
return;
|
|
3185
|
+
}
|
|
3186
|
+
identifiers.push(identifier);
|
|
3187
|
+
this.spellings.push(spelling);
|
|
3188
|
+
this.spelledSavings.push(saving);
|
|
3189
|
+
}
|
|
3190
|
+
|
|
3191
|
+
/**
|
|
3192
|
+
* Collects a property's value named as its key could be, under `spelledNames`.
|
|
3193
|
+
* @param {number} property a property of an object or a pattern
|
|
3194
|
+
* @returns {void}
|
|
3195
|
+
*/
|
|
3196
|
+
_spellProperty(property) {
|
|
3197
|
+
const { tree } = this;
|
|
3198
|
+
if (!this.spelledKeys || tree.flag(Flag.computed, property)) {
|
|
3199
|
+
return;
|
|
3200
|
+
}
|
|
3201
|
+
const value = tree.field(0, Field.value, property);
|
|
3202
|
+
this._spell(
|
|
3203
|
+
this.types[value] === NodeType.AssignmentPattern
|
|
3204
|
+
? tree.field(0, Field.left, value)
|
|
3205
|
+
: value,
|
|
3206
|
+
tree.field(0, Field.key, property),
|
|
3207
|
+
SHORTHAND_SAVING
|
|
3208
|
+
);
|
|
3209
|
+
}
|
|
3210
|
+
|
|
3211
|
+
/**
|
|
3212
|
+
* @returns {SpelledNames | null} the names collected under `spelledNames`, resolved
|
|
3213
|
+
*/
|
|
3214
|
+
_spelledNames() {
|
|
3215
|
+
const identifiers = this.spelledIdentifiers;
|
|
3216
|
+
if (identifiers === null) return null;
|
|
3217
|
+
return {
|
|
3218
|
+
identifiers: this._asNames(identifiers),
|
|
3219
|
+
spellings: this.spellings,
|
|
3220
|
+
savings: this.spelledSavings
|
|
3221
|
+
};
|
|
3222
|
+
}
|
|
3223
|
+
|
|
3224
|
+
/**
|
|
3225
|
+
* @param {number} field the `Field`
|
|
3226
|
+
* @param {number} node a node
|
|
3227
|
+
* @param {number=} i the item's index, for a list
|
|
3228
|
+
* @returns {number} the node the field holds, past parentheses, 0 for none
|
|
3229
|
+
*/
|
|
3230
|
+
_child(field, node, i = 0) {
|
|
3231
|
+
const { tree } = this;
|
|
3232
|
+
let child = tree.field(i, field, node);
|
|
3233
|
+
while (
|
|
3234
|
+
child !== 0 &&
|
|
3235
|
+
tree.type(child) === NodeType.ParenthesizedExpression
|
|
3236
|
+
) {
|
|
3237
|
+
child = tree.field(0, Field.expression, child);
|
|
3238
|
+
}
|
|
3239
|
+
return child;
|
|
3240
|
+
}
|
|
3241
|
+
|
|
3242
|
+
/**
|
|
3243
|
+
* @param {number} field the `Field`, a list
|
|
3244
|
+
* @param {number} node a node
|
|
3245
|
+
* @returns {void}
|
|
3246
|
+
*/
|
|
3247
|
+
_visitList(field, node) {
|
|
3248
|
+
const count = this.tree.fieldCount(field, node);
|
|
3249
|
+
for (let i = 0; i < count; i++) {
|
|
3250
|
+
const child = this._child(field, node, i);
|
|
3251
|
+
if (child !== 0) this._visit(child);
|
|
3252
|
+
}
|
|
3253
|
+
}
|
|
3254
|
+
|
|
3255
|
+
/**
|
|
3256
|
+
* @param {number} field the `Field`
|
|
3257
|
+
* @param {number} node a node
|
|
3258
|
+
* @returns {void}
|
|
3259
|
+
*/
|
|
3260
|
+
_visitChild(field, node) {
|
|
3261
|
+
const child = this._child(field, node);
|
|
3262
|
+
if (child !== 0) this._visit(child);
|
|
3263
|
+
}
|
|
3264
|
+
|
|
3265
|
+
/**
|
|
3266
|
+
* @param {number} node a node
|
|
3267
|
+
* @returns {string} the name it is, a quoted module name's among them
|
|
3268
|
+
*/
|
|
3269
|
+
_nameOf(node) {
|
|
3270
|
+
const { tree } = this;
|
|
3271
|
+
return tree.type(node) === NodeType.Literal
|
|
3272
|
+
? String(tree.value(node))
|
|
3273
|
+
: tree.name(node);
|
|
3274
|
+
}
|
|
3275
|
+
|
|
3276
|
+
/**
|
|
3277
|
+
* @param {ScopeType} type what opens it
|
|
3278
|
+
* @param {number} node the node opening it
|
|
3279
|
+
* @param {boolean} isVarScope whether `var` hoists to here
|
|
3280
|
+
* @returns {MinifierScope} the scope, now current
|
|
3281
|
+
*/
|
|
3282
|
+
_open(type, node, isVarScope) {
|
|
3283
|
+
const scope = new MinifierScope(
|
|
3284
|
+
type,
|
|
3285
|
+
/** @type {PrintNode} */ (/** @type {unknown} */ (node)),
|
|
3286
|
+
this.scope,
|
|
3287
|
+
isVarScope
|
|
3288
|
+
);
|
|
3289
|
+
this.scope = scope;
|
|
3290
|
+
return scope;
|
|
3291
|
+
}
|
|
3292
|
+
|
|
3293
|
+
/**
|
|
3294
|
+
* @param {ScopeType} type what opens it
|
|
3295
|
+
* @param {number} node a block's node
|
|
3296
|
+
* @returns {MinifierScope} the scope it leaves
|
|
3297
|
+
*/
|
|
3298
|
+
_enterBlock(type, node) {
|
|
3299
|
+
const outer = this.scope;
|
|
3300
|
+
this._open(type, node, false).usesWith = outer.usesWith;
|
|
3301
|
+
return outer;
|
|
3302
|
+
}
|
|
3303
|
+
|
|
3304
|
+
/**
|
|
3305
|
+
* terser's `def_variable`.
|
|
3306
|
+
* @param {MinifierScope} target the scope declaring it
|
|
3307
|
+
* @param {number} identifier the name declaring it, 0 for none written
|
|
3308
|
+
* @param {string} name the name
|
|
3309
|
+
* @param {number} kind how it is declared
|
|
3310
|
+
* @returns {MinifierVariable} its definition, made or joined
|
|
3311
|
+
*/
|
|
3312
|
+
_defineVariable(target, identifier, name, kind) {
|
|
3313
|
+
let variable = /** @type {MinifierVariable | undefined} */ (
|
|
3314
|
+
target.getBinding(name)
|
|
3315
|
+
);
|
|
3316
|
+
if (variable !== undefined) {
|
|
3317
|
+
variable.declarations |= 1 << kind;
|
|
3318
|
+
} else {
|
|
3319
|
+
variable = new MinifierVariable(name, target, kind);
|
|
3320
|
+
variable.global = target.upper === null;
|
|
3321
|
+
addBinding(target, variable);
|
|
3322
|
+
}
|
|
3323
|
+
if (identifier !== 0) this.definitions[identifier] = variable;
|
|
3324
|
+
return variable;
|
|
3325
|
+
}
|
|
3326
|
+
|
|
3327
|
+
/**
|
|
3328
|
+
* @param {MinifierScope} from the scope reading it
|
|
3329
|
+
* @param {MinifierVariable} variable what it reads
|
|
3330
|
+
* @returns {void}
|
|
3331
|
+
*/
|
|
3332
|
+
_referenceVariable(from, variable) {
|
|
3333
|
+
variable.referenceCount++;
|
|
3334
|
+
encloseVariable(from, variable);
|
|
3335
|
+
}
|
|
3336
|
+
|
|
3337
|
+
/**
|
|
3338
|
+
* terser's `mark_export`, counting levels on the walk's stack.
|
|
3339
|
+
* @param {MinifierVariable} variable a definition just made
|
|
3340
|
+
* @param {number} level where its declaration's statement is
|
|
3341
|
+
* @returns {void}
|
|
3342
|
+
*/
|
|
3343
|
+
_markExport(variable, level) {
|
|
3344
|
+
const { stack } = this;
|
|
3345
|
+
if (this.inDestructuring !== 0) {
|
|
3346
|
+
let i = 0;
|
|
3347
|
+
do {
|
|
3348
|
+
level++;
|
|
3349
|
+
} while (stack[stack.length - 1 - i++] !== this.inDestructuring);
|
|
3350
|
+
}
|
|
3351
|
+
const node = stack[stack.length - 1 - level];
|
|
3352
|
+
const type = node === undefined ? 0 : this.types[node];
|
|
3353
|
+
if (
|
|
3354
|
+
type !== NodeType.ExportNamedDeclaration &&
|
|
3355
|
+
type !== NodeType.ExportDefaultDeclaration &&
|
|
3356
|
+
type !== NodeType.ExportAllDeclaration
|
|
3357
|
+
) {
|
|
3358
|
+
variable.export = 0;
|
|
3359
|
+
return;
|
|
3360
|
+
}
|
|
3361
|
+
variable.export =
|
|
3362
|
+
type === NodeType.ExportDefaultDeclaration && !this._exportsValue(node)
|
|
3363
|
+
? EXPORT_WANT_MANGLE
|
|
3364
|
+
: EXPORT_KEEP_NAME;
|
|
3365
|
+
}
|
|
3366
|
+
|
|
3367
|
+
/**
|
|
3368
|
+
* @param {number} node an `export default`
|
|
3369
|
+
* @returns {boolean} whether terser holds what it exports as a value, not a named declaration
|
|
3370
|
+
*/
|
|
3371
|
+
_exportsValue(node) {
|
|
3372
|
+
const declaration = this.tree.field(0, Field.declaration, node);
|
|
3373
|
+
const type = this.tree.type(declaration);
|
|
3374
|
+
return (
|
|
3375
|
+
(type !== NodeType.FunctionDeclaration &&
|
|
3376
|
+
type !== NodeType.ClassDeclaration) ||
|
|
3377
|
+
this.tree.field(0, Field.id, declaration) === 0
|
|
3378
|
+
);
|
|
3379
|
+
}
|
|
3380
|
+
|
|
3381
|
+
/**
|
|
3382
|
+
* @param {number} node an import or export
|
|
3383
|
+
* @param {string} type terser's name for it
|
|
3384
|
+
* @returns {void}
|
|
3385
|
+
*/
|
|
3386
|
+
_checkModuleStatement(node, type) {
|
|
3387
|
+
if (this.scope !== this.toplevel) {
|
|
3388
|
+
this.raise(node, `"${type}" statement may only appear at the top level`);
|
|
3389
|
+
}
|
|
3390
|
+
}
|
|
3391
|
+
|
|
3392
|
+
/**
|
|
3393
|
+
* @param {number} node a name read, or a re-exported string
|
|
3394
|
+
* @param {number} flags what else is known of it, as `REFERENCE_*` bits
|
|
3395
|
+
* @returns {void}
|
|
3396
|
+
*/
|
|
3397
|
+
_addReference(node, flags) {
|
|
3398
|
+
this.referenceNodes.push(node);
|
|
3399
|
+
this.referenceScopes.push(this.scope);
|
|
3400
|
+
this.referenceFlags.push(flags);
|
|
3401
|
+
}
|
|
3402
|
+
|
|
3403
|
+
/**
|
|
3404
|
+
* A name a declaration or a pattern binds, or reads where `kind` is 0.
|
|
3405
|
+
* @param {number} node the name or pattern
|
|
3406
|
+
* @param {number} kind how it declares, as a `DECLARES_*` code, or 0
|
|
3407
|
+
* @returns {void}
|
|
3408
|
+
*/
|
|
3409
|
+
_visitBinding(node, kind) {
|
|
3410
|
+
const { stack } = this;
|
|
3411
|
+
switch (this.types[node]) {
|
|
3412
|
+
case NodeType.Identifier:
|
|
3413
|
+
if (kind === 0) this._visit(node);
|
|
3414
|
+
else this._declare(node, kind);
|
|
3415
|
+
return;
|
|
3416
|
+
case NodeType.ObjectPattern:
|
|
3417
|
+
this._visitPattern(node, Field.properties, kind);
|
|
3418
|
+
return;
|
|
3419
|
+
case NodeType.ArrayPattern:
|
|
3420
|
+
this._visitPattern(node, Field.elements, kind);
|
|
3421
|
+
return;
|
|
3422
|
+
case NodeType.AssignmentPattern:
|
|
3423
|
+
stack.push(node);
|
|
3424
|
+
this._visitBinding(this._child(Field.left, node), kind);
|
|
3425
|
+
this._visit(this._child(Field.right, node));
|
|
3426
|
+
stack.pop();
|
|
3427
|
+
return;
|
|
3428
|
+
case NodeType.RestElement:
|
|
3429
|
+
stack.push(node);
|
|
3430
|
+
this._visitBinding(this._child(Field.argument, node), kind);
|
|
3431
|
+
stack.pop();
|
|
3432
|
+
return;
|
|
3433
|
+
default:
|
|
3434
|
+
this._visit(node);
|
|
3435
|
+
}
|
|
3436
|
+
}
|
|
3437
|
+
|
|
3438
|
+
/**
|
|
3439
|
+
* @param {number} pattern an object or array pattern
|
|
3440
|
+
* @param {number} field its properties or elements
|
|
3441
|
+
* @param {number} kind how it declares, as a `DECLARES_*` code, or 0
|
|
3442
|
+
* @returns {void}
|
|
3443
|
+
*/
|
|
3444
|
+
_visitPattern(pattern, field, kind) {
|
|
3445
|
+
const { stack, tree } = this;
|
|
3446
|
+
const outer = this.inDestructuring;
|
|
3447
|
+
this.inDestructuring = pattern;
|
|
3448
|
+
stack.push(pattern);
|
|
3449
|
+
const count = tree.fieldCount(field, pattern);
|
|
3450
|
+
for (let i = 0; i < count; i++) {
|
|
3451
|
+
const element = this._child(field, pattern, i);
|
|
3452
|
+
if (element === 0) continue;
|
|
3453
|
+
if (this.types[element] !== NodeType.Property) {
|
|
3454
|
+
this._visitBinding(element, kind);
|
|
3455
|
+
continue;
|
|
3456
|
+
}
|
|
3457
|
+
stack.push(element);
|
|
3458
|
+
if (tree.flag(Flag.computed, element)) {
|
|
3459
|
+
this._visitChild(Field.key, element);
|
|
3460
|
+
}
|
|
3461
|
+
this._visitBinding(this._child(Field.value, element), kind);
|
|
3462
|
+
this._spellProperty(element);
|
|
3463
|
+
stack.pop();
|
|
3464
|
+
}
|
|
3465
|
+
stack.pop();
|
|
3466
|
+
this.inDestructuring = outer;
|
|
3467
|
+
}
|
|
3468
|
+
|
|
3469
|
+
/**
|
|
3470
|
+
* A `var`, parameter, `let`, `const`, `using`, catch parameter or import.
|
|
3471
|
+
* @param {number} identifier the name declared
|
|
3472
|
+
* @param {number} kind how, as a `DECLARES_*` code
|
|
3473
|
+
* @returns {void}
|
|
3474
|
+
*/
|
|
3475
|
+
_declare(identifier, kind) {
|
|
3476
|
+
const name = this.tree.name(identifier);
|
|
3477
|
+
const { scope } = this;
|
|
3478
|
+
if (kind === DECLARES_IMPORT) {
|
|
3479
|
+
this._defineVariable(scope, identifier, name, kind);
|
|
3480
|
+
return;
|
|
3481
|
+
}
|
|
3482
|
+
const blockDeclaration =
|
|
3483
|
+
kind === DECLARES_LET ||
|
|
3484
|
+
kind === DECLARES_CONST ||
|
|
3485
|
+
kind === DECLARES_USING ||
|
|
3486
|
+
kind === DECLARES_CATCH;
|
|
3487
|
+
const defun = /** @type {MinifierScope} */ (scope.variableScope);
|
|
3488
|
+
// A redeclaration terser refuses here the tree's parser refused first.
|
|
3489
|
+
const variable = this._defineVariable(
|
|
3490
|
+
blockDeclaration ? scope : defun,
|
|
3491
|
+
identifier,
|
|
3492
|
+
name,
|
|
3493
|
+
kind
|
|
3494
|
+
);
|
|
3495
|
+
if (kind !== DECLARES_FUNARG) this._markExport(variable, 2);
|
|
3496
|
+
if (defun !== scope) {
|
|
3497
|
+
encloseVariable(scope, variable);
|
|
3498
|
+
const found = /** @type {MinifierVariable} */ (
|
|
3499
|
+
findMinifierVariable(scope, name)
|
|
3500
|
+
);
|
|
3501
|
+
if (found !== variable) {
|
|
3502
|
+
this.definitions[identifier] = found;
|
|
3503
|
+
this._referenceVariable(scope, found);
|
|
3504
|
+
}
|
|
3505
|
+
}
|
|
3506
|
+
if (kind === DECLARES_CATCH) {
|
|
3507
|
+
this._addReference(identifier, REFERENCE_CATCH);
|
|
3508
|
+
this.catchParameters.push(identifier);
|
|
3509
|
+
}
|
|
3510
|
+
}
|
|
3511
|
+
|
|
3512
|
+
/**
|
|
3513
|
+
* @param {number} node a binding pattern, 0 for an array's hole
|
|
3514
|
+
* @param {string} name a name
|
|
3515
|
+
* @returns {boolean} whether the pattern binds the name
|
|
3516
|
+
*/
|
|
3517
|
+
_bindsName(node, name) {
|
|
3518
|
+
if (node === 0) return false;
|
|
3519
|
+
const { tree } = this;
|
|
3520
|
+
switch (this.types[node]) {
|
|
3521
|
+
case NodeType.ObjectPattern:
|
|
3522
|
+
return this._someChild(Field.properties, node, (property) =>
|
|
3523
|
+
this._bindsName(
|
|
3524
|
+
this.types[property] === NodeType.Property
|
|
3525
|
+
? this._child(Field.value, property)
|
|
3526
|
+
: property,
|
|
3527
|
+
name
|
|
3528
|
+
)
|
|
3529
|
+
);
|
|
3530
|
+
case NodeType.ArrayPattern:
|
|
3531
|
+
return this._someChild(Field.elements, node, (element) =>
|
|
3532
|
+
this._bindsName(element, name)
|
|
3533
|
+
);
|
|
3534
|
+
case NodeType.AssignmentPattern:
|
|
3535
|
+
return this._bindsName(this._child(Field.left, node), name);
|
|
3536
|
+
case NodeType.RestElement:
|
|
3537
|
+
return this._bindsName(this._child(Field.argument, node), name);
|
|
3538
|
+
default:
|
|
3539
|
+
return tree.name(node) === name;
|
|
3540
|
+
}
|
|
3541
|
+
}
|
|
3542
|
+
|
|
3543
|
+
/**
|
|
3544
|
+
* @param {number} field the `Field`, a list
|
|
3545
|
+
* @param {number} node a node
|
|
3546
|
+
* @param {(child: number) => boolean} test what a child is asked
|
|
3547
|
+
* @returns {boolean} whether it holds for a child, holes 0
|
|
3548
|
+
*/
|
|
3549
|
+
_someChild(field, node, test) {
|
|
3550
|
+
const count = this.tree.fieldCount(field, node);
|
|
3551
|
+
for (let i = 0; i < count; i++) {
|
|
3552
|
+
if (test(this._child(field, node, i))) return true;
|
|
3553
|
+
}
|
|
3554
|
+
return false;
|
|
3555
|
+
}
|
|
3556
|
+
|
|
3557
|
+
/**
|
|
3558
|
+
* @param {number} node a statement, or a loop's head, 0 for none
|
|
3559
|
+
* @param {string} name a name
|
|
3560
|
+
* @returns {boolean} whether it declares the name with `let`, `const`, `using` or a class
|
|
3561
|
+
*/
|
|
3562
|
+
_declaresLexically(node, name) {
|
|
3563
|
+
if (node === 0) return false;
|
|
3564
|
+
const { tree } = this;
|
|
3565
|
+
const type = this.types[node];
|
|
3566
|
+
if (type === NodeType.VariableDeclaration) {
|
|
3567
|
+
return (
|
|
3568
|
+
tree.textOf(Part.kind, node) !== "var" &&
|
|
3569
|
+
this._someChild(Field.declarations, node, (declarator) =>
|
|
3570
|
+
this._bindsName(tree.field(0, Field.id, declarator), name)
|
|
3571
|
+
)
|
|
3572
|
+
);
|
|
3573
|
+
}
|
|
3574
|
+
return (
|
|
3575
|
+
type === NodeType.ClassDeclaration &&
|
|
3576
|
+
tree.name(tree.field(0, Field.id, node)) === name
|
|
3577
|
+
);
|
|
3578
|
+
}
|
|
3579
|
+
|
|
3580
|
+
/**
|
|
3581
|
+
* @param {number} owner a node listing statements
|
|
3582
|
+
* @param {number} field the `Field` listing them
|
|
3583
|
+
* @param {string} name a name
|
|
3584
|
+
* @returns {boolean} whether one of them declares it lexically
|
|
3585
|
+
*/
|
|
3586
|
+
_listDeclaresLexically(owner, field, name) {
|
|
3587
|
+
const count = this.tree.fieldCount(field, owner);
|
|
3588
|
+
for (let i = 0; i < count; i++) {
|
|
3589
|
+
if (this._declaresLexically(this.tree.field(i, field, owner), name)) {
|
|
3590
|
+
return true;
|
|
3591
|
+
}
|
|
3592
|
+
}
|
|
3593
|
+
return false;
|
|
3594
|
+
}
|
|
3595
|
+
|
|
3596
|
+
/**
|
|
3597
|
+
* Annex B's test for a sloppy block's function: a `var` of its name would be
|
|
3598
|
+
* an early error, which keeps the function in its block.
|
|
3599
|
+
* @param {MinifierScope} scope the scope the function is declared in
|
|
3600
|
+
* @param {string} name the function's name
|
|
3601
|
+
* @returns {boolean} true for `f` in `{ let f; { function f() {} } }`
|
|
3602
|
+
*/
|
|
3603
|
+
_keepsInBlock(scope, name) {
|
|
3604
|
+
const { tree } = this;
|
|
3605
|
+
while (scope !== scope.variableScope) {
|
|
3606
|
+
const node = /** @type {number} */ (/** @type {unknown} */ (scope.node));
|
|
3607
|
+
switch (this.types[node]) {
|
|
3608
|
+
case NodeType.BlockStatement:
|
|
3609
|
+
if (this._listDeclaresLexically(node, Field.body, name)) return true;
|
|
3610
|
+
break;
|
|
3611
|
+
case NodeType.SwitchStatement: {
|
|
3612
|
+
const count = tree.fieldCount(Field.cases, node);
|
|
3613
|
+
for (let i = 0; i < count; i++) {
|
|
3614
|
+
const branch = tree.field(i, Field.cases, node);
|
|
3615
|
+
if (this._listDeclaresLexically(branch, Field.consequent, name)) {
|
|
3616
|
+
return true;
|
|
3617
|
+
}
|
|
3618
|
+
}
|
|
3619
|
+
break;
|
|
3620
|
+
}
|
|
3621
|
+
case NodeType.ForStatement:
|
|
3622
|
+
if (this._declaresLexically(this._child(Field.init, node), name)) {
|
|
3623
|
+
return true;
|
|
3624
|
+
}
|
|
3625
|
+
break;
|
|
3626
|
+
case NodeType.ForInStatement:
|
|
3627
|
+
case NodeType.ForOfStatement:
|
|
3628
|
+
if (this._declaresLexically(this._child(Field.left, node), name)) {
|
|
3629
|
+
return true;
|
|
3630
|
+
}
|
|
3631
|
+
break;
|
|
3632
|
+
case NodeType.CatchClause: {
|
|
3633
|
+
const param = tree.field(0, Field.param, node);
|
|
3634
|
+
if (
|
|
3635
|
+
(param !== 0 &&
|
|
3636
|
+
this.types[param] !== NodeType.Identifier &&
|
|
3637
|
+
this._bindsName(param, name)) ||
|
|
3638
|
+
this._listDeclaresLexically(
|
|
3639
|
+
tree.field(0, Field.body, node),
|
|
3640
|
+
Field.body,
|
|
3641
|
+
name
|
|
3642
|
+
)
|
|
3643
|
+
) {
|
|
3644
|
+
return true;
|
|
3645
|
+
}
|
|
3646
|
+
break;
|
|
3647
|
+
}
|
|
3648
|
+
}
|
|
3649
|
+
scope = /** @type {MinifierScope} */ (scope.upper);
|
|
3650
|
+
}
|
|
3651
|
+
const node = /** @type {number} */ (/** @type {unknown} */ (scope.node));
|
|
3652
|
+
if (this.types[node] === NodeType.Program) {
|
|
3653
|
+
return this._listDeclaresLexically(node, Field.body, name);
|
|
3654
|
+
}
|
|
3655
|
+
// A function holding a statement has a block for its body.
|
|
3656
|
+
return (
|
|
3657
|
+
this._someChild(Field.params, node, (param) =>
|
|
3658
|
+
this._bindsName(param, name)
|
|
3659
|
+
) ||
|
|
3660
|
+
this._listDeclaresLexically(
|
|
3661
|
+
this._child(Field.body, node),
|
|
3662
|
+
Field.body,
|
|
3663
|
+
name
|
|
3664
|
+
)
|
|
3665
|
+
);
|
|
3666
|
+
}
|
|
3667
|
+
|
|
3668
|
+
/**
|
|
3669
|
+
* @param {number} node a function
|
|
3670
|
+
* @returns {void}
|
|
3671
|
+
*/
|
|
3672
|
+
_visitFunction(node) {
|
|
3673
|
+
const { stack, tree } = this;
|
|
3674
|
+
const outerStrict = this.strict;
|
|
3675
|
+
const outer = this.scope;
|
|
3676
|
+
const outerLabels = this.labelsInScope;
|
|
3677
|
+
const type = this.types[node];
|
|
3678
|
+
const parentType = this.types[stack[stack.length - 1]];
|
|
3679
|
+
const inBlock =
|
|
3680
|
+
type === NodeType.FunctionDeclaration &&
|
|
3681
|
+
parentType !== NodeType.Program &&
|
|
3682
|
+
parentType !== NodeType.FunctionDeclaration &&
|
|
3683
|
+
parentType !== NodeType.FunctionExpression &&
|
|
3684
|
+
parentType !== NodeType.ArrowFunctionExpression &&
|
|
3685
|
+
parentType !== NodeType.StaticBlock;
|
|
3686
|
+
if (inBlock) {
|
|
3687
|
+
this.blockDefunScopes.add(
|
|
3688
|
+
/** @type {MinifierScope} */ (outer.variableScope)
|
|
3689
|
+
);
|
|
3690
|
+
}
|
|
3691
|
+
stack.push(node);
|
|
3692
|
+
const lambda = this._open("function", node, true);
|
|
3693
|
+
if (type !== NodeType.ArrowFunctionExpression) {
|
|
3694
|
+
this._defineVariable(lambda, 0, "arguments", DECLARES_FUNARG);
|
|
3695
|
+
}
|
|
3696
|
+
this.labelsInScope = new Map();
|
|
3697
|
+
const id = tree.field(0, Field.id, node);
|
|
3698
|
+
if (id === 0) {
|
|
3699
|
+
// An arrow or a method has no name of its own.
|
|
3700
|
+
} else if (type === NodeType.FunctionDeclaration) {
|
|
3701
|
+
const name = tree.name(id);
|
|
3702
|
+
this._markExport(
|
|
3703
|
+
this._defineVariable(
|
|
3704
|
+
// Annex B hoists a sloppy block's plain function only.
|
|
3705
|
+
this.strict ||
|
|
3706
|
+
(this.parameterScopes &&
|
|
3707
|
+
(tree.flag(Flag.async, node) ||
|
|
3708
|
+
tree.flag(Flag.generator, node) ||
|
|
3709
|
+
(inBlock && this._keepsInBlock(outer, name))))
|
|
3710
|
+
? outer
|
|
3711
|
+
: /** @type {MinifierScope} */ (outer.variableScope),
|
|
3712
|
+
id,
|
|
3713
|
+
name,
|
|
3714
|
+
DECLARES_DEFUN
|
|
3715
|
+
),
|
|
3716
|
+
1
|
|
3717
|
+
);
|
|
3718
|
+
} else {
|
|
3719
|
+
this._defineVariable(lambda, id, tree.name(id), DECLARES_LAMBDA);
|
|
3720
|
+
lambda.functionName = /** @type {MinifierVariable} */ (
|
|
3721
|
+
this.definitions[id]
|
|
3722
|
+
);
|
|
3723
|
+
}
|
|
3724
|
+
const params = tree.fieldCount(Field.params, node);
|
|
3725
|
+
const ranged = this.parameterScopes && params !== 0;
|
|
3726
|
+
if (ranged) {
|
|
3727
|
+
lambda.parameterStart = this.referenceNodes.length;
|
|
3728
|
+
this.parameterRanges.push(lambda);
|
|
3729
|
+
}
|
|
3730
|
+
for (let i = 0; i < params; i++) {
|
|
3731
|
+
this._visitBinding(this._child(Field.params, node, i), DECLARES_FUNARG);
|
|
3732
|
+
}
|
|
3733
|
+
if (ranged) lambda.parameterEnd = this.referenceNodes.length;
|
|
3734
|
+
const body = this._child(Field.body, node);
|
|
3735
|
+
if (this.types[body] === NodeType.BlockStatement) {
|
|
3736
|
+
this._visitList(Field.body, body);
|
|
3737
|
+
} else {
|
|
3738
|
+
// terser's arrow returns its expression from a statement of its own.
|
|
3739
|
+
stack.push(0);
|
|
3740
|
+
this._visit(body);
|
|
3741
|
+
stack.pop();
|
|
3742
|
+
}
|
|
3743
|
+
this.scope = outer;
|
|
3744
|
+
this.labelsInScope = outerLabels;
|
|
3745
|
+
this.strict = outerStrict;
|
|
3746
|
+
stack.pop();
|
|
3747
|
+
}
|
|
3748
|
+
|
|
3749
|
+
/**
|
|
3750
|
+
* @param {number} node a class
|
|
3751
|
+
* @returns {void}
|
|
3752
|
+
*/
|
|
3753
|
+
_visitClass(node) {
|
|
3754
|
+
const { tree } = this;
|
|
3755
|
+
const outerStrict = this.strict;
|
|
3756
|
+
const outer = this.scope;
|
|
3757
|
+
const outerLabels = this.labelsInScope;
|
|
3758
|
+
this.stack.push(node);
|
|
3759
|
+
this.strict = true;
|
|
3760
|
+
const classScope = this._open("class", node, true);
|
|
3761
|
+
this.labelsInScope = new Map();
|
|
3762
|
+
const id = tree.field(0, Field.id, node);
|
|
3763
|
+
if (id !== 0) {
|
|
3764
|
+
const name = tree.name(id);
|
|
3765
|
+
this._markExport(
|
|
3766
|
+
this.types[node] === NodeType.ClassDeclaration
|
|
3767
|
+
? this._defineVariable(outer, id, name, DECLARES_DEF_CLASS)
|
|
3768
|
+
: this._defineVariable(classScope, id, name, DECLARES_CLASS),
|
|
3769
|
+
1
|
|
3770
|
+
);
|
|
3771
|
+
}
|
|
3772
|
+
this._visitChild(Field.superClass, node);
|
|
3773
|
+
this._visitList(Field.body, tree.field(0, Field.body, node));
|
|
3774
|
+
this.scope = outer;
|
|
3775
|
+
this.labelsInScope = outerLabels;
|
|
3776
|
+
this.strict = outerStrict;
|
|
3777
|
+
this.stack.pop();
|
|
3778
|
+
}
|
|
3779
|
+
|
|
3780
|
+
/**
|
|
3781
|
+
* @param {number} node a `var`, `let`, `const` or `using`
|
|
3782
|
+
* @returns {void}
|
|
3783
|
+
*/
|
|
3784
|
+
_visitDeclaration(node) {
|
|
3785
|
+
const { stack, tree, functionDeclarators, classDeclarators } = this;
|
|
3786
|
+
const text = tree.textOf(Part.kind, node);
|
|
3787
|
+
const kind =
|
|
3788
|
+
text === "var"
|
|
3789
|
+
? DECLARES_VAR
|
|
3790
|
+
: text === "let"
|
|
3791
|
+
? DECLARES_LET
|
|
3792
|
+
: text === "const"
|
|
3793
|
+
? DECLARES_CONST
|
|
3794
|
+
: DECLARES_USING;
|
|
3795
|
+
stack.push(node);
|
|
3796
|
+
const count = tree.fieldCount(Field.declarations, node);
|
|
3797
|
+
for (let i = 0; i < count; i++) {
|
|
3798
|
+
const declarator = tree.field(i, Field.declarations, node);
|
|
3799
|
+
const id = tree.field(0, Field.id, declarator);
|
|
3800
|
+
const init = this._child(Field.init, declarator);
|
|
3801
|
+
if (
|
|
3802
|
+
functionDeclarators !== null &&
|
|
3803
|
+
kind !== DECLARES_USING &&
|
|
3804
|
+
this.types[id] === NodeType.Identifier &&
|
|
3805
|
+
init !== 0 &&
|
|
3806
|
+
(this.types[init] === NodeType.FunctionExpression ||
|
|
3807
|
+
this.types[init] === NodeType.ArrowFunctionExpression) &&
|
|
3808
|
+
tree.field(0, Field.id, init) === 0
|
|
3809
|
+
) {
|
|
3810
|
+
functionDeclarators.push(id);
|
|
3811
|
+
} else if (
|
|
3812
|
+
classDeclarators !== null &&
|
|
3813
|
+
kind !== DECLARES_USING &&
|
|
3814
|
+
this.types[id] === NodeType.Identifier &&
|
|
3815
|
+
init !== 0 &&
|
|
3816
|
+
this.types[init] === NodeType.ClassExpression &&
|
|
3817
|
+
tree.field(0, Field.id, init) === 0
|
|
3818
|
+
) {
|
|
3819
|
+
classDeclarators.push(id);
|
|
3820
|
+
}
|
|
3821
|
+
stack.push(declarator);
|
|
3822
|
+
this._visitBinding(id, kind);
|
|
3823
|
+
if (init !== 0) this._visit(init);
|
|
3824
|
+
stack.pop();
|
|
3825
|
+
}
|
|
3826
|
+
stack.pop();
|
|
3827
|
+
}
|
|
3828
|
+
|
|
3829
|
+
/**
|
|
3830
|
+
* A loop's children, its scope entered.
|
|
3831
|
+
* @param {number} node the loop
|
|
3832
|
+
* @returns {void}
|
|
3833
|
+
*/
|
|
3834
|
+
_visitLoop(node) {
|
|
3835
|
+
switch (this.types[node]) {
|
|
3836
|
+
case NodeType.ForStatement:
|
|
3837
|
+
this._visitChild(Field.init, node);
|
|
3838
|
+
this._visitChild(Field.test, node);
|
|
3839
|
+
this._visitChild(Field.update, node);
|
|
3840
|
+
break;
|
|
3841
|
+
case NodeType.WhileStatement:
|
|
3842
|
+
this._visitChild(Field.test, node);
|
|
3843
|
+
break;
|
|
3844
|
+
case NodeType.DoWhileStatement:
|
|
3845
|
+
this._visitChild(Field.body, node);
|
|
3846
|
+
this._visitChild(Field.test, node);
|
|
3847
|
+
return;
|
|
3848
|
+
default:
|
|
3849
|
+
this._visitBinding(this._child(Field.left, node), 0);
|
|
3850
|
+
this._visitChild(Field.right, node);
|
|
3851
|
+
}
|
|
3852
|
+
this._visitChild(Field.body, node);
|
|
3853
|
+
}
|
|
3854
|
+
|
|
3855
|
+
/**
|
|
3856
|
+
* Reads one node as `MinifierScopeAnalyzer#_visitPrint` reads terser's.
|
|
3857
|
+
* @param {number} node node to visit
|
|
3858
|
+
* @returns {void}
|
|
3859
|
+
*/
|
|
3860
|
+
_visit(node) {
|
|
3861
|
+
const { stack, tree } = this;
|
|
3862
|
+
const type = this.types[node];
|
|
3863
|
+
switch (type) {
|
|
3864
|
+
case NodeType.Identifier: {
|
|
3865
|
+
// A number too large for a double, which terser holds as an atom.
|
|
3866
|
+
if (tree.type(node) !== NodeType.Identifier) return;
|
|
3867
|
+
const parentType = this.types[stack[stack.length - 1]];
|
|
3868
|
+
this._addReference(
|
|
3869
|
+
node,
|
|
3870
|
+
tree.name(node) === "eval" &&
|
|
3871
|
+
(parentType === NodeType.CallExpression ||
|
|
3872
|
+
parentType === NodeType.NewExpression)
|
|
3873
|
+
? REFERENCE_CALLED
|
|
3874
|
+
: 0
|
|
3875
|
+
);
|
|
3876
|
+
return;
|
|
3877
|
+
}
|
|
3878
|
+
case NodeType.MemberExpression: {
|
|
3879
|
+
stack.push(node);
|
|
3880
|
+
this._visitChild(Field.object, node);
|
|
3881
|
+
const property = this._child(Field.property, node);
|
|
3882
|
+
if (tree.flag(Flag.computed, node)) {
|
|
3883
|
+
this._visit(property);
|
|
3884
|
+
} else if (tree.type(property) === NodeType.PrivateIdentifier) {
|
|
3885
|
+
this.namesPrivate = true;
|
|
3886
|
+
}
|
|
3887
|
+
stack.pop();
|
|
3888
|
+
return;
|
|
3889
|
+
}
|
|
3890
|
+
case NodeType.CallExpression:
|
|
3891
|
+
case NodeType.NewExpression:
|
|
3892
|
+
// terser's walk reaches the arguments first.
|
|
3893
|
+
stack.push(node);
|
|
3894
|
+
this._visitList(Field.arguments, node);
|
|
3895
|
+
this._visitChild(Field.callee, node);
|
|
3896
|
+
stack.pop();
|
|
3897
|
+
return;
|
|
3898
|
+
case NodeType.Literal:
|
|
3899
|
+
case NodeType.ThisExpression:
|
|
3900
|
+
return;
|
|
3901
|
+
case NodeType.ExpressionStatement: {
|
|
3902
|
+
const directive = tree.textOf(Part.directive, node);
|
|
3903
|
+
if (directive !== null) {
|
|
3904
|
+
if (directive === "use strict") this.strict = true;
|
|
3905
|
+
return;
|
|
3906
|
+
}
|
|
3907
|
+
stack.push(node);
|
|
3908
|
+
this._visitChild(Field.expression, node);
|
|
3909
|
+
stack.pop();
|
|
3910
|
+
return;
|
|
3911
|
+
}
|
|
3912
|
+
case NodeType.BinaryExpression:
|
|
3913
|
+
case NodeType.LogicalExpression:
|
|
3914
|
+
case NodeType.AssignmentExpression:
|
|
3915
|
+
stack.push(node);
|
|
3916
|
+
this._visitChild(Field.left, node);
|
|
3917
|
+
this._visitChild(Field.right, node);
|
|
3918
|
+
stack.pop();
|
|
3919
|
+
return;
|
|
3920
|
+
case NodeType.BlockStatement: {
|
|
3921
|
+
stack.push(node);
|
|
3922
|
+
const outer = this._enterBlock("block", node);
|
|
3923
|
+
this._visitList(Field.body, node);
|
|
3924
|
+
this.scope = outer;
|
|
3925
|
+
stack.pop();
|
|
3926
|
+
return;
|
|
3927
|
+
}
|
|
3928
|
+
case NodeType.ReturnStatement:
|
|
3929
|
+
case NodeType.UnaryExpression:
|
|
3930
|
+
case NodeType.UpdateExpression:
|
|
3931
|
+
case NodeType.ThrowStatement:
|
|
3932
|
+
case NodeType.AwaitExpression:
|
|
3933
|
+
case NodeType.SpreadElement:
|
|
3934
|
+
case NodeType.YieldExpression:
|
|
3935
|
+
stack.push(node);
|
|
3936
|
+
this._visitChild(Field.argument, node);
|
|
3937
|
+
stack.pop();
|
|
3938
|
+
return;
|
|
3939
|
+
case NodeType.VariableDeclaration:
|
|
3940
|
+
this._visitDeclaration(node);
|
|
3941
|
+
return;
|
|
3942
|
+
case NodeType.FunctionDeclaration:
|
|
3943
|
+
case NodeType.FunctionExpression:
|
|
3944
|
+
case NodeType.ArrowFunctionExpression:
|
|
3945
|
+
this._visitFunction(node);
|
|
3946
|
+
return;
|
|
3947
|
+
case NodeType.ClassDeclaration:
|
|
3948
|
+
case NodeType.ClassExpression:
|
|
3949
|
+
this._visitClass(node);
|
|
3950
|
+
return;
|
|
3951
|
+
case NodeType.ForStatement:
|
|
3952
|
+
case NodeType.ForInStatement:
|
|
3953
|
+
case NodeType.ForOfStatement:
|
|
3954
|
+
case NodeType.WhileStatement:
|
|
3955
|
+
case NodeType.DoWhileStatement: {
|
|
3956
|
+
stack.push(node);
|
|
3957
|
+
const outer = this._enterBlock(
|
|
3958
|
+
type === NodeType.WhileStatement || type === NodeType.DoWhileStatement
|
|
3959
|
+
? "block"
|
|
3960
|
+
: "for",
|
|
3961
|
+
node
|
|
3962
|
+
);
|
|
3963
|
+
this._visitLoop(node);
|
|
3964
|
+
this.scope = outer;
|
|
3965
|
+
stack.pop();
|
|
3966
|
+
return;
|
|
3967
|
+
}
|
|
3968
|
+
case NodeType.SwitchStatement: {
|
|
3969
|
+
stack.push(node);
|
|
3970
|
+
const outer = this._enterBlock("switch", node);
|
|
3971
|
+
// The switched expression belongs to the scope around the switch.
|
|
3972
|
+
const block = this.scope;
|
|
3973
|
+
this.scope = outer;
|
|
3974
|
+
this._visitChild(Field.discriminant, node);
|
|
3975
|
+
this.scope = block;
|
|
3976
|
+
this._visitList(Field.cases, node);
|
|
3977
|
+
this.scope = outer;
|
|
3978
|
+
stack.pop();
|
|
3979
|
+
return;
|
|
3980
|
+
}
|
|
3981
|
+
case NodeType.CatchClause: {
|
|
3982
|
+
stack.push(node);
|
|
3983
|
+
const outer = this._enterBlock("catch", node);
|
|
3984
|
+
const catchScope = this.scope;
|
|
3985
|
+
const param = tree.field(0, Field.param, node);
|
|
3986
|
+
const ranged = this.parameterScopes && param !== 0;
|
|
3987
|
+
if (ranged) {
|
|
3988
|
+
catchScope.parameterStart = this.referenceNodes.length;
|
|
3989
|
+
this.parameterRanges.push(catchScope);
|
|
3990
|
+
}
|
|
3991
|
+
if (param !== 0) this._visitBinding(param, DECLARES_CATCH);
|
|
3992
|
+
if (ranged) catchScope.parameterEnd = this.referenceNodes.length;
|
|
3993
|
+
this._visitList(Field.body, tree.field(0, Field.body, node));
|
|
3994
|
+
this.scope = outer;
|
|
3995
|
+
stack.pop();
|
|
3996
|
+
return;
|
|
3997
|
+
}
|
|
3998
|
+
case NodeType.StaticBlock: {
|
|
3999
|
+
const outer = this.scope;
|
|
4000
|
+
const outerLabels = this.labelsInScope;
|
|
4001
|
+
stack.push(node);
|
|
4002
|
+
this._open("class-static-block", node, true);
|
|
4003
|
+
this.labelsInScope = new Map();
|
|
4004
|
+
this._visitList(Field.body, node);
|
|
4005
|
+
this.scope = outer;
|
|
4006
|
+
this.labelsInScope = outerLabels;
|
|
4007
|
+
stack.pop();
|
|
4008
|
+
return;
|
|
4009
|
+
}
|
|
4010
|
+
case NodeType.LabeledStatement: {
|
|
4011
|
+
// The tree's parser refuses a label defined twice or undefined.
|
|
4012
|
+
const labelName = tree.field(0, Field.label, node);
|
|
4013
|
+
const name = tree.name(labelName);
|
|
4014
|
+
const label = new MinifierLabel(name, this.currentLabel);
|
|
4015
|
+
this.labels.push(label);
|
|
4016
|
+
this.definitions[labelName] = label;
|
|
4017
|
+
this.labelsInScope.set(name, label);
|
|
4018
|
+
stack.push(node);
|
|
4019
|
+
this.currentLabel = label;
|
|
4020
|
+
this._visitChild(Field.body, node);
|
|
4021
|
+
this.currentLabel = label.parent;
|
|
4022
|
+
stack.pop();
|
|
4023
|
+
this.labelsInScope.delete(name);
|
|
4024
|
+
return;
|
|
4025
|
+
}
|
|
4026
|
+
case NodeType.BreakStatement:
|
|
4027
|
+
case NodeType.ContinueStatement: {
|
|
4028
|
+
const labelName = tree.field(0, Field.label, node);
|
|
4029
|
+
if (labelName === 0) return;
|
|
4030
|
+
this.definitions[labelName] = /** @type {MinifierLabel} */ (
|
|
4031
|
+
this.labelsInScope.get(tree.name(labelName))
|
|
4032
|
+
);
|
|
4033
|
+
return;
|
|
4034
|
+
}
|
|
4035
|
+
case NodeType.WithStatement:
|
|
4036
|
+
for (
|
|
4037
|
+
let outer = /** @type {MinifierScope | null} */ (this.scope);
|
|
4038
|
+
outer !== null;
|
|
4039
|
+
outer = /** @type {MinifierScope | null} */ (outer.upper)
|
|
4040
|
+
) {
|
|
4041
|
+
outer.usesWith = true;
|
|
4042
|
+
}
|
|
4043
|
+
stack.push(node);
|
|
4044
|
+
this._visitChild(Field.object, node);
|
|
4045
|
+
this._visitChild(Field.body, node);
|
|
4046
|
+
stack.pop();
|
|
4047
|
+
return;
|
|
4048
|
+
case NodeType.Property:
|
|
4049
|
+
case NodeType.PropertyDefinition:
|
|
4050
|
+
if (
|
|
4051
|
+
tree.type(tree.field(0, Field.key, node)) ===
|
|
4052
|
+
NodeType.PrivateIdentifier
|
|
4053
|
+
) {
|
|
4054
|
+
this.namesPrivate = true;
|
|
4055
|
+
}
|
|
4056
|
+
stack.push(node);
|
|
4057
|
+
if (tree.flag(Flag.computed, node)) this._visitChild(Field.key, node);
|
|
4058
|
+
this._visitChild(Field.value, node);
|
|
4059
|
+
if (
|
|
4060
|
+
this.types[node] === NodeType.Property &&
|
|
4061
|
+
tree.textOf(Part.kind, node) === "init" &&
|
|
4062
|
+
!tree.flag(Flag.method, node)
|
|
4063
|
+
) {
|
|
4064
|
+
this._spellProperty(node);
|
|
4065
|
+
}
|
|
4066
|
+
stack.pop();
|
|
4067
|
+
return;
|
|
4068
|
+
case NodeType.ObjectPattern:
|
|
4069
|
+
case NodeType.ArrayPattern:
|
|
4070
|
+
case NodeType.AssignmentPattern:
|
|
4071
|
+
case NodeType.RestElement:
|
|
4072
|
+
this._visitBinding(node, 0);
|
|
4073
|
+
return;
|
|
4074
|
+
case NodeType.TemplateLiteral:
|
|
4075
|
+
// Its strings, between the expressions, read nothing.
|
|
4076
|
+
stack.push(node);
|
|
4077
|
+
this._visitList(Field.expressions, node);
|
|
4078
|
+
stack.pop();
|
|
4079
|
+
return;
|
|
4080
|
+
case NodeType.ImportExpression:
|
|
4081
|
+
stack.push(node);
|
|
4082
|
+
this._visitChild(Field.source, node);
|
|
4083
|
+
this._visitChild(Field.options, node);
|
|
4084
|
+
stack.pop();
|
|
4085
|
+
return;
|
|
4086
|
+
case NodeType.MethodDefinition:
|
|
4087
|
+
if (
|
|
4088
|
+
tree.type(tree.field(0, Field.key, node)) ===
|
|
4089
|
+
NodeType.PrivateIdentifier
|
|
4090
|
+
) {
|
|
4091
|
+
this.namesPrivate = true;
|
|
4092
|
+
}
|
|
4093
|
+
stack.push(node);
|
|
4094
|
+
if (tree.flag(Flag.computed, node)) this._visitChild(Field.key, node);
|
|
4095
|
+
this._visitChild(Field.value, node);
|
|
4096
|
+
stack.pop();
|
|
4097
|
+
return;
|
|
4098
|
+
case NodeType.IfStatement:
|
|
4099
|
+
case NodeType.ConditionalExpression:
|
|
4100
|
+
stack.push(node);
|
|
4101
|
+
this._visitChild(Field.test, node);
|
|
4102
|
+
this._visitChild(Field.consequent, node);
|
|
4103
|
+
this._visitChild(Field.alternate, node);
|
|
4104
|
+
stack.pop();
|
|
4105
|
+
return;
|
|
4106
|
+
case NodeType.SwitchCase:
|
|
4107
|
+
stack.push(node);
|
|
4108
|
+
this._visitChild(Field.test, node);
|
|
4109
|
+
this._visitList(Field.consequent, node);
|
|
4110
|
+
stack.pop();
|
|
4111
|
+
return;
|
|
4112
|
+
case NodeType.ArrayExpression:
|
|
4113
|
+
stack.push(node);
|
|
4114
|
+
this._visitList(Field.elements, node);
|
|
4115
|
+
stack.pop();
|
|
4116
|
+
return;
|
|
4117
|
+
case NodeType.ObjectExpression:
|
|
4118
|
+
stack.push(node);
|
|
4119
|
+
this._visitList(Field.properties, node);
|
|
4120
|
+
stack.pop();
|
|
4121
|
+
return;
|
|
4122
|
+
case NodeType.SequenceExpression:
|
|
4123
|
+
stack.push(node);
|
|
4124
|
+
this._visitList(Field.expressions, node);
|
|
4125
|
+
stack.pop();
|
|
4126
|
+
return;
|
|
4127
|
+
case NodeType.TaggedTemplateExpression:
|
|
4128
|
+
stack.push(node);
|
|
4129
|
+
this._visitChild(Field.tag, node);
|
|
4130
|
+
this._visitChild(Field.quasi, node);
|
|
4131
|
+
stack.pop();
|
|
4132
|
+
return;
|
|
4133
|
+
case NodeType.ChainExpression:
|
|
4134
|
+
stack.push(node);
|
|
4135
|
+
this._visitChild(Field.expression, node);
|
|
4136
|
+
stack.pop();
|
|
4137
|
+
return;
|
|
4138
|
+
case NodeType.TryStatement:
|
|
4139
|
+
stack.push(node);
|
|
4140
|
+
this._visitChild(Field.block, node);
|
|
4141
|
+
this._visitChild(Field.handler, node);
|
|
4142
|
+
this._visitChild(Field.finalizer, node);
|
|
4143
|
+
stack.pop();
|
|
4144
|
+
return;
|
|
4145
|
+
case NodeType.PrivateIdentifier:
|
|
4146
|
+
this.namesPrivate = true;
|
|
4147
|
+
return;
|
|
4148
|
+
case NodeType.ImportDeclaration: {
|
|
4149
|
+
this._checkModuleStatement(node, "Import");
|
|
4150
|
+
stack.push(node);
|
|
4151
|
+
const count = tree.fieldCount(Field.specifiers, node);
|
|
4152
|
+
for (let i = 0; i < count; i++) {
|
|
4153
|
+
const specifier = tree.field(i, Field.specifiers, node);
|
|
4154
|
+
const local = tree.field(0, Field.local, specifier);
|
|
4155
|
+
// terser holds a default import's name with no node around it.
|
|
4156
|
+
if (this.types[specifier] === NodeType.ImportDefaultSpecifier) {
|
|
4157
|
+
this._declare(local, DECLARES_IMPORT);
|
|
4158
|
+
continue;
|
|
4159
|
+
}
|
|
4160
|
+
stack.push(specifier);
|
|
4161
|
+
this._declare(local, DECLARES_IMPORT);
|
|
4162
|
+
if (this.types[specifier] === NodeType.ImportSpecifier) {
|
|
4163
|
+
this._spell(
|
|
4164
|
+
local,
|
|
4165
|
+
tree.field(0, Field.imported, specifier),
|
|
4166
|
+
AS_SAVING
|
|
4167
|
+
);
|
|
4168
|
+
}
|
|
4169
|
+
stack.pop();
|
|
4170
|
+
}
|
|
4171
|
+
stack.pop();
|
|
4172
|
+
return;
|
|
4173
|
+
}
|
|
4174
|
+
case NodeType.ExportNamedDeclaration: {
|
|
4175
|
+
this._checkModuleStatement(node, "Export");
|
|
4176
|
+
stack.push(node);
|
|
4177
|
+
this._visitChild(Field.declaration, node);
|
|
4178
|
+
const flags =
|
|
4179
|
+
tree.field(0, Field.source, node) !== 0
|
|
4180
|
+
? REFERENCE_EXPORTED | REFERENCE_FROM_MODULE
|
|
4181
|
+
: REFERENCE_EXPORTED;
|
|
4182
|
+
const count = tree.fieldCount(Field.specifiers, node);
|
|
4183
|
+
for (let i = 0; i < count; i++) {
|
|
4184
|
+
const specifier = tree.field(i, Field.specifiers, node);
|
|
4185
|
+
stack.push(specifier);
|
|
4186
|
+
const local = tree.field(0, Field.local, specifier);
|
|
4187
|
+
this._addReference(local, flags);
|
|
4188
|
+
if ((flags & REFERENCE_FROM_MODULE) === 0) {
|
|
4189
|
+
this._spell(
|
|
4190
|
+
local,
|
|
4191
|
+
tree.field(0, Field.exported, specifier),
|
|
4192
|
+
AS_SAVING
|
|
4193
|
+
);
|
|
4194
|
+
}
|
|
4195
|
+
stack.pop();
|
|
4196
|
+
}
|
|
4197
|
+
stack.pop();
|
|
4198
|
+
return;
|
|
4199
|
+
}
|
|
4200
|
+
case NodeType.ExportDefaultDeclaration:
|
|
4201
|
+
this._checkModuleStatement(node, "Export");
|
|
4202
|
+
stack.push(node);
|
|
4203
|
+
this._visitChild(Field.declaration, node);
|
|
4204
|
+
stack.pop();
|
|
4205
|
+
return;
|
|
4206
|
+
case NodeType.ExportAllDeclaration:
|
|
4207
|
+
// terser's `*` reads a global no name in the output depends on.
|
|
4208
|
+
this._checkModuleStatement(node, "Export");
|
|
4209
|
+
return;
|
|
4210
|
+
case NodeType.Super:
|
|
4211
|
+
case NodeType.EmptyStatement:
|
|
4212
|
+
case NodeType.DebuggerStatement:
|
|
4213
|
+
case NodeType.MetaProperty:
|
|
4214
|
+
return;
|
|
4215
|
+
default:
|
|
4216
|
+
throw new Error(
|
|
4217
|
+
`The minifier's scope analysis cannot read a node of type ${type}`
|
|
4218
|
+
);
|
|
4219
|
+
}
|
|
4220
|
+
}
|
|
4221
|
+
|
|
4222
|
+
/**
|
|
4223
|
+
* Resolves each name read, finds `eval`, and encloses what a catch
|
|
4224
|
+
* parameter redefines.
|
|
4225
|
+
* @returns {void}
|
|
4226
|
+
*/
|
|
4227
|
+
_resolve() {
|
|
4228
|
+
const { referenceNodes, referenceScopes, referenceFlags, globals, tree } =
|
|
4229
|
+
this;
|
|
4230
|
+
for (let i = 0; i < referenceNodes.length; i++) {
|
|
4231
|
+
const node = referenceNodes[i];
|
|
4232
|
+
const from = referenceScopes[i];
|
|
4233
|
+
const flags = referenceFlags[i];
|
|
4234
|
+
if (flags & REFERENCE_CATCH) {
|
|
4235
|
+
const redefinition = /** @type {MinifierVariable | undefined} */ (
|
|
4236
|
+
from.variableScope.getBinding(tree.name(node))
|
|
4237
|
+
);
|
|
4238
|
+
if (redefinition !== undefined) encloseVariable(from, redefinition);
|
|
4239
|
+
continue;
|
|
4240
|
+
}
|
|
4241
|
+
const name = this._nameOf(node);
|
|
4242
|
+
if (flags & REFERENCE_CALLED) {
|
|
4243
|
+
for (
|
|
4244
|
+
let outer = /** @type {MinifierScope | null} */ (from);
|
|
4245
|
+
outer !== null && !outer.usesEval;
|
|
4246
|
+
outer = /** @type {MinifierScope | null} */ (outer.upper)
|
|
4247
|
+
) {
|
|
4248
|
+
outer.usesEval = true;
|
|
4249
|
+
}
|
|
4250
|
+
}
|
|
4251
|
+
let variable =
|
|
4252
|
+
flags & REFERENCE_FROM_MODULE
|
|
4253
|
+
? undefined
|
|
4254
|
+
: findMinifierVariable(from, name, i);
|
|
4255
|
+
if (variable === undefined) {
|
|
4256
|
+
variable = globals.get(name);
|
|
4257
|
+
if (variable === undefined) {
|
|
4258
|
+
variable = new MinifierVariable(name, this.toplevel, DECLARES_GLOBAL);
|
|
4259
|
+
variable.undeclared = true;
|
|
4260
|
+
variable.global = true;
|
|
4261
|
+
globals.set(name, variable);
|
|
4262
|
+
}
|
|
4263
|
+
if (flags & REFERENCE_EXPORTED) variable.export = EXPORT_KEEP_NAME;
|
|
4264
|
+
}
|
|
4265
|
+
if (tree.type(node) === NodeType.Identifier) {
|
|
4266
|
+
this.definitions[node] = variable;
|
|
4267
|
+
this._referenceVariable(from, variable);
|
|
4268
|
+
} else {
|
|
4269
|
+
// A re-exported string reads a global, which keeps no references.
|
|
4270
|
+
encloseVariable(from, variable);
|
|
4271
|
+
}
|
|
4272
|
+
}
|
|
4273
|
+
const { parameterRanges } = this;
|
|
4274
|
+
for (let i = 0; i < parameterRanges.length; i++) {
|
|
4275
|
+
parameterRanges[i].parameterStart = -1;
|
|
4276
|
+
parameterRanges[i].parameterEnd = -1;
|
|
4277
|
+
}
|
|
4278
|
+
}
|
|
4279
|
+
|
|
4280
|
+
/**
|
|
4281
|
+
* @param {number[]} identifiers names
|
|
4282
|
+
* @returns {PrintIdentifier[]} each as the mangler reads it: its name and its definition
|
|
4283
|
+
*/
|
|
4284
|
+
_asNames(identifiers) {
|
|
4285
|
+
return identifiers.map(
|
|
4286
|
+
(identifier) =>
|
|
4287
|
+
/** @type {PrintIdentifier} */ (
|
|
4288
|
+
/** @type {unknown} */ ({
|
|
4289
|
+
name: this.tree.name(identifier),
|
|
4290
|
+
definition: this.definitions[identifier]
|
|
4291
|
+
})
|
|
4292
|
+
)
|
|
4293
|
+
);
|
|
4294
|
+
}
|
|
4295
|
+
}
|
|
4296
|
+
|
|
4297
|
+
/**
|
|
4298
|
+
* Analyses a `SyntaxTree` as `analyzeMinifierScope` does terser's tree of
|
|
4299
|
+
* the same source; neither `ie8` nor `safari10` may be on.
|
|
4300
|
+
* @param {SyntaxTree} tree the tree
|
|
4301
|
+
* @param {number} program its program
|
|
4302
|
+
* @param {Uint8Array} types each node's type, as terser's tree types it
|
|
4303
|
+
* @param {MinifierScopeOptions} options the mangle options
|
|
4304
|
+
* @param {(node: number, message: string) => never} raise throws the parse error a misplaced import or export is
|
|
4305
|
+
* @returns {MinifierTreeScopeAnalysis} the scopes, and each name's definition
|
|
4306
|
+
*/
|
|
4307
|
+
const analyzeMinifierTree = (tree, program, types, options, raise) => {
|
|
4308
|
+
if (NodeType === undefined) {
|
|
4309
|
+
({ NodeType, Field, Flag, Part } = require("./data"));
|
|
4310
|
+
}
|
|
4311
|
+
const analyzer = new MinifierTreeScopeAnalyzer(
|
|
4312
|
+
tree,
|
|
4313
|
+
program,
|
|
4314
|
+
types,
|
|
4315
|
+
options,
|
|
4316
|
+
raise
|
|
4317
|
+
);
|
|
4318
|
+
analyzer.stack.push(program);
|
|
4319
|
+
analyzer._visitList(Field.body, program);
|
|
4320
|
+
analyzer.stack.pop();
|
|
4321
|
+
analyzer._resolve();
|
|
4322
|
+
const { functionDeclarators, classDeclarators } = analyzer;
|
|
4323
|
+
return {
|
|
4324
|
+
toplevel: analyzer.toplevel,
|
|
4325
|
+
labels: analyzer.labels,
|
|
4326
|
+
globals: analyzer.globals,
|
|
4327
|
+
blockDefunScopes: analyzer.blockDefunScopes,
|
|
4328
|
+
functionDeclarators:
|
|
4329
|
+
functionDeclarators === null
|
|
4330
|
+
? null
|
|
4331
|
+
: analyzer._asNames(functionDeclarators),
|
|
4332
|
+
classDeclarators:
|
|
4333
|
+
classDeclarators === null ? null : analyzer._asNames(classDeclarators),
|
|
4334
|
+
catchParameters: analyzer._asNames(analyzer.catchParameters),
|
|
4335
|
+
namesPrivate: analyzer.namesPrivate,
|
|
4336
|
+
spelledNames: analyzer._spelledNames(),
|
|
4337
|
+
definitions: analyzer.definitions
|
|
4338
|
+
};
|
|
4339
|
+
};
|
|
4340
|
+
|
|
4341
|
+
// The declarations whose name a block keeps: a read of any other name from a
|
|
4342
|
+
// block is the function's, as terser re-points it.
|
|
4343
|
+
const BLOCK_DECLARATIONS =
|
|
4344
|
+
(1 << DECLARES_LET) |
|
|
4345
|
+
(1 << DECLARES_CONST) |
|
|
4346
|
+
(1 << DECLARES_USING) |
|
|
4347
|
+
(1 << DECLARES_CATCH) |
|
|
4348
|
+
(1 << DECLARES_DEF_CLASS) |
|
|
4349
|
+
(1 << DECLARES_IMPORT);
|
|
4350
|
+
|
|
4351
|
+
// The declarations naming a function, which terser's `def_function` defines.
|
|
4352
|
+
const FUNCTION_DECLARATIONS =
|
|
4353
|
+
(1 << DECLARES_LAMBDA) | (1 << DECLARES_DEFUN) | (1 << DECLARES_DEF_CLASS);
|
|
4354
|
+
|
|
4355
|
+
/**
|
|
4356
|
+
* What the compressor's analysis asks of its tree's nodes, which only the
|
|
4357
|
+
* tree's kinds answer.
|
|
4358
|
+
* @typedef {object} CompressorDialect
|
|
4359
|
+
* @property {(node: CompressorNode) => boolean} isSymbol whether a node is one of terser's symbols, which records its scope
|
|
4360
|
+
* @property {(node: CompressorNode) => boolean} isFunction whether a node is a function expression, not a method
|
|
4361
|
+
* @property {(node: CompressorNode) => boolean} isDefun whether a node is a function declaration
|
|
4362
|
+
* @property {(node: CompressorNode) => boolean} isObjectKeyValue whether a property is a plain key and value, its key a name only where computed
|
|
4363
|
+
* @property {(node: CompressorNode) => boolean} isPrivateField whether a class field is a private one, its key no symbol
|
|
4364
|
+
* @property {(lambda: CompressorNode) => CompressorNode} argumentsSymbol the symbol a function's own `arguments` is declared by
|
|
4365
|
+
*/
|
|
4366
|
+
|
|
4367
|
+
/**
|
|
4368
|
+
* The compressor's analysis: the minifier's, recording what terser's
|
|
4369
|
+
* `figure_out_scope` gives the compressor besides. Each scope is a
|
|
4370
|
+
* `CompressorScope` its node holds, each definition a `CompressorVariable`
|
|
4371
|
+
* with its declaring symbols, its value and its reads, and each symbol its
|
|
4372
|
+
* scope; a label is its own definition, its `break`s and `continue`s its
|
|
4373
|
+
* references.
|
|
4374
|
+
*/
|
|
4375
|
+
class CompressorScopeAnalyzer extends MinifierScopeAnalyzer {
|
|
4376
|
+
/**
|
|
4377
|
+
* @param {CompressorNode} root the program, or a function or class analysed again
|
|
4378
|
+
* @param {MinifierScopeOptions} options the options
|
|
4379
|
+
* @param {(node: PrintNode, message: string, tables?: TokenTables) => never} raise throws the parse error a misplaced declaration is
|
|
4380
|
+
* @param {CompressorDialect} dialect what the tree's kinds answer
|
|
4381
|
+
* @param {CompressorScopeShape} parentScope the scope the root sits in, the program's own for the program
|
|
4382
|
+
* @param {CompressorScopeShape} toplevel the program's scope
|
|
4383
|
+
*/
|
|
4384
|
+
constructor(root, options, raise, dialect, parentScope, toplevel) {
|
|
4385
|
+
super(
|
|
4386
|
+
/** @type {PrintProgram} */ (/** @type {unknown} */ (root)),
|
|
4387
|
+
{
|
|
4388
|
+
ie8: options.ie8,
|
|
4389
|
+
safari10: options.safari10,
|
|
4390
|
+
module: options.module,
|
|
4391
|
+
parameterScopes: options.parameterScopes
|
|
4392
|
+
},
|
|
4393
|
+
raise,
|
|
4394
|
+
undefined
|
|
4395
|
+
);
|
|
4396
|
+
/** @type {CompressorDialect} */
|
|
4397
|
+
this.dialect = dialect;
|
|
4398
|
+
this.toplevel = /** @type {MinifierScope} */ (
|
|
4399
|
+
/** @type {unknown} */ (toplevel)
|
|
4400
|
+
);
|
|
4401
|
+
this.tokenTables =
|
|
4402
|
+
/** @type {PrintProgram} */ (/** @type {unknown} */ (toplevel.node))
|
|
4403
|
+
.tokenTables || undefined;
|
|
4404
|
+
this.scope = /** @type {MinifierScope} */ (
|
|
4405
|
+
/** @type {unknown} */ (parentScope)
|
|
4406
|
+
);
|
|
4407
|
+
// The program's node holds its globals, as terser's did.
|
|
4408
|
+
this.globals = /** @type {Map<string, MinifierVariable>} */ (
|
|
4409
|
+
/** @type {CompressorNode} */ (/** @type {unknown} */ (toplevel.node))
|
|
4410
|
+
.globals
|
|
4411
|
+
);
|
|
4412
|
+
}
|
|
4413
|
+
|
|
4414
|
+
/**
|
|
4415
|
+
* @param {ScopeType} type what opens it
|
|
4416
|
+
* @param {PrintNode} node the node opening it
|
|
4417
|
+
* @param {boolean} isVarScope whether `var` hoists to here
|
|
4418
|
+
* @returns {MinifierScope} the scope, now current
|
|
4419
|
+
*/
|
|
4420
|
+
_open(type, node, isVarScope) {
|
|
4421
|
+
const opener = /** @type {CompressorNode} */ (
|
|
4422
|
+
/** @type {unknown} */ (node)
|
|
4423
|
+
);
|
|
4424
|
+
const scope = createCompressorScope(
|
|
4425
|
+
type,
|
|
4426
|
+
opener,
|
|
4427
|
+
/** @type {CompressorScopeShape | null} */ (
|
|
4428
|
+
/** @type {unknown} */ (this.scope)
|
|
4429
|
+
),
|
|
4430
|
+
isVarScope
|
|
4431
|
+
);
|
|
4432
|
+
// eslint-disable-next-line camelcase -- terser's name, which the compressor reads
|
|
4433
|
+
opener.block_scope = scope;
|
|
4434
|
+
this.scope = /** @type {MinifierScope} */ (/** @type {unknown} */ (scope));
|
|
4435
|
+
return this.scope;
|
|
4436
|
+
}
|
|
4437
|
+
|
|
4438
|
+
/**
|
|
4439
|
+
* terser's `def_variable`, the scope's binding of the name already looked up.
|
|
4440
|
+
* @param {MinifierScope} target the scope declaring it
|
|
4441
|
+
* @param {MinifierVariable | undefined} variable what the scope binds the name to, if anything
|
|
4442
|
+
* @param {PrintIdentifier | null} identifier the name declaring it, if written
|
|
4443
|
+
* @param {string} name the name
|
|
4444
|
+
* @param {number} kind how it is declared
|
|
4445
|
+
* @returns {MinifierVariable} its definition, made or joined
|
|
4446
|
+
*/
|
|
4447
|
+
_addDeclaration(target, variable, identifier, name, kind) {
|
|
4448
|
+
const scope = /** @type {CompressorScopeShape} */ (
|
|
4449
|
+
/** @type {unknown} */ (target)
|
|
4450
|
+
);
|
|
4451
|
+
const opener = /** @type {CompressorNode} */ (
|
|
4452
|
+
/** @type {unknown} */ (/** @type {MinifierScope} */ (this.scope).node)
|
|
4453
|
+
);
|
|
4454
|
+
/** @type {CompressorNode | null | undefined} */
|
|
4455
|
+
let init;
|
|
4456
|
+
let symbol;
|
|
4457
|
+
if (identifier === null) {
|
|
4458
|
+
symbol = this.dialect.argumentsSymbol(opener);
|
|
4459
|
+
} else {
|
|
4460
|
+
symbol = /** @type {CompressorNode} */ (
|
|
4461
|
+
/** @type {unknown} */ (identifier)
|
|
4462
|
+
);
|
|
4463
|
+
if ((1 << kind) & (FUNCTION_DECLARATIONS | (1 << DECLARES_CLASS))) {
|
|
4464
|
+
// A function's or class's name, its scope where it is declared.
|
|
4465
|
+
symbol.scope = /** @type {CompressorNode} */ (
|
|
4466
|
+
/** @type {unknown} */ (scope)
|
|
4467
|
+
);
|
|
4468
|
+
// A function expression named `arguments` is not its own value.
|
|
4469
|
+
init =
|
|
4470
|
+
kind === DECLARES_LAMBDA && name === "arguments" ? undefined : opener;
|
|
4471
|
+
} else if (kind !== DECLARES_FUNARG && kind !== DECLARES_IMPORT) {
|
|
4472
|
+
init = null;
|
|
4473
|
+
}
|
|
4474
|
+
}
|
|
4475
|
+
let definition = /** @type {CompressorDefinition | undefined} */ (
|
|
4476
|
+
/** @type {unknown} */ (variable)
|
|
4477
|
+
);
|
|
4478
|
+
if (definition !== undefined) {
|
|
4479
|
+
definition.declarations |= 1 << kind;
|
|
4480
|
+
definition.identifiers.push(symbol);
|
|
4481
|
+
if (
|
|
4482
|
+
definition.init &&
|
|
4483
|
+
(definition.scope !== /** @type {unknown} */ (symbol.scope) ||
|
|
4484
|
+
this.dialect.isFunction(definition.init))
|
|
4485
|
+
) {
|
|
4486
|
+
definition.init = init;
|
|
4487
|
+
}
|
|
4488
|
+
} else {
|
|
4489
|
+
definition = createCompressorDefinition(name, scope, kind, symbol, init);
|
|
4490
|
+
definition.global = scope.upper === null;
|
|
4491
|
+
scope.bind(definition);
|
|
4492
|
+
}
|
|
4493
|
+
if (
|
|
4494
|
+
(1 << kind) & FUNCTION_DECLARATIONS &&
|
|
4495
|
+
(!definition.init || this.dialect.isDefun(definition.init))
|
|
4496
|
+
) {
|
|
4497
|
+
definition.init = init;
|
|
4498
|
+
}
|
|
4499
|
+
symbol.definition = definition;
|
|
4500
|
+
return /** @type {MinifierVariable} */ (
|
|
4501
|
+
/** @type {unknown} */ (definition)
|
|
4502
|
+
);
|
|
4503
|
+
}
|
|
4504
|
+
|
|
4505
|
+
/**
|
|
4506
|
+
* terser's `reference`.
|
|
4507
|
+
* @param {PrintIdentifier} identifier the name read
|
|
4508
|
+
* @param {MinifierScope} from the scope reading it
|
|
4509
|
+
* @param {MinifierVariable} variable what it reads
|
|
4510
|
+
* @returns {void}
|
|
4511
|
+
*/
|
|
4512
|
+
_referenceVariable(identifier, from, variable) {
|
|
4513
|
+
/** @type {CompressorDefinition} */ (
|
|
4514
|
+
/** @type {unknown} */ (variable)
|
|
4515
|
+
).references.push(
|
|
4516
|
+
/** @type {CompressorNode} */ (/** @type {unknown} */ (identifier))
|
|
4517
|
+
);
|
|
4518
|
+
encloseVariable(from, variable);
|
|
4519
|
+
}
|
|
4520
|
+
|
|
4521
|
+
/**
|
|
4522
|
+
* A `var`, parameter, `let`, `const`, `using`, catch parameter or import.
|
|
4523
|
+
* @param {PrintIdentifier} identifier the name declared
|
|
4524
|
+
* @param {number} kind how, as a `DECLARES_*` code
|
|
4525
|
+
* @returns {void}
|
|
4526
|
+
*/
|
|
4527
|
+
_declare(identifier, kind) {
|
|
4528
|
+
/** @type {CompressorNode} */ (/** @type {unknown} */ (identifier)).scope =
|
|
4529
|
+
/** @type {CompressorNode} */ (/** @type {unknown} */ (this.scope));
|
|
4530
|
+
super._declare(identifier, kind);
|
|
4531
|
+
}
|
|
4532
|
+
|
|
4533
|
+
/**
|
|
4534
|
+
* @param {PrintIdentifier | PrintLiteral} node a name read, or a re-exported string
|
|
4535
|
+
* @param {number} flags what else is known of it, as `REFERENCE_*` bits
|
|
4536
|
+
* @returns {void}
|
|
4537
|
+
*/
|
|
4538
|
+
_addReference(node, flags) {
|
|
4539
|
+
// The name holds the scope it is read in, as its `scope`.
|
|
4540
|
+
this.referenceNodes.push(node);
|
|
4541
|
+
this.referenceFlags.push(flags);
|
|
4542
|
+
}
|
|
4543
|
+
|
|
4544
|
+
/**
|
|
4545
|
+
* Records the scope of a symbol the walk reaches but the minifier's does not
|
|
4546
|
+
* read: a member's name, a label, or a name an import or export maps.
|
|
4547
|
+
* @param {PrintNode | CompressorNode | null | undefined} node a node, if any
|
|
4548
|
+
* @returns {void}
|
|
4549
|
+
*/
|
|
4550
|
+
_recordScope(node) {
|
|
4551
|
+
if (node === null || node === undefined) return;
|
|
4552
|
+
const symbol = /** @type {CompressorNode} */ (
|
|
4553
|
+
/** @type {unknown} */ (node)
|
|
4554
|
+
);
|
|
4555
|
+
if (this.dialect.isSymbol(symbol)) {
|
|
4556
|
+
symbol.scope = /** @type {CompressorNode} */ (
|
|
4557
|
+
/** @type {unknown} */ (this.scope)
|
|
4558
|
+
);
|
|
4559
|
+
}
|
|
4560
|
+
}
|
|
4561
|
+
|
|
4562
|
+
/**
|
|
4563
|
+
* Reads what is scoped as webpack does with the shared walk, pushed as
|
|
4564
|
+
* terser's walk pushes it, and the rest as terser's analysis does.
|
|
4565
|
+
* @param {PrintNode} current node to visit
|
|
4566
|
+
* @returns {void}
|
|
4567
|
+
*/
|
|
4568
|
+
_visitPrint(current) {
|
|
4569
|
+
const node = /** @type {CompressorNode} */ (
|
|
4570
|
+
/** @type {unknown} */ (current)
|
|
4571
|
+
);
|
|
4572
|
+
switch (current.type) {
|
|
4573
|
+
case "Identifier":
|
|
4574
|
+
case "ThisExpression":
|
|
4575
|
+
case "Super":
|
|
4576
|
+
case "PrivateIdentifier":
|
|
4577
|
+
case "Literal":
|
|
4578
|
+
this._recordScope(current);
|
|
4579
|
+
break;
|
|
4580
|
+
case "MethodDefinition":
|
|
4581
|
+
if (!current.computed) this._recordScope(current.key);
|
|
4582
|
+
break;
|
|
4583
|
+
case "Property":
|
|
4584
|
+
if (
|
|
4585
|
+
!current.computed &&
|
|
4586
|
+
!this.dialect.isObjectKeyValue(
|
|
4587
|
+
/** @type {CompressorNode} */ (/** @type {unknown} */ (current))
|
|
4588
|
+
)
|
|
4589
|
+
) {
|
|
4590
|
+
this._recordScope(current.key);
|
|
4591
|
+
}
|
|
4592
|
+
break;
|
|
4593
|
+
case "PropertyDefinition":
|
|
4594
|
+
if (
|
|
4595
|
+
!current.computed &&
|
|
4596
|
+
!this.dialect.isPrivateField(
|
|
4597
|
+
/** @type {CompressorNode} */ (/** @type {unknown} */ (current))
|
|
4598
|
+
)
|
|
4599
|
+
) {
|
|
4600
|
+
this._recordScope(current.key);
|
|
4601
|
+
}
|
|
4602
|
+
break;
|
|
4603
|
+
case "LabeledStatement":
|
|
4604
|
+
this._visitLabeled(node);
|
|
4605
|
+
return;
|
|
4606
|
+
case "BreakStatement":
|
|
4607
|
+
case "ContinueStatement":
|
|
4608
|
+
this._visitLoopControl(node);
|
|
4609
|
+
return;
|
|
4610
|
+
case "ImportDeclaration":
|
|
4611
|
+
this._visitNameMappings(node.imported_names);
|
|
4612
|
+
break;
|
|
4613
|
+
case "ExportNamedDeclaration":
|
|
4614
|
+
this._visitNameMappings(node.exported_names);
|
|
4615
|
+
break;
|
|
4616
|
+
case "ExportAllDeclaration":
|
|
4617
|
+
this._visitExportAll(node);
|
|
4618
|
+
return;
|
|
4619
|
+
}
|
|
4620
|
+
super._visitPrint(current);
|
|
4621
|
+
}
|
|
4622
|
+
|
|
4623
|
+
/**
|
|
4624
|
+
* @param {CompressorNode[] | null | undefined} mappings an import's or export's names
|
|
4625
|
+
* @returns {void}
|
|
4626
|
+
*/
|
|
4627
|
+
_visitNameMappings(mappings) {
|
|
4628
|
+
if (!mappings) return;
|
|
4629
|
+
for (let i = 0; i < mappings.length; i++) {
|
|
4630
|
+
const mapping = mappings[i];
|
|
4631
|
+
this._recordScope(mapping.imported);
|
|
4632
|
+
this._recordScope(mapping.exported);
|
|
4633
|
+
this._recordScope(mapping.local);
|
|
4634
|
+
}
|
|
4635
|
+
}
|
|
4636
|
+
|
|
4637
|
+
/**
|
|
4638
|
+
* An `export *`, whose names read terser's `*` global.
|
|
4639
|
+
* @param {CompressorNode} node the export
|
|
4640
|
+
* @returns {void}
|
|
4641
|
+
*/
|
|
4642
|
+
_visitExportAll(node) {
|
|
4643
|
+
const exported = /** @type {PrintNode} */ (/** @type {unknown} */ (node));
|
|
4644
|
+
this._checkModuleStatement(exported, "Export");
|
|
4645
|
+
/** @type {CompressorNode[]} */
|
|
4646
|
+
const names = node.exported_names;
|
|
4647
|
+
this._visitNameMappings(names);
|
|
4648
|
+
const stack = this.stack;
|
|
4649
|
+
stack.push(exported);
|
|
4650
|
+
for (let i = 0; i < names.length; i++) {
|
|
4651
|
+
const mapping = names[i];
|
|
4652
|
+
stack.push(/** @type {PrintNode} */ (/** @type {unknown} */ (mapping)));
|
|
4653
|
+
this._addReference(
|
|
4654
|
+
/** @type {PrintIdentifier} */ (mapping.local),
|
|
4655
|
+
REFERENCE_EXPORTED | REFERENCE_FROM_MODULE
|
|
4656
|
+
);
|
|
4657
|
+
stack.pop();
|
|
4658
|
+
}
|
|
4659
|
+
stack.pop();
|
|
4660
|
+
}
|
|
4661
|
+
|
|
4662
|
+
/**
|
|
4663
|
+
* A labeled statement, its label its own definition.
|
|
4664
|
+
* @param {CompressorNode} node the statement
|
|
4665
|
+
* @returns {void}
|
|
4666
|
+
*/
|
|
4667
|
+
_visitLabeled(node) {
|
|
4668
|
+
const { label } = node;
|
|
4669
|
+
const { name } = label;
|
|
4670
|
+
const labels = /** @type {Map<string, CompressorNode>} */ (
|
|
4671
|
+
/** @type {unknown} */ (this.labelsInScope)
|
|
4672
|
+
);
|
|
4673
|
+
if (labels.has(name)) throw new Error(`Label ${name} defined twice`);
|
|
4674
|
+
this._recordScope(label);
|
|
4675
|
+
// A label's definition is the label itself.
|
|
4676
|
+
label.definition = /** @type {CompressorDefinition} */ (
|
|
4677
|
+
/** @type {unknown} */ (label)
|
|
4678
|
+
);
|
|
4679
|
+
label.references = [];
|
|
4680
|
+
labels.set(name, label);
|
|
4681
|
+
this.stack.push(/** @type {PrintNode} */ (/** @type {unknown} */ (node)));
|
|
4682
|
+
this._visitPrint(node.body);
|
|
4683
|
+
this.stack.pop();
|
|
4684
|
+
labels.delete(name);
|
|
4685
|
+
}
|
|
4686
|
+
|
|
4687
|
+
/**
|
|
4688
|
+
* A `break` or `continue`, one of its label's references.
|
|
4689
|
+
* @param {CompressorNode} node the statement
|
|
4690
|
+
* @returns {void}
|
|
4691
|
+
*/
|
|
4692
|
+
_visitLoopControl(node) {
|
|
4693
|
+
const name = /** @type {CompressorNode | null} */ (node.label);
|
|
4694
|
+
if (!name) return;
|
|
4695
|
+
this._recordScope(name);
|
|
4696
|
+
const label = /** @type {Map<string, CompressorNode>} */ (
|
|
4697
|
+
/** @type {unknown} */ (this.labelsInScope)
|
|
4698
|
+
).get(name.name);
|
|
4699
|
+
if (label === undefined) {
|
|
4700
|
+
const start = /** @type {Token} */ (this.tokenOf(name.startToken));
|
|
4701
|
+
throw new Error(
|
|
4702
|
+
`Undefined label ${name.name} [${start.line},${start.col}]`
|
|
4703
|
+
);
|
|
4704
|
+
}
|
|
4705
|
+
name.definition = /** @type {CompressorDefinition} */ (
|
|
4706
|
+
/** @type {unknown} */ (label)
|
|
4707
|
+
);
|
|
4708
|
+
label.references.push(node);
|
|
4709
|
+
}
|
|
4710
|
+
|
|
4711
|
+
/**
|
|
4712
|
+
* Resolves each name read as terser's compressor reads it: the definition's
|
|
4713
|
+
* reads, a function's own `arguments` read, and a read from a block of a
|
|
4714
|
+
* name the block does not keep moved to the function's scope.
|
|
4715
|
+
* @returns {void}
|
|
4716
|
+
*/
|
|
4717
|
+
_resolveCompressor() {
|
|
4718
|
+
const { referenceNodes, referenceFlags } = this;
|
|
4719
|
+
const globals = /** @type {Map<string, CompressorDefinition>} */ (
|
|
4720
|
+
/** @type {unknown} */ (this.globals)
|
|
4721
|
+
);
|
|
4722
|
+
const toplevel = /** @type {CompressorScopeShape} */ (
|
|
4723
|
+
/** @type {unknown} */ (this.toplevel)
|
|
4724
|
+
);
|
|
4725
|
+
for (let i = 0; i < referenceNodes.length; i++) {
|
|
4726
|
+
const node = /** @type {CompressorNode} */ (
|
|
4727
|
+
/** @type {unknown} */ (referenceNodes[i])
|
|
4728
|
+
);
|
|
4729
|
+
const from = /** @type {MinifierScope} */ (
|
|
4730
|
+
/** @type {unknown} */ (node.scope)
|
|
4731
|
+
);
|
|
4732
|
+
const flags = referenceFlags[i];
|
|
4733
|
+
const { name } = node;
|
|
4734
|
+
if (flags & REFERENCE_CATCH) {
|
|
4735
|
+
const redefinition = /** @type {MinifierVariable | undefined} */ (
|
|
4736
|
+
from.variableScope.getBinding(name)
|
|
4737
|
+
);
|
|
4738
|
+
if (redefinition !== undefined) encloseVariable(from, redefinition);
|
|
4739
|
+
continue;
|
|
4740
|
+
}
|
|
4741
|
+
if (flags & REFERENCE_CALLED) {
|
|
4742
|
+
for (
|
|
4743
|
+
let outer = /** @type {MinifierScope | null} */ (from);
|
|
4744
|
+
outer !== null && !outer.usesEval;
|
|
4745
|
+
outer = /** @type {MinifierScope | null} */ (outer.upper)
|
|
4746
|
+
) {
|
|
4747
|
+
outer.usesEval = true;
|
|
4748
|
+
}
|
|
4749
|
+
}
|
|
4750
|
+
let definition = /** @type {CompressorDefinition | undefined} */ (
|
|
4751
|
+
/** @type {unknown} */ (
|
|
4752
|
+
flags & REFERENCE_FROM_MODULE
|
|
4753
|
+
? undefined
|
|
4754
|
+
: findMinifierVariable(from, name, i)
|
|
4755
|
+
)
|
|
4756
|
+
);
|
|
4757
|
+
if (definition === undefined) {
|
|
4758
|
+
definition = globals.get(name);
|
|
4759
|
+
if (definition === undefined) {
|
|
4760
|
+
definition = createCompressorDefinition(
|
|
4761
|
+
name,
|
|
4762
|
+
toplevel,
|
|
4763
|
+
DECLARES_GLOBAL,
|
|
4764
|
+
node,
|
|
4765
|
+
undefined
|
|
4766
|
+
);
|
|
4767
|
+
definition.undeclared = true;
|
|
4768
|
+
definition.global = true;
|
|
4769
|
+
globals.set(name, definition);
|
|
4770
|
+
}
|
|
4771
|
+
if (flags & REFERENCE_EXPORTED) definition.export = EXPORT_KEEP_NAME;
|
|
4772
|
+
} else if (name === "arguments" && definition.scope.type === "function") {
|
|
4773
|
+
definition.scope.getDefunScope().usesArguments = true;
|
|
4774
|
+
}
|
|
4775
|
+
node.definition = definition;
|
|
4776
|
+
definition.references.push(node);
|
|
4777
|
+
encloseVariable(
|
|
4778
|
+
from,
|
|
4779
|
+
/** @type {MinifierVariable} */ (/** @type {unknown} */ (definition))
|
|
4780
|
+
);
|
|
4781
|
+
if (
|
|
4782
|
+
from.variableScope !== from &&
|
|
4783
|
+
((1 << definition.kind) & BLOCK_DECLARATIONS) === 0
|
|
4784
|
+
) {
|
|
4785
|
+
node.scope = /** @type {CompressorNode} */ (
|
|
4786
|
+
/** @type {unknown} */ (from.variableScope)
|
|
4787
|
+
);
|
|
4788
|
+
}
|
|
4789
|
+
}
|
|
4790
|
+
|
|
4791
|
+
this._clearParameterRanges();
|
|
4792
|
+
|
|
4793
|
+
// Passes 3 and 4: work around old engines' catch and loop scopes.
|
|
4794
|
+
const { catchNames, catchScopes } = this;
|
|
4795
|
+
for (let i = 0; i < catchNames.length; i++) {
|
|
4796
|
+
const symbol = /** @type {CompressorNode} */ (
|
|
4797
|
+
/** @type {unknown} */ (catchNames[i])
|
|
4798
|
+
);
|
|
4799
|
+
const { name } = symbol;
|
|
4800
|
+
const { references } = symbol.definition;
|
|
4801
|
+
const defunScope = /** @type {CompressorScopeShape} */ (
|
|
4802
|
+
/** @type {unknown} */ (catchScopes[i].variableScope)
|
|
4803
|
+
);
|
|
4804
|
+
let definition = defunScope.findVariable(name) || globals.get(name);
|
|
4805
|
+
if (definition === undefined) {
|
|
4806
|
+
definition = createCompressorDefinition(
|
|
4807
|
+
name,
|
|
4808
|
+
defunScope,
|
|
4809
|
+
DECLARES_CATCH,
|
|
4810
|
+
symbol,
|
|
4811
|
+
undefined
|
|
4812
|
+
);
|
|
4813
|
+
definition.global = defunScope.upper === null;
|
|
4814
|
+
defunScope.bind(definition);
|
|
4815
|
+
}
|
|
4816
|
+
// As terser's `forEach`: referencing appends to the list it reads.
|
|
4817
|
+
const { length } = references;
|
|
4818
|
+
for (let j = 0; j < length; j++) {
|
|
4819
|
+
const read = references[j];
|
|
4820
|
+
read.definition = definition;
|
|
4821
|
+
read.scope.addReference(read);
|
|
4822
|
+
}
|
|
4823
|
+
symbol.definition = definition;
|
|
4824
|
+
symbol.scope.addReference(symbol);
|
|
4825
|
+
}
|
|
4826
|
+
const { forScopes } = this;
|
|
4827
|
+
for (let i = 0; i < forScopes.length; i++) {
|
|
4828
|
+
const forScope = forScopes[i];
|
|
4829
|
+
const variables = /** @type {MinifierScope} */ (forScope.upper).variables;
|
|
4830
|
+
for (let j = 0; j < variables.length; j++) {
|
|
4831
|
+
encloseUnique(forScope, /** @type {MinifierVariable} */ (variables[j]));
|
|
4832
|
+
}
|
|
4833
|
+
}
|
|
4834
|
+
}
|
|
4835
|
+
}
|
|
4836
|
+
|
|
4837
|
+
/**
|
|
4838
|
+
* Analyses the compressor's tree, or a function or class of it again, with
|
|
4839
|
+
* terser's scoping, recording what the compressor reads: see
|
|
4840
|
+
* `CompressorScopeAnalyzer`.
|
|
4841
|
+
* @param {CompressorNode} root the program, or a function or class in it
|
|
4842
|
+
* @param {MinifierScopeOptions} options the options
|
|
4843
|
+
* @param {(node: PrintNode, message: string, tables?: TokenTables) => never} raise throws the parse error a misplaced declaration is
|
|
4844
|
+
* @param {CompressorDialect} dialect what the tree's kinds answer
|
|
4845
|
+
* @param {CompressorScopeShape | null} parentScope the scope the root sits in, unless it is the program
|
|
4846
|
+
* @param {CompressorNode} program the program
|
|
4847
|
+
* @returns {void}
|
|
4848
|
+
*/
|
|
4849
|
+
const analyzeCompressorScope = (
|
|
4850
|
+
root,
|
|
4851
|
+
options,
|
|
4852
|
+
raise,
|
|
4853
|
+
dialect,
|
|
4854
|
+
parentScope,
|
|
4855
|
+
program
|
|
4856
|
+
) => {
|
|
4857
|
+
const isProgram = root === program;
|
|
4858
|
+
let toplevel;
|
|
4859
|
+
if (isProgram) {
|
|
4860
|
+
toplevel = createCompressorScope("global", root, null, true);
|
|
4861
|
+
root.globals = new Map();
|
|
4862
|
+
// eslint-disable-next-line camelcase -- terser's name, which the compressor reads
|
|
4863
|
+
root.block_scope = toplevel;
|
|
4864
|
+
} else {
|
|
4865
|
+
toplevel = program.block_scope;
|
|
4866
|
+
}
|
|
4867
|
+
const analyzer = new CompressorScopeAnalyzer(
|
|
4868
|
+
root,
|
|
4869
|
+
options,
|
|
4870
|
+
raise,
|
|
4871
|
+
dialect,
|
|
4872
|
+
isProgram ? toplevel : /** @type {CompressorScopeShape} */ (parentScope),
|
|
4873
|
+
toplevel
|
|
4874
|
+
);
|
|
4875
|
+
if (isProgram) {
|
|
4876
|
+
analyzer.stack.push(
|
|
4877
|
+
/** @type {PrintNode} */ (/** @type {unknown} */ (root))
|
|
4878
|
+
);
|
|
4879
|
+
analyzer._visitList(
|
|
4880
|
+
/** @type {PrintProgram} */ (/** @type {unknown} */ (root)).body
|
|
4881
|
+
);
|
|
4882
|
+
} else {
|
|
4883
|
+
// What a declaration's `export` is read off is not there.
|
|
4884
|
+
analyzer.stack.push(
|
|
4885
|
+
/** @type {PrintNode} */ (
|
|
4886
|
+
/** @type {unknown} */ (
|
|
4887
|
+
/** @type {CompressorScopeShape} */ (parentScope).node
|
|
4888
|
+
)
|
|
4889
|
+
)
|
|
4890
|
+
);
|
|
4891
|
+
analyzer._visitPrint(
|
|
4892
|
+
/** @type {PrintNode} */ (/** @type {unknown} */ (root))
|
|
4893
|
+
);
|
|
4894
|
+
}
|
|
4895
|
+
analyzer.stack.pop();
|
|
4896
|
+
analyzer._resolveCompressor();
|
|
1088
4897
|
};
|
|
1089
4898
|
|
|
1090
4899
|
analyzeScope.Reference = Reference;
|
|
1091
4900
|
analyzeScope.Scope = Scope;
|
|
1092
4901
|
analyzeScope.Variable = Variable;
|
|
4902
|
+
analyzeScope.MinifierLabel = MinifierLabel;
|
|
4903
|
+
analyzeScope.MinifierScope = MinifierScope;
|
|
4904
|
+
analyzeScope.MinifierVariable = MinifierVariable;
|
|
4905
|
+
analyzeScope.isMinifierVariable = isMinifierVariable;
|
|
4906
|
+
analyzeScope.CompressorScope = CompressorScope;
|
|
4907
|
+
analyzeScope.CompressorVariable = CompressorVariable;
|
|
4908
|
+
analyzeScope.createCompressorDefinition = createCompressorDefinition;
|
|
4909
|
+
analyzeScope.createCompressorScope = createCompressorScope;
|
|
4910
|
+
analyzeScope.analyzeMinifierScope = analyzeMinifierScope;
|
|
4911
|
+
analyzeScope.analyzeMinifierTree = analyzeMinifierTree;
|
|
4912
|
+
analyzeScope.analyzeCompressorScope = analyzeCompressorScope;
|
|
4913
|
+
analyzeScope.encloseUnique = encloseUnique;
|
|
4914
|
+
analyzeScope.DECLARES_VAR = DECLARES_VAR;
|
|
4915
|
+
analyzeScope.DECLARES_FUNARG = DECLARES_FUNARG;
|
|
4916
|
+
analyzeScope.DECLARES_LET = DECLARES_LET;
|
|
4917
|
+
analyzeScope.DECLARES_CONST = DECLARES_CONST;
|
|
4918
|
+
analyzeScope.DECLARES_USING = DECLARES_USING;
|
|
4919
|
+
analyzeScope.DECLARES_CATCH = DECLARES_CATCH;
|
|
4920
|
+
analyzeScope.DECLARES_IMPORT = DECLARES_IMPORT;
|
|
4921
|
+
analyzeScope.DECLARES_DEFUN = DECLARES_DEFUN;
|
|
4922
|
+
analyzeScope.DECLARES_LAMBDA = DECLARES_LAMBDA;
|
|
4923
|
+
analyzeScope.DECLARES_CLASS = DECLARES_CLASS;
|
|
4924
|
+
analyzeScope.DECLARES_DEF_CLASS = DECLARES_DEF_CLASS;
|
|
4925
|
+
analyzeScope.DECLARES_GLOBAL = DECLARES_GLOBAL;
|
|
4926
|
+
analyzeScope.EXPORT_KEEP_NAME = EXPORT_KEEP_NAME;
|
|
4927
|
+
analyzeScope.EXPORT_WANT_MANGLE = EXPORT_WANT_MANGLE;
|
|
1093
4928
|
|
|
1094
4929
|
module.exports = analyzeScope;
|