@depup/webpack 5.109.0-depup.0 → 5.110.1-depup.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/bin/webpack.js +12 -0
- package/changes.json +10 -10
- package/lib/APIPlugin.js +123 -17
- package/lib/AsyncDependenciesBlock.js +10 -7
- package/lib/AutomaticPrefetchPlugin.js +1 -1
- package/lib/BannerPlugin.js +10 -6
- package/lib/CacheFacade.js +6 -6
- package/lib/Chunk.js +14 -11
- package/lib/ChunkGraph.js +43 -32
- package/lib/ChunkGroup.js +7 -7
- package/lib/ChunkTemplate.js +35 -44
- package/lib/CircularModulesPlugin.js +205 -28
- package/lib/CleanPlugin.js +15 -16
- package/lib/CodeGenerationResults.js +11 -8
- package/lib/CompatibilityPlugin.js +38 -7
- package/lib/Compilation.js +709 -414
- package/lib/Compiler.js +69 -42
- package/lib/ConcatenationScope.js +117 -8
- package/lib/ConditionalInitFragment.js +3 -3
- package/lib/ConstPlugin.js +13 -11
- package/lib/ContextExclusionPlugin.js +1 -1
- package/lib/ContextModule.js +146 -54
- package/lib/ContextModuleFactory.js +46 -14
- package/lib/ContextReplacementPlugin.js +12 -14
- package/lib/DefinePlugin.js +168 -57
- package/lib/DependenciesBlock.js +9 -6
- package/lib/Dependency.js +36 -16
- package/lib/DependencyTemplate.js +11 -12
- package/lib/DependencyTemplates.js +3 -3
- package/lib/DotenvPlugin.js +50 -13
- package/lib/DynamicEntryPlugin.js +8 -4
- package/lib/EntryOptionPlugin.js +8 -4
- package/lib/EntryPlugin.js +2 -2
- package/lib/Entrypoint.js +6 -2
- package/lib/EnvironmentPlugin.js +2 -2
- package/lib/EvalDevToolModulePlugin.js +8 -4
- package/lib/EvalSourceMapDevToolPlugin.js +15 -8
- package/lib/ExportsInfo.js +123 -19
- package/lib/ExportsInfoApiPlugin.js +2 -4
- package/lib/ExternalModule.js +242 -84
- package/lib/ExternalModuleFactoryPlugin.js +97 -38
- package/lib/ExternalsPlugin.js +10 -6
- package/lib/FileSystemInfo.js +116 -42
- package/lib/FlagAllModulesAsUsedPlugin.js +2 -3
- package/lib/FlagDependencyExportsPlugin.js +76 -19
- package/lib/FlagDependencyUsagePlugin.js +63 -57
- package/lib/FlagEntryExportAsUsedPlugin.js +1 -1
- package/lib/Generator.js +36 -15
- package/lib/HotModuleReplacementPlugin.js +16 -44
- package/lib/IgnorePlugin.js +8 -4
- package/lib/IgnoreWarningsPlugin.js +2 -2
- package/lib/InitFragment.js +28 -36
- package/lib/JavascriptMetaInfoPlugin.js +35 -4
- package/lib/LazyBarrel.js +3 -4
- package/lib/LibraryTemplatePlugin.js +10 -6
- package/lib/LoaderOptionsPlugin.js +7 -3
- package/lib/LoaderTargetPlugin.js +1 -1
- package/lib/MainTemplate.js +49 -42
- package/lib/ManifestPlugin.js +12 -11
- package/lib/Module.js +62 -33
- package/lib/ModuleFactory.js +3 -3
- package/lib/ModuleFilenameHelpers.js +22 -6
- package/lib/ModuleGraph.js +195 -21
- package/lib/ModuleGraphConnection.js +6 -13
- package/lib/ModuleInfoHeaderPlugin.js +8 -10
- package/lib/ModuleTemplate.js +62 -63
- package/lib/MultiCompiler.js +130 -64
- package/lib/MultiStats.js +40 -9
- package/lib/MultiWatching.js +3 -3
- package/lib/NoEmitOnErrorsPlugin.js +1 -1
- package/lib/NodeStuffPlugin.js +29 -19
- package/lib/NormalModule.js +221 -156
- package/lib/NormalModuleFactory.js +563 -112
- package/lib/NormalModuleReplacementPlugin.js +5 -8
- package/lib/NullFactory.js +6 -2
- package/lib/OptionsApply.js +7 -3
- package/lib/Parser.js +7 -3
- package/lib/PlatformPlugin.js +2 -2
- package/lib/PrefetchPlugin.js +1 -1
- package/lib/ProgressPlugin.js +16 -13
- package/lib/ProvidePlugin.js +3 -5
- package/lib/RawModule.js +25 -17
- package/lib/RecordIdsPlugin.js +3 -3
- package/lib/RequestShortener.js +1 -1
- package/lib/ResolverFactory.js +2 -2
- package/lib/RuntimeGlobals.js +22 -10
- package/lib/RuntimeModule.js +29 -19
- package/lib/RuntimePlugin.js +346 -256
- package/lib/RuntimeTemplate.js +2792 -352
- package/lib/SelfModuleFactory.js +7 -3
- package/lib/SourceMapDevToolModuleOptionsPlugin.js +6 -2
- package/lib/SourceMapDevToolPlugin.js +30 -20
- package/lib/Stats.js +3 -4
- package/lib/Template.js +55 -25
- package/lib/TemplatedPathPlugin.js +96 -14
- package/lib/UseStrictPlugin.js +4 -6
- package/lib/WarnCaseSensitiveModulesPlugin.js +4 -4
- package/lib/WarnDeprecatedOptionPlugin.js +1 -1
- package/lib/WarnNoModeSetPlugin.js +1 -1
- package/lib/WatchIgnorePlugin.js +8 -6
- package/lib/Watching.js +8 -8
- package/lib/WebpackIsIncludedPlugin.js +2 -4
- package/lib/WebpackOptionsApply.js +308 -18
- package/lib/WebpackOptionsDefaulter.js +6 -2
- package/lib/asset/AssetBytesGenerator.js +12 -10
- package/lib/asset/AssetBytesParser.js +2 -4
- package/lib/asset/AssetGenerator.js +188 -95
- package/lib/asset/AssetModule.js +7 -3
- package/lib/asset/AssetModulesPlugin.js +110 -38
- package/lib/asset/AssetParser.js +9 -7
- package/lib/asset/AssetSourceGenerator.js +60 -13
- package/lib/asset/AssetSourceParser.js +2 -4
- package/lib/asset/RawDataUrlModule.js +24 -16
- package/lib/asset/WebManifestGenerator.js +8 -10
- package/lib/asset/WebManifestParser.js +24 -10
- package/lib/async-modules/AsyncModuleHelpers.js +2 -2
- package/lib/async-modules/AwaitDependenciesInitFragment.js +2 -2
- package/lib/async-modules/InferAsyncModulesPlugin.js +2 -2
- package/lib/async-modules/isGeneratorLowered.js +4 -4
- package/lib/buildChunkGraph.js +36 -27
- package/lib/bun/BunTargetPlugin.js +1 -1
- package/lib/cache/AddBuildDependenciesPlugin.js +1 -1
- package/lib/cache/AddManagedPathsPlugin.js +1 -1
- package/lib/cache/IdleFileCachePlugin.js +2 -2
- package/lib/cache/MemoryCachePlugin.js +18 -10
- package/lib/cache/MemoryWithGcCachePlugin.js +34 -22
- package/lib/cache/PackFileCacheStrategy.js +289 -28
- package/lib/cache/ResolverCachePlugin.js +38 -18
- package/lib/cache/getLazyHashedEtag.js +1 -2
- package/lib/cache/mergeEtags.js +1 -1
- package/lib/cli.js +1 -3
- package/lib/config/browserslistTargetHandler.js +41 -5
- package/lib/config/defaults.js +282 -81
- package/lib/config/defineConfig.js +10 -2
- package/lib/config/getClaimedAssetTypes.js +65 -0
- package/lib/config/normalization.js +36 -16
- package/lib/config/target.js +46 -3
- package/lib/container/ContainerEntryDependency.js +1 -1
- package/lib/container/ContainerEntryModule.js +24 -15
- package/lib/container/ContainerEntryModuleFactory.js +7 -3
- package/lib/container/ContainerPlugin.js +9 -10
- package/lib/container/ContainerReferencePlugin.js +6 -2
- package/lib/container/FallbackDependency.js +1 -1
- package/lib/container/FallbackModule.js +24 -17
- package/lib/container/FallbackModuleFactory.js +7 -3
- package/lib/container/HoistContainerReferencesPlugin.js +53 -66
- package/lib/container/ModuleFederationPlugin.js +7 -18
- package/lib/container/RemoteModule.js +27 -19
- package/lib/container/RemoteRuntimeModule.js +10 -8
- package/lib/container/moduleFederationHooks.js +32 -0
- package/lib/css/CssGenerator.js +178 -44
- package/lib/css/CssInjectStyleRuntimeModule.js +7 -5
- package/lib/css/CssLoadingRuntimeModule.js +82 -36
- package/lib/css/CssModule.js +10 -7
- package/lib/css/CssModulesPlugin.js +197 -106
- package/lib/css/CssParser.js +1248 -618
- package/lib/css/CssServerStylesRuntimeModule.js +54 -0
- package/lib/css/cssMinify.js +168 -0
- package/lib/css/data.js +5324 -0
- package/lib/css/syntax.js +10396 -952
- package/lib/debug/ProfilingPlugin.js +14 -9
- package/lib/deno/DenoTargetPlugin.js +1 -1
- package/lib/dependencies/AMDDefineDependency.js +112 -87
- package/lib/dependencies/AMDDefineDependencyParserPlugin.js +30 -17
- package/lib/dependencies/AMDPlugin.js +9 -7
- package/lib/dependencies/AMDRequireArrayDependency.js +5 -5
- package/lib/dependencies/AMDRequireContextDependency.js +2 -2
- package/lib/dependencies/AMDRequireDependenciesBlock.js +1 -1
- package/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js +25 -14
- package/lib/dependencies/AMDRequireDependency.js +8 -7
- package/lib/dependencies/AMDRequireItemDependency.js +1 -1
- package/lib/dependencies/AMDRuntimeModules.js +21 -1
- package/lib/dependencies/BuildTimeConstDependency.js +102 -0
- package/lib/dependencies/CachedConstDependency.js +11 -8
- package/lib/dependencies/CommonJsDependencyHelpers.js +67 -46
- package/lib/dependencies/CommonJsExportRequireDependency.js +140 -45
- package/lib/dependencies/CommonJsExportsDependency.js +53 -49
- package/lib/dependencies/CommonJsExportsParserPlugin.js +207 -25
- package/lib/dependencies/CommonJsFullRequireDependency.js +140 -26
- package/lib/dependencies/CommonJsImportsParserPlugin.js +100 -48
- package/lib/dependencies/CommonJsObjectExportDependency.js +188 -0
- package/lib/dependencies/CommonJsPlugin.js +35 -6
- package/lib/dependencies/CommonJsRequireContextDependency.js +5 -6
- package/lib/dependencies/CommonJsRequireDependency.js +156 -27
- package/lib/dependencies/CommonJsSelfReferenceDependency.js +63 -38
- package/lib/dependencies/ConstDependency.js +8 -9
- package/lib/dependencies/ContextDependency.js +12 -8
- package/lib/dependencies/ContextDependencyHelpers.js +14 -9
- package/lib/dependencies/ContextDependencyTemplateAsId.js +4 -4
- package/lib/dependencies/ContextDependencyTemplateAsRequireCall.js +4 -4
- package/lib/dependencies/ContextElementDependency.js +31 -12
- package/lib/dependencies/CreateRequireParserPlugin.js +12 -7
- package/lib/dependencies/CreateScriptUrlDependency.js +4 -4
- package/lib/dependencies/CssIcssExportDependency.js +56 -28
- package/lib/dependencies/CssIcssImportDependency.js +17 -13
- package/lib/dependencies/CssIcssSymbolDependency.js +9 -10
- package/lib/dependencies/CssImportDependency.js +18 -9
- package/lib/dependencies/CssUrlDependency.js +17 -13
- package/lib/dependencies/DllEntryDependency.js +1 -1
- package/lib/dependencies/DynamicExports.js +2 -2
- package/lib/dependencies/ExportBindingInitFragment.js +36 -9
- package/lib/dependencies/ExportsInfoDependency.js +7 -8
- package/lib/dependencies/ExternalModuleDependency.js +9 -5
- package/lib/dependencies/ExternalModuleInitFragment.js +2 -2
- package/lib/dependencies/ExternalModuleInitFragmentDependency.js +8 -5
- package/lib/dependencies/HarmonyAcceptDependency.js +5 -5
- package/lib/dependencies/HarmonyCompatibilityDependency.js +52 -17
- package/lib/dependencies/HarmonyDetectionParserPlugin.js +11 -7
- package/lib/dependencies/HarmonyEvaluatedImportSpecifierDependency.js +15 -11
- package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +78 -12
- package/lib/dependencies/HarmonyExportExpressionDependency.js +23 -18
- package/lib/dependencies/HarmonyExportHeaderDependency.js +7 -7
- package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +159 -71
- package/lib/dependencies/HarmonyExportInitFragment.js +18 -6
- package/lib/dependencies/HarmonyExportSpecifierDependency.js +51 -14
- package/lib/dependencies/HarmonyExports.js +7 -4
- package/lib/dependencies/HarmonyImportDependency.js +28 -20
- package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +31 -24
- package/lib/dependencies/HarmonyImportGuard.js +21 -30
- package/lib/dependencies/HarmonyImportSideEffectDependency.js +38 -9
- package/lib/dependencies/HarmonyImportSpecifierDependency.js +106 -55
- package/lib/dependencies/HarmonyModulesPlugin.js +7 -3
- package/lib/dependencies/HarmonyTopLevelThisParserPlugin.js +1 -3
- package/lib/dependencies/HtmlEntryDependency.js +37 -29
- package/lib/dependencies/HtmlInlineHtmlDependency.js +7 -8
- package/lib/dependencies/HtmlInlineScriptDependency.js +11 -8
- package/lib/dependencies/HtmlInlineStyleDependency.js +7 -10
- package/lib/dependencies/HtmlSourceDependency.js +22 -14
- package/lib/dependencies/ImportContextDependency.js +2 -2
- package/lib/dependencies/ImportDependency.js +24 -20
- package/lib/dependencies/ImportEagerDependency.js +6 -9
- package/lib/dependencies/ImportMetaContextDependency.js +2 -2
- package/lib/dependencies/ImportMetaContextDependencyParserPlugin.js +14 -13
- package/lib/dependencies/ImportMetaContextPlugin.js +7 -3
- package/lib/dependencies/ImportMetaGlobDependency.js +2 -2
- package/lib/dependencies/ImportMetaGlobDependencyParserPlugin.js +2 -3
- package/lib/dependencies/ImportMetaGlobHelpers.js +19 -22
- package/lib/dependencies/ImportMetaHotAcceptDependency.js +1 -1
- package/lib/dependencies/ImportMetaHotDeclineDependency.js +1 -1
- package/lib/dependencies/ImportMetaPlugin.js +154 -71
- package/lib/dependencies/ImportMetaResolveDependency.js +3 -4
- package/lib/dependencies/ImportParserPlugin.js +49 -35
- package/lib/dependencies/ImportPhase.js +12 -5
- package/lib/dependencies/ImportPlugin.js +7 -3
- package/lib/dependencies/ImportWeakDependency.js +6 -9
- package/lib/dependencies/JsonExportsDependency.js +11 -7
- package/lib/dependencies/LoaderDependency.js +2 -2
- package/lib/dependencies/LoaderImportDependency.js +2 -2
- package/lib/dependencies/LoaderPlugin.js +11 -7
- package/lib/dependencies/LocalModuleDependency.js +5 -5
- package/lib/dependencies/LocalModulesHelpers.js +1 -1
- package/lib/dependencies/ModuleDecoratorDependency.js +6 -7
- package/lib/dependencies/ModuleDependency.js +9 -6
- package/lib/dependencies/ModuleDependencyTemplateAsId.js +4 -4
- package/lib/dependencies/ModuleDependencyTemplateAsRequireId.js +3 -3
- package/lib/dependencies/ModuleHotAcceptDependency.js +1 -1
- package/lib/dependencies/ModuleHotDeclineDependency.js +1 -1
- package/lib/dependencies/ModuleInitFragmentDependency.js +24 -10
- package/lib/dependencies/NullDependency.js +3 -3
- package/lib/dependencies/ProvidedDependency.js +14 -10
- package/lib/dependencies/PureExpressionDependency.js +9 -10
- package/lib/dependencies/RequireContextDependency.js +2 -2
- package/lib/dependencies/RequireContextDependencyParserPlugin.js +2 -4
- package/lib/dependencies/RequireContextPlugin.js +8 -4
- package/lib/dependencies/RequireEnsureDependenciesBlock.js +2 -2
- package/lib/dependencies/RequireEnsureDependenciesBlockParserPlugin.js +5 -8
- package/lib/dependencies/RequireEnsureDependency.js +8 -7
- package/lib/dependencies/RequireEnsurePlugin.js +7 -3
- package/lib/dependencies/RequireHeaderDependency.js +51 -12
- package/lib/dependencies/RequireIncludeDependency.js +6 -6
- package/lib/dependencies/RequireIncludeDependencyParserPlugin.js +2 -3
- package/lib/dependencies/RequireIncludePlugin.js +7 -3
- package/lib/dependencies/RequireJsStuffPlugin.js +7 -3
- package/lib/dependencies/RequireResolveContextDependency.js +2 -2
- package/lib/dependencies/RequireResolveDependency.js +4 -4
- package/lib/dependencies/RequireResolveHeaderDependency.js +4 -4
- package/lib/dependencies/RuntimeRequirementsDependency.js +5 -6
- package/lib/dependencies/StaticExportsDependency.js +2 -2
- package/lib/dependencies/SystemPlugin.js +10 -6
- package/lib/dependencies/SystemRuntimeModule.js +10 -0
- package/lib/dependencies/TopLevelAwaitDependency.js +11 -7
- package/lib/dependencies/URLContextDependency.js +2 -2
- package/lib/dependencies/URLDependency.js +110 -64
- package/lib/dependencies/URLPlugin.js +7 -3
- package/lib/dependencies/UnsupportedDependency.js +4 -4
- package/lib/dependencies/WebAssemblyExportImportedDependency.js +3 -4
- package/lib/dependencies/WebAssemblyImportDependency.js +5 -5
- package/lib/dependencies/WebpackIsIncludedDependency.js +6 -6
- package/lib/dependencies/WorkerAndWorkletPlugin.js +46 -28
- package/lib/dependencies/WorkerDependency.js +28 -22
- package/lib/dependencies/WorkletDependency.js +15 -14
- package/lib/dependencies/getFunctionExpression.js +8 -4
- package/lib/dependencies/processExportInfo.js +5 -5
- package/lib/dll/DelegatedModule.js +34 -22
- package/lib/dll/DelegatedModuleFactoryPlugin.js +15 -7
- package/lib/dll/DelegatedPlugin.js +2 -2
- package/lib/dll/DllEntryPlugin.js +2 -2
- package/lib/dll/DllModule.js +22 -15
- package/lib/dll/DllModuleFactory.js +7 -3
- package/lib/dll/DllPlugin.js +7 -5
- package/lib/dll/DllReferencePlugin.js +10 -7
- package/lib/dll/LibManifestPlugin.js +5 -5
- package/lib/electron/ElectronTargetPlugin.js +53 -49
- package/lib/errors/AsyncChunkWaterfallWarning.js +36 -0
- package/lib/errors/AsyncDependencyToInitialChunkError.js +2 -2
- package/lib/errors/BroadContextsWarning.js +43 -0
- package/lib/errors/BuildCycleError.js +1 -1
- package/lib/errors/CacheEffectivenessWarning.js +55 -0
- package/lib/errors/ChunkRenderError.js +1 -1
- package/lib/errors/CircularDependenciesWarning.js +38 -0
- package/lib/errors/CodeGenerationError.js +1 -1
- package/lib/errors/CommentCompilationWarning.js +1 -1
- package/lib/errors/ConflictingResourceHintsWarning.js +35 -0
- package/lib/errors/DuplicateModulesWarning.js +45 -0
- package/lib/errors/DynamicExportsWarning.js +30 -0
- package/lib/errors/EmbeddedSourceMapsWarning.js +25 -0
- package/lib/errors/EntrypointOverlapWarning.js +45 -0
- package/lib/errors/EnvironmentNotSupportAsyncWarning.js +2 -2
- package/lib/errors/EvalUsageWarning.js +28 -0
- package/lib/errors/HookWebpackError.js +5 -5
- package/lib/errors/HotspotsWarning.js +57 -0
- package/lib/errors/IgnoreErrorModuleFactory.js +7 -3
- package/lib/errors/InlinedAssetsWarning.js +36 -0
- package/lib/errors/InvalidDependenciesModuleWarning.js +1 -1
- package/lib/errors/LargeModulesWarning.js +45 -0
- package/lib/errors/LegacyJavascriptWarning.js +48 -0
- package/lib/errors/MissingSideEffectsWarning.js +36 -0
- package/lib/errors/MixedExportsWarning.js +41 -0
- package/lib/errors/ModuleDependencyError.js +13 -16
- package/lib/errors/ModuleDependencyWarning.js +5 -15
- package/lib/errors/ModuleHashingError.js +1 -1
- package/lib/errors/ModuleNotFoundError.js +2 -2
- package/lib/errors/ModuleParseError.js +1 -2
- package/lib/errors/ModuleRestoreError.js +1 -1
- package/lib/errors/ModuleStoreError.js +1 -1
- package/lib/errors/NodeStuffInWebError.js +1 -1
- package/lib/errors/OsDependentRuleWarning.js +31 -0
- package/lib/errors/PureAnnotationsWarning.js +36 -0
- package/lib/errors/RedundantDynamicImportWarning.js +31 -0
- package/lib/errors/ScopeHoistingBailoutsWarning.js +41 -0
- package/lib/errors/SplitChunksCappedWarning.js +41 -0
- package/lib/errors/TinyChunksWarning.js +40 -0
- package/lib/errors/TopLevelThisWarning.js +34 -0
- package/lib/errors/UnsplitVendorsWarning.js +42 -0
- package/lib/errors/UnsupportedFeatureWarning.js +1 -1
- package/lib/errors/UnusedAliasesWarning.js +29 -0
- package/lib/errors/UnusedDefinesWarning.js +29 -0
- package/lib/errors/UnusedExternalsWarning.js +29 -0
- package/lib/errors/UnusedReexportsWarning.js +42 -0
- package/lib/errors/UnusedRuleWarning.js +29 -0
- package/lib/errors/WebpackError.js +9 -5
- package/lib/errors/deriveStackFromNestedError.js +90 -0
- package/lib/esm/ExportWebpackRequireRuntimeModule.js +2 -0
- package/lib/esm/ModuleChunkFormatPlugin.js +37 -19
- package/lib/esm/ModuleChunkLoadingPlugin.js +89 -51
- package/lib/esm/ModuleChunkLoadingRuntimeModule.js +170 -71
- package/lib/hmr/HotModuleReplacement.runtime.js +24 -5
- package/lib/hmr/HotModuleReplacementRuntimeModule.js +1 -1
- package/lib/hmr/LazyCompilationPlugin.js +45 -24
- package/lib/hmr/lazyCompilationBackend.js +28 -10
- package/lib/hmr/parserHooks.js +56 -0
- package/lib/html/HtmlGenerator.js +299 -79
- package/lib/html/HtmlModule.js +7 -3
- package/lib/html/HtmlModulesPlugin.js +312 -174
- package/lib/html/HtmlParser.js +31 -86
- package/lib/html/data.js +1928 -0
- package/lib/html/htmlMinify.js +288 -0
- package/lib/html/syntax.js +7819 -3331
- package/lib/ids/ChunkModuleIdRangePlugin.js +3 -3
- package/lib/ids/DeterministicChunkIdsPlugin.js +1 -1
- package/lib/ids/DeterministicModuleIdsPlugin.js +2 -2
- package/lib/ids/HashedModuleIdsPlugin.js +6 -2
- package/lib/ids/IdHelpers.js +31 -18
- package/lib/ids/NamedChunkIdsPlugin.js +1 -1
- package/lib/ids/NamedModuleIdsPlugin.js +1 -1
- package/lib/ids/NaturalChunkIdsPlugin.js +2 -2
- package/lib/ids/NaturalModuleIdsPlugin.js +1 -1
- package/lib/ids/OccurrenceChunkIdsPlugin.js +7 -3
- package/lib/ids/OccurrenceModuleIdsPlugin.js +7 -3
- package/lib/ids/SyncModuleIdsPlugin.js +4 -4
- package/lib/index.js +10 -0
- package/lib/javascript/ArrayPushCallbackChunkFormatPlugin.js +3 -3
- package/lib/javascript/BasicEvaluatedExpression.js +18 -14
- package/lib/javascript/ChunkFormatHelpers.js +6 -6
- package/lib/javascript/ChunkHelpers.js +1 -1
- package/lib/javascript/CommonJsChunkFormatPlugin.js +11 -5
- package/lib/javascript/EnableChunkLoadingPlugin.js +2 -2
- package/lib/javascript/JavascriptGenerator.js +65 -165
- package/lib/javascript/JavascriptModule.js +9 -3
- package/lib/javascript/JavascriptModulesPlugin.js +181 -162
- package/lib/javascript/JavascriptParser.js +291 -112
- package/lib/javascript/JavascriptParserHelpers.js +10 -7
- package/lib/javascript/ScopeAnalyzer.js +1094 -0
- package/lib/javascript/StartupHelpers.js +55 -9
- package/lib/javascript/syntax.js +3403 -300
- package/lib/json/JsonData.js +8 -4
- package/lib/json/JsonGenerator.js +38 -16
- package/lib/json/JsonModule.js +7 -3
- package/lib/json/JsonModulesPlugin.js +1 -1
- package/lib/json/JsonParser.js +5 -6
- package/lib/library/AbstractLibraryPlugin.js +20 -14
- package/lib/library/AmdLibraryPlugin.js +11 -7
- package/lib/library/AssignLibraryPlugin.js +19 -13
- package/lib/library/EnableLibraryPlugin.js +2 -2
- package/lib/library/ExportPropertyLibraryPlugin.js +15 -8
- package/lib/library/JsonpLibraryPlugin.js +11 -7
- package/lib/library/ModuleLibraryPlugin.js +256 -64
- package/lib/library/SystemLibraryPlugin.js +12 -8
- package/lib/library/UmdLibraryPlugin.js +62 -25
- package/lib/loaders/LoaderRunner.js +14 -1
- package/lib/loaders/loadLoader.js +8 -4
- package/lib/logging/createConsoleLogger.js +7 -4
- package/lib/node/CommonJsChunkLoadingPlugin.js +36 -22
- package/lib/node/NodeEnvironmentPlugin.js +17 -3
- package/lib/node/NodeSourcePlugin.js +1 -1
- package/lib/node/NodeTargetPlugin.js +4 -3
- package/lib/node/NodeTemplatePlugin.js +1 -1
- package/lib/node/NodeWatchFileSystem.js +70 -9
- package/lib/node/ReadFileChunkLoadingRuntimeModule.js +35 -38
- package/lib/node/ReadFileCompileAsyncWasmPlugin.js +81 -20
- package/lib/node/ReadFileCompileWasmPlugin.js +37 -17
- package/lib/node/RequireChunkLoadingRuntimeModule.js +35 -38
- package/lib/node/nodeConsole.js +7 -3
- package/lib/optimize/AggressiveMergingPlugin.js +21 -17
- package/lib/optimize/AggressiveSplittingPlugin.js +9 -6
- package/lib/optimize/ConcatenatedModule.js +996 -477
- package/lib/optimize/ConstExportsPlugin.js +11 -7
- package/lib/optimize/EnsureChunkConditionsPlugin.js +3 -3
- package/lib/optimize/FlagIncludedChunksPlugin.js +3 -4
- package/lib/optimize/InlineExports.js +9 -5
- package/lib/optimize/InnerGraph.js +28 -12
- package/lib/optimize/InnerGraphPlugin.js +23 -18
- package/lib/optimize/LimitChunkCountPlugin.js +7 -3
- package/lib/optimize/MangleExportsPlugin.js +7 -8
- package/lib/optimize/MergeDuplicateChunksPlugin.js +7 -3
- package/lib/optimize/MinChunkSizePlugin.js +7 -3
- package/lib/optimize/ModuleConcatenationPlugin.js +124 -59
- package/lib/optimize/RealContentHashPlugin.js +20 -13
- package/lib/optimize/RemoveEmptyChunksPlugin.js +2 -2
- package/lib/optimize/RemoveParentModulesPlugin.js +4 -4
- package/lib/optimize/RuntimeChunkPlugin.js +2 -2
- package/lib/optimize/SideEffectsFlagPlugin.js +262 -39
- package/lib/optimize/SplitChunksPlugin.js +232 -68
- package/lib/performance/AssetsOverSizeLimitWarning.js +10 -2
- package/lib/performance/AsyncChunkWaterfallsPlugin.js +136 -0
- package/lib/performance/BroadContextsPlugin.js +142 -0
- package/lib/performance/CacheEffectivenessPlugin.js +125 -0
- package/lib/performance/ConflictingResourceHintsPlugin.js +99 -0
- package/lib/performance/DuplicateModulesPlugin.js +93 -0
- package/lib/performance/DuplicatePackagesPlugin.js +119 -0
- package/lib/performance/DuplicatePackagesWarning.js +84 -0
- package/lib/performance/DynamicExportsPlugin.js +120 -0
- package/lib/performance/EmbeddedSourceMapsPlugin.js +71 -0
- package/lib/performance/EntrypointOverlapPlugin.js +122 -0
- package/lib/performance/EntrypointsOverSizeLimitWarning.js +1 -1
- package/lib/performance/EvalUsagePlugin.js +115 -0
- package/lib/performance/HotspotsPlugin.js +296 -0
- package/lib/performance/InlinedAssetsPlugin.js +99 -0
- package/lib/performance/LargeModulesPlugin.js +126 -0
- package/lib/performance/LegacyJavascriptPlugin.js +139 -0
- package/lib/performance/MissingSideEffectsPlugin.js +138 -0
- package/lib/performance/MixedExportsPlugin.js +136 -0
- package/lib/performance/OsDependentRuleWarningPlugin.js +178 -0
- package/lib/performance/PureAnnotationsPlugin.js +219 -0
- package/lib/performance/RedundantDynamicImportsPlugin.js +225 -0
- package/lib/performance/RuntimeInLargeChunkWarning.js +27 -0
- package/lib/performance/ScopeHoistingBailoutsPlugin.js +164 -0
- package/lib/performance/SizeLimitsPlugin.js +139 -7
- package/lib/performance/SplitChunksCappedPlugin.js +99 -0
- package/lib/performance/TinyChunksPlugin.js +128 -0
- package/lib/performance/TopLevelThisPlugin.js +208 -0
- package/lib/performance/UnsplitVendorsPlugin.js +112 -0
- package/lib/performance/UnusedAliasesPlugin.js +253 -0
- package/lib/performance/UnusedDefinesPlugin.js +87 -0
- package/lib/performance/UnusedExternalsPlugin.js +110 -0
- package/lib/performance/UnusedReexportsPlugin.js +159 -0
- package/lib/performance/UnusedRuleWarningPlugin.js +105 -0
- package/lib/performance/getModuleSize.js +22 -0
- package/lib/performance/getSourceModules.js +22 -0
- package/lib/performance/hasOnlyUnusedExports.js +40 -0
- package/lib/prefetch/ChunkPrefetchFunctionRuntimeModule.js +24 -10
- package/lib/prefetch/ChunkPrefetchPreloadPlugin.js +63 -46
- package/lib/prefetch/ChunkPrefetchStartupRuntimeModule.js +2 -3
- package/lib/prefetch/ChunkPrefetchTriggerRuntimeModule.js +2 -2
- package/lib/prefetch/ChunkPreloadTriggerRuntimeModule.js +2 -2
- package/lib/prefetch/ResourceHintPlugin.js +377 -136
- package/lib/prefetch/ResourceHintRuntimeModule.js +1 -21
- package/lib/prefetch/StartupAssetHintRuntimeModule.js +10 -133
- package/lib/prefetch/parseResourceHintOptions.js +31 -4
- package/lib/rules/BasicEffectRulePlugin.js +2 -2
- package/lib/rules/BasicMatcherRulePlugin.js +8 -4
- package/lib/rules/GlobMatcherRulePlugin.js +68 -0
- package/lib/rules/ObjectMatcherRulePlugin.js +12 -5
- package/lib/rules/RuleSetCompiler.js +146 -12
- package/lib/rules/UseEffectRulePlugin.js +18 -11
- package/lib/runtime/AsyncModuleGeneratorRuntimeModule.js +11 -1
- package/lib/runtime/AsyncModuleRuntimeModule.js +1 -1
- package/lib/runtime/AutoPublicPathRuntimeModule.js +15 -20
- package/lib/runtime/BaseUriRuntimeModule.js +33 -7
- package/lib/runtime/ChunkNameRuntimeModule.js +10 -0
- package/lib/runtime/CompatGetDefaultExportRuntimeModule.js +11 -1
- package/lib/runtime/CompatRuntimeModule.js +5 -3
- package/lib/runtime/ConcatenationWrapRuntimeModule.js +90 -0
- package/lib/runtime/ConstructRequireRuntimeModule.js +52 -0
- package/lib/runtime/CreateFakeNamespaceObjectRuntimeModule.js +8 -6
- package/lib/runtime/CreateScriptRuntimeModule.js +11 -1
- package/lib/runtime/CreateScriptUrlRuntimeModule.js +11 -1
- package/lib/runtime/DefinePropertyGettersRuntimeModule.js +56 -38
- package/lib/runtime/EnsureChunkRuntimeModule.js +18 -2
- package/lib/runtime/GetChunkFilenameRuntimeModule.js +62 -37
- package/lib/runtime/GetFullHashRuntimeModule.js +12 -2
- package/lib/runtime/GetMainFilenameRuntimeModule.js +12 -2
- package/lib/runtime/GetTrustedTypesPolicyRuntimeModule.js +2 -2
- package/lib/runtime/GetWorkletBootstrapRuntimeModule.js +16 -3
- package/lib/runtime/GlobalRuntimeModule.js +18 -0
- package/lib/runtime/HasOwnPropertyRuntimeModule.js +12 -2
- package/lib/runtime/LoadScriptRuntimeModule.js +2 -2
- package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +23 -6
- package/lib/runtime/MakeNamespaceObjectRuntimeModule.js +22 -6
- package/lib/runtime/NonceRuntimeModule.js +10 -0
- package/lib/runtime/OnChunksLoadedRuntimeModule.js +5 -3
- package/lib/runtime/PublicPathRuntimeModule.js +12 -2
- package/lib/runtime/RelativeUrlRuntimeModule.js +11 -1
- package/lib/runtime/RuntimeIdRuntimeModule.js +12 -2
- package/lib/runtime/SetAnonymousDefaultNameRuntimeModule.js +11 -1
- package/lib/runtime/StartupChunkDependenciesPlugin.js +18 -9
- package/lib/runtime/StartupChunkDependenciesRuntimeModule.js +3 -3
- package/lib/runtime/StartupEntrypointRuntimeModule.js +21 -4
- package/lib/runtime/SystemContextRuntimeModule.js +10 -0
- package/lib/runtime/ToBinaryRuntimeModule.js +1 -1
- package/lib/runtime/WorkerRuntimeModule.js +11 -1
- package/lib/runtime/baseUri.js +63 -0
- package/lib/schemes/DataUriPlugin.js +1 -1
- package/lib/schemes/FileUriPlugin.js +1 -1
- package/lib/schemes/HttpUriPlugin.js +24 -15
- package/lib/schemes/VirtualUrlPlugin.js +13 -7
- package/lib/serialization/AggregateErrorSerializer.js +1 -1
- package/lib/serialization/BinaryMiddleware.js +274 -942
- package/lib/serialization/ErrorObjectSerializer.js +1 -1
- package/lib/serialization/FileMiddleware.js +305 -66
- package/lib/serialization/ObjectMiddleware.js +139 -114
- package/lib/serialization/PlainObjectSerializer.js +19 -16
- package/lib/sharing/ConsumeSharedModule.js +30 -21
- package/lib/sharing/ConsumeSharedPlugin.js +18 -10
- package/lib/sharing/ConsumeSharedRuntimeModule.js +6 -9
- package/lib/sharing/ProvideSharedModule.js +25 -16
- package/lib/sharing/ProvideSharedModuleFactory.js +7 -3
- package/lib/sharing/ProvideSharedPlugin.js +8 -4
- package/lib/sharing/SharePlugin.js +17 -5
- package/lib/sharing/ShareRuntimeModule.js +4 -4
- package/lib/sharing/resolveMatchedConfigs.js +9 -6
- package/lib/sharing/utils.js +1 -3
- package/lib/stats/DefaultStatsFactoryPlugin.js +253 -226
- package/lib/stats/DefaultStatsPresetPlugin.js +17 -8
- package/lib/stats/DefaultStatsPrinterPlugin.js +60 -192
- package/lib/stats/StatsFactory.js +56 -35
- package/lib/stats/StatsPrinter.js +16 -12
- package/lib/typescript/TypeScriptPlugin.js +12 -14
- package/lib/url/URLParserPlugin.js +26 -13
- package/lib/util/AsyncQueue.js +4 -3
- package/lib/util/Hash.js +5 -1
- package/lib/util/LazySet.js +35 -22
- package/lib/util/LocConverter.js +36 -13
- package/lib/util/SourceProcessor.js +1050 -24
- package/lib/util/StringXor.js +1 -1
- package/lib/util/chainedImports.js +9 -5
- package/lib/util/cleverMerge.js +1 -1
- package/lib/util/comparators.js +45 -14
- package/lib/util/concatenate.js +203 -77
- package/lib/util/conventions.js +5 -1
- package/lib/util/createHash.js +2 -2
- package/lib/util/createHooksRegistry.js +8 -10
- package/lib/util/dataURL.js +225 -1
- package/lib/util/extractSourceMap.js +4 -3
- package/lib/util/findCaseMismatch.js +139 -0
- package/lib/util/formatLocation.js +1 -2
- package/lib/util/fs.js +22 -5
- package/lib/util/globUtils.js +298 -24
- package/lib/util/hash/BatchedHash.js +5 -1
- package/lib/util/hash/BulkUpdateHash.js +5 -1
- package/lib/util/hash/DebugHash.js +5 -1
- package/lib/util/hash/hash-digest.js +6 -2
- package/lib/util/identifier.js +25 -1
- package/lib/util/implicitTypeLoaderFallback.js +1 -1
- package/lib/util/internalSerializables.js +6 -0
- package/lib/util/lazyModule.js +56 -0
- package/lib/util/makeSerializable.js +7 -3
- package/lib/util/matchAlias.js +25 -0
- package/lib/util/mimeTypes.js +11 -5
- package/lib/util/nonNumericOnlyHash.js +4 -3
- package/lib/util/parseJson.js +5 -3
- package/lib/util/preloadModuleType.js +32 -0
- package/lib/util/registerExternalSerializer.js +7 -5
- package/lib/util/runtime.js +2 -2
- package/lib/util/semver.js +1 -1
- package/lib/util/serialization.js +28 -28
- package/lib/util/source.js +2 -2
- package/lib/util/traverseDestructuringAssignmentProperties.js +6 -2
- package/lib/wasm/EnableWasmLoadingPlugin.js +10 -8
- package/lib/wasm/wasmModuleFilename.js +54 -0
- package/lib/wasm-async/AsyncWasmCompileRuntimeModule.js +41 -21
- package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +43 -21
- package/lib/wasm-async/AsyncWasmModule.js +3 -3
- package/lib/wasm-async/AsyncWebAssemblyGenerator.js +4 -5
- package/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js +57 -17
- package/lib/wasm-async/AsyncWebAssemblyModulesPlugin.js +34 -18
- package/lib/wasm-async/AsyncWebAssemblyParser.js +9 -8
- package/lib/wasm-async/UniversalCompileAsyncWasmPlugin.js +34 -8
- package/lib/wasm-sync/SyncWasmModule.js +2 -2
- package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +18 -13
- package/lib/wasm-sync/WasmFinalizeExportsPlugin.js +4 -5
- package/lib/wasm-sync/WebAssemblyGenerator.js +18 -17
- package/lib/wasm-sync/WebAssemblyInInitialChunkError.js +4 -4
- package/lib/wasm-sync/WebAssemblyJavascriptGenerator.js +7 -7
- package/lib/wasm-sync/WebAssemblyModulesPlugin.js +24 -11
- package/lib/wasm-sync/WebAssemblyParser.js +4 -6
- package/lib/wasm-sync/WebAssemblyUtils.js +2 -2
- package/lib/web/FetchCompileAsyncWasmPlugin.js +101 -19
- package/lib/web/FetchCompileWasmPlugin.js +46 -16
- package/lib/web/JsonpChunkLoadingPlugin.js +47 -23
- package/lib/web/JsonpChunkLoadingRuntimeModule.js +50 -20
- package/lib/web/JsonpTemplatePlugin.js +2 -2
- package/lib/webpack.js +22 -11
- package/lib/webworker/ImportScriptsChunkLoadingPlugin.js +60 -26
- package/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js +30 -32
- package/lib/webworker/WebWorkerTemplatePlugin.js +1 -1
- package/module.d.ts +1 -0
- package/package.json +37 -30
- package/schemas/WebpackOptions.check.js +1 -1
- package/schemas/WebpackOptions.json +780 -91
- package/schemas/plugins/HtmlParserOptions.check.js +1 -1
- package/schemas/plugins/container/ContainerPlugin.check.js +1 -1
- package/schemas/plugins/container/ContainerPlugin.json +10 -0
- package/schemas/plugins/container/ModuleFederationPlugin.check.js +1 -1
- package/schemas/plugins/container/ModuleFederationPlugin.json +10 -0
- package/schemas/plugins/css/CssAutoOrModuleParserOptions.check.js +1 -1
- package/schemas/plugins/css/CssModuleParserOptions.check.js +1 -1
- package/schemas/plugins/css/CssParserOptions.check.js +1 -1
- package/types.d.ts +4013 -738
- package/lib/runtime/CommonJsWrapRuntimeModule.js +0 -37
package/lib/javascript/syntax.js
CHANGED
|
@@ -36,24 +36,69 @@ const keywordTypes =
|
|
|
36
36
|
(/** @type {unknown} */ (require("acorn"))).keywordTypes
|
|
37
37
|
);
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
39
|
+
// acorn exports these Unicode/character helpers at runtime but leaves them out
|
|
40
|
+
// of its public types; the ported cold-path readers below reuse them so their
|
|
41
|
+
// classification stays byte-identical to acorn's tokenizer.
|
|
42
|
+
const {
|
|
43
|
+
isIdentifierChar,
|
|
44
|
+
isIdentifierStart,
|
|
45
|
+
isNewLine,
|
|
46
|
+
lineBreak,
|
|
47
|
+
nonASCIIwhitespace
|
|
48
|
+
} =
|
|
49
|
+
/** @type {{ isIdentifierStart: (code: number, astral?: boolean) => boolean, isIdentifierChar: (code: number, astral?: boolean) => boolean, isNewLine: (code: number) => boolean, lineBreak: RegExp, nonASCIIwhitespace: RegExp }} */
|
|
50
|
+
(/** @type {unknown} */ (require("acorn")));
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @param {number} code code point
|
|
54
|
+
* @returns {string} the string for a single code point
|
|
55
|
+
*/
|
|
56
|
+
const codePointToString = (code) => String.fromCodePoint(code);
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* acorn's `stringToNumber`: legacy octal parses in base 8, everything else via
|
|
60
|
+
* `parseFloat` after dropping `_` separators.
|
|
61
|
+
* @param {string} str numeric literal text (may contain `_` separators)
|
|
62
|
+
* @param {boolean} isLegacyOctal whether it is a legacy octal literal
|
|
63
|
+
* @returns {number} numeric value
|
|
64
|
+
*/
|
|
65
|
+
const stringToNumber = (str, isLegacyOctal) =>
|
|
66
|
+
isLegacyOctal
|
|
67
|
+
? Number.parseInt(str, 8)
|
|
68
|
+
: Number.parseFloat(str.replace(/_/g, ""));
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* acorn's `stringToBigInt`, minus the pre-BigInt fallback (every supported
|
|
72
|
+
* Node has `BigInt`).
|
|
73
|
+
* @param {string} str numeric literal text (may contain `_` separators)
|
|
74
|
+
* @returns {bigint} bigint value
|
|
75
|
+
*/
|
|
76
|
+
const stringToBigInt = (str) => BigInt(str.replace(/_/g, ""));
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @import {
|
|
80
|
+
* Options,
|
|
81
|
+
* Position,
|
|
82
|
+
* Node,
|
|
83
|
+
* Identifier,
|
|
84
|
+
* ImportAttribute,
|
|
85
|
+
* ImportDefaultSpecifier,
|
|
86
|
+
* ImportExpression,
|
|
87
|
+
* Expression,
|
|
88
|
+
* TokenType
|
|
89
|
+
* } from "acorn"
|
|
90
|
+
*/
|
|
47
91
|
/** @typedef {import("acorn").ImportSpecifier | import("acorn").ImportDefaultSpecifier | import("acorn").ImportNamespaceSpecifier} AnyImportSpecifier */
|
|
48
|
-
/** @typedef {
|
|
49
|
-
/** @typedef {TokenType & { beforeExpr: boolean, isAssign?: boolean, prefix?: boolean, postfix?: boolean, binop: number | null, updateContext?: (prevType: TokenType) => void }} TokenTypeInternal acorn's internal TokenType fields, absent from its public types */
|
|
50
|
-
/** @typedef {import("estree").SourceLocation} SourceLocation */
|
|
92
|
+
/** @typedef {TokenType & { beforeExpr: boolean, isAssign?: boolean, prefix?: boolean, postfix?: boolean, binop: number | null, updateContext: ((prevType: TokenType) => void) | null }} TokenTypeInternal acorn's internal TokenType fields, absent from its public types */
|
|
51
93
|
/** @typedef {[number, number]} Range */
|
|
52
94
|
/** @typedef {"defer" | "source"} ImportPhase */
|
|
53
95
|
/** @typedef {import("estree").Comment & { start: number, end: number }} CollectedComment comment as JavascriptParser exposes it */
|
|
54
96
|
|
|
55
97
|
// Symbol-keyed so they stay out of for-in, Object.keys and JSON.stringify
|
|
56
98
|
// over AST nodes.
|
|
99
|
+
// Per-TokContext "the owned token loop must step aside" flag, cached on the
|
|
100
|
+
// context itself so the hot guard reads one slot instead of two.
|
|
101
|
+
const kSlowContext = Symbol("slow context");
|
|
57
102
|
const kSource = Symbol("source");
|
|
58
103
|
const kRange = Symbol("range");
|
|
59
104
|
const kText = Symbol("text");
|
|
@@ -63,12 +108,23 @@ const kTextStart = Symbol("text start");
|
|
|
63
108
|
const LEGACY_ASSERT_ATTRIBUTES = Symbol("assert");
|
|
64
109
|
|
|
65
110
|
// acorn's binding types and scope flags, stable across acorn 8
|
|
111
|
+
const BIND_NONE = 0;
|
|
66
112
|
const BIND_VAR = 1;
|
|
67
113
|
const BIND_LEXICAL = 2;
|
|
114
|
+
const BIND_OUTSIDE = 5;
|
|
68
115
|
const SCOPE_TOP = 1;
|
|
116
|
+
const SCOPE_FUNCTION = 2;
|
|
117
|
+
const SCOPE_ASYNC = 4;
|
|
118
|
+
const SCOPE_GENERATOR = 8;
|
|
119
|
+
const SCOPE_ARROW = 16;
|
|
69
120
|
const SCOPE_SIMPLE_CATCH = 32;
|
|
70
121
|
// SCOPE_TOP | SCOPE_FUNCTION | SCOPE_CLASS_STATIC_BLOCK
|
|
122
|
+
const SCOPE_SWITCH = 1024;
|
|
71
123
|
const SCOPE_VAR = 0b100000011;
|
|
124
|
+
// acorn's parseFunction statement bit flags
|
|
125
|
+
const FUNC_STATEMENT = 1;
|
|
126
|
+
const FUNC_HANGING_STATEMENT = 2;
|
|
127
|
+
const FUNC_NULLABLE_ID = 4;
|
|
72
128
|
|
|
73
129
|
// ASCII identifier-continuation chars ($ 0-9 A-Z _ a-z); css/html-style
|
|
74
130
|
// Uint8Array table so the tokenizer fast path is one load per char
|
|
@@ -103,6 +159,18 @@ SIMPLE_PUNCT[123] = tokTypes.braceL;
|
|
|
103
159
|
SIMPLE_PUNCT[125] = tokTypes.braceR;
|
|
104
160
|
SIMPLE_PUNCT[58] = tokTypes.colon;
|
|
105
161
|
|
|
162
|
+
// Characters that can only start a token which cannot continue an expression,
|
|
163
|
+
// so an atom directly followed by one is the whole expression (see
|
|
164
|
+
// `parseMaybeAssign`'s fast path). `}` included: it only ever closes a block,
|
|
165
|
+
// an object or a template substitution.
|
|
166
|
+
const EXPRESSION_END_CHAR = new Uint8Array(128);
|
|
167
|
+
EXPRESSION_END_CHAR[41] = 1; // )
|
|
168
|
+
EXPRESSION_END_CHAR[44] = 1; // ,
|
|
169
|
+
EXPRESSION_END_CHAR[58] = 1; // :
|
|
170
|
+
EXPRESSION_END_CHAR[59] = 1; // ;
|
|
171
|
+
EXPRESSION_END_CHAR[93] = 1; // ]
|
|
172
|
+
EXPRESSION_END_CHAR[125] = 1; // }
|
|
173
|
+
|
|
106
174
|
// Char classification for the owned `nextToken` (yuku's ws_class): one table
|
|
107
175
|
// load steers both the whitespace skip loop and the token dispatch. Token
|
|
108
176
|
// classes sort below CLS_SPACE so the skip loop exits on a single compare.
|
|
@@ -592,6 +660,235 @@ class PropertyNode {
|
|
|
592
660
|
}
|
|
593
661
|
}
|
|
594
662
|
|
|
663
|
+
/**
|
|
664
|
+
* Single-shape `ForStatement`.
|
|
665
|
+
*/
|
|
666
|
+
class ForStatementNode {
|
|
667
|
+
/**
|
|
668
|
+
* @param {number} start start offset
|
|
669
|
+
* @param {number} end end offset
|
|
670
|
+
* @param {Node | null} init init statement or expression
|
|
671
|
+
* @param {Expression | null} test loop condition
|
|
672
|
+
* @param {Expression | null} update update expression
|
|
673
|
+
* @param {Node} body loop body
|
|
674
|
+
*/
|
|
675
|
+
constructor(start, end, init, test, update, body) {
|
|
676
|
+
this.type = "ForStatement";
|
|
677
|
+
this.start = start;
|
|
678
|
+
this.end = end;
|
|
679
|
+
this.init = init;
|
|
680
|
+
this.test = test;
|
|
681
|
+
this.update = update;
|
|
682
|
+
this.body = body;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Single-shape `ForInStatement` (no `await` slot, matching acorn).
|
|
688
|
+
*/
|
|
689
|
+
class ForInStatementNode {
|
|
690
|
+
/**
|
|
691
|
+
* @param {number} start start offset
|
|
692
|
+
* @param {number} end end offset
|
|
693
|
+
* @param {Node} left loop target
|
|
694
|
+
* @param {Expression} right iterated expression
|
|
695
|
+
* @param {Node} body loop body
|
|
696
|
+
*/
|
|
697
|
+
constructor(start, end, left, right, body) {
|
|
698
|
+
this.type = "ForInStatement";
|
|
699
|
+
this.start = start;
|
|
700
|
+
this.end = end;
|
|
701
|
+
this.left = left;
|
|
702
|
+
this.right = right;
|
|
703
|
+
this.body = body;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/**
|
|
708
|
+
* Single-shape `ForOfStatement`; `await` leads, matching acorn's write order.
|
|
709
|
+
*/
|
|
710
|
+
class ForOfStatementNode {
|
|
711
|
+
/**
|
|
712
|
+
* @param {number} start start offset
|
|
713
|
+
* @param {number} end end offset
|
|
714
|
+
* @param {boolean} isAwait whether this is `for await`
|
|
715
|
+
* @param {Node} left loop target
|
|
716
|
+
* @param {Expression} right iterated expression
|
|
717
|
+
* @param {Node} body loop body
|
|
718
|
+
*/
|
|
719
|
+
constructor(start, end, isAwait, left, right, body) {
|
|
720
|
+
this.type = "ForOfStatement";
|
|
721
|
+
this.start = start;
|
|
722
|
+
this.end = end;
|
|
723
|
+
this.await = isAwait;
|
|
724
|
+
this.left = left;
|
|
725
|
+
this.right = right;
|
|
726
|
+
this.body = body;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* Single-shape `WhileStatement`.
|
|
732
|
+
*/
|
|
733
|
+
class WhileStatementNode {
|
|
734
|
+
/**
|
|
735
|
+
* @param {number} start start offset
|
|
736
|
+
* @param {number} end end offset
|
|
737
|
+
* @param {Expression} test loop condition
|
|
738
|
+
* @param {Node} body loop body
|
|
739
|
+
*/
|
|
740
|
+
constructor(start, end, test, body) {
|
|
741
|
+
this.type = "WhileStatement";
|
|
742
|
+
this.start = start;
|
|
743
|
+
this.end = end;
|
|
744
|
+
this.test = test;
|
|
745
|
+
this.body = body;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
/**
|
|
750
|
+
* Single-shape `SwitchStatement`.
|
|
751
|
+
*/
|
|
752
|
+
class SwitchStatementNode {
|
|
753
|
+
/**
|
|
754
|
+
* @param {number} start start offset
|
|
755
|
+
* @param {number} end end offset
|
|
756
|
+
* @param {Expression} discriminant switched expression
|
|
757
|
+
* @param {Node[]} cases case clauses
|
|
758
|
+
*/
|
|
759
|
+
constructor(start, end, discriminant, cases) {
|
|
760
|
+
this.type = "SwitchStatement";
|
|
761
|
+
this.start = start;
|
|
762
|
+
this.end = end;
|
|
763
|
+
this.discriminant = discriminant;
|
|
764
|
+
this.cases = cases;
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* Pre-shaped `SwitchCase`: filled in acorn's write order (`consequent` before
|
|
770
|
+
* `test`), finished via `finishNode` like acorn's.
|
|
771
|
+
*/
|
|
772
|
+
class SwitchCaseNode {
|
|
773
|
+
/**
|
|
774
|
+
* @param {number} start start offset
|
|
775
|
+
*/
|
|
776
|
+
constructor(start) {
|
|
777
|
+
this.type = "";
|
|
778
|
+
this.start = start;
|
|
779
|
+
this.end = 0;
|
|
780
|
+
/** @type {Node[] | null} */
|
|
781
|
+
this.consequent = null;
|
|
782
|
+
/** @type {Expression | null} */
|
|
783
|
+
this.test = null;
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* Single-shape `ThrowStatement`.
|
|
789
|
+
*/
|
|
790
|
+
class ThrowStatementNode {
|
|
791
|
+
/**
|
|
792
|
+
* @param {number} start start offset
|
|
793
|
+
* @param {number} end end offset
|
|
794
|
+
* @param {Expression} argument thrown expression
|
|
795
|
+
*/
|
|
796
|
+
constructor(start, end, argument) {
|
|
797
|
+
this.type = "ThrowStatement";
|
|
798
|
+
this.start = start;
|
|
799
|
+
this.end = end;
|
|
800
|
+
this.argument = argument;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* Single-shape `BreakStatement`/`ContinueStatement` — identical field sets, so
|
|
806
|
+
* both node types share one hidden class.
|
|
807
|
+
*/
|
|
808
|
+
class BreakContinueNode {
|
|
809
|
+
/**
|
|
810
|
+
* @param {number} start start offset
|
|
811
|
+
* @param {number} end end offset
|
|
812
|
+
* @param {"BreakStatement" | "ContinueStatement"} type node type
|
|
813
|
+
* @param {Identifier | null} label target label
|
|
814
|
+
*/
|
|
815
|
+
constructor(start, end, type, label) {
|
|
816
|
+
this.type = type;
|
|
817
|
+
this.start = start;
|
|
818
|
+
this.end = end;
|
|
819
|
+
this.label = label;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
/**
|
|
824
|
+
* Single-shape `TryStatement`.
|
|
825
|
+
*/
|
|
826
|
+
class TryStatementNode {
|
|
827
|
+
/**
|
|
828
|
+
* @param {number} start start offset
|
|
829
|
+
* @param {number} end end offset
|
|
830
|
+
* @param {Node} block try block
|
|
831
|
+
* @param {Node | null} handler catch clause
|
|
832
|
+
* @param {Node | null} finalizer finally block
|
|
833
|
+
*/
|
|
834
|
+
constructor(start, end, block, handler, finalizer) {
|
|
835
|
+
this.type = "TryStatement";
|
|
836
|
+
this.start = start;
|
|
837
|
+
this.end = end;
|
|
838
|
+
this.block = block;
|
|
839
|
+
this.handler = handler;
|
|
840
|
+
this.finalizer = finalizer;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
/**
|
|
845
|
+
* Single-shape `CatchClause`.
|
|
846
|
+
*/
|
|
847
|
+
class CatchClauseNode {
|
|
848
|
+
/**
|
|
849
|
+
* @param {number} start start offset
|
|
850
|
+
* @param {number} end end offset
|
|
851
|
+
* @param {Node | null} param catch parameter
|
|
852
|
+
* @param {Node} body catch block
|
|
853
|
+
*/
|
|
854
|
+
constructor(start, end, param, body) {
|
|
855
|
+
this.type = "CatchClause";
|
|
856
|
+
this.start = start;
|
|
857
|
+
this.end = end;
|
|
858
|
+
this.param = param;
|
|
859
|
+
this.body = body;
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
/**
|
|
864
|
+
* Pre-shaped `FunctionDeclaration`/`FunctionExpression`/
|
|
865
|
+
* `ArrowFunctionExpression`: acorn fills function nodes through shared
|
|
866
|
+
* subroutines (`parseFunctionParams`/`parseFunctionBody`), so like
|
|
867
|
+
* `PropertyNode` the fields are all declared up-front — in acorn's exact write
|
|
868
|
+
* order (`initFunction` assigns `expression` before `generator`) so JSON key
|
|
869
|
+
* order is unchanged — and acorn's writes land in existing slots: one hidden
|
|
870
|
+
* class for all three function node types, no transitions.
|
|
871
|
+
*/
|
|
872
|
+
class FunctionNode {
|
|
873
|
+
/**
|
|
874
|
+
* @param {number} start start offset
|
|
875
|
+
*/
|
|
876
|
+
constructor(start) {
|
|
877
|
+
this.type = "";
|
|
878
|
+
this.start = start;
|
|
879
|
+
this.end = 0;
|
|
880
|
+
/** @type {Identifier | null} */
|
|
881
|
+
this.id = null;
|
|
882
|
+
this.expression = false;
|
|
883
|
+
this.generator = false;
|
|
884
|
+
this.async = false;
|
|
885
|
+
/** @type {Node[] | null} */
|
|
886
|
+
this.params = null;
|
|
887
|
+
/** @type {Node | null} */
|
|
888
|
+
this.body = null;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
595
892
|
/**
|
|
596
893
|
* Single-shape `SpreadElement`/`RestElement` — identical field sets, so both
|
|
597
894
|
* node types share one hidden class.
|
|
@@ -611,6 +908,10 @@ class RestSpreadNode {
|
|
|
611
908
|
}
|
|
612
909
|
}
|
|
613
910
|
|
|
911
|
+
// Mirrors of acorn's module-level `loopLabel`/`switchLabel`.
|
|
912
|
+
const LOOP_LABEL = { kind: "loop" };
|
|
913
|
+
const SWITCH_LABEL = { kind: "switch" };
|
|
914
|
+
|
|
614
915
|
// Shared zero-length arguments array for `new X` without parens, mirroring
|
|
615
916
|
// acorn's module-level `empty`.
|
|
616
917
|
/** @type {Expression[]} */
|
|
@@ -676,7 +977,18 @@ for (const NodeClass of [
|
|
|
676
977
|
TemplateElementNode,
|
|
677
978
|
ObjectNode,
|
|
678
979
|
PropertyNode,
|
|
679
|
-
RestSpreadNode
|
|
980
|
+
RestSpreadNode,
|
|
981
|
+
FunctionNode,
|
|
982
|
+
ForStatementNode,
|
|
983
|
+
ForInStatementNode,
|
|
984
|
+
ForOfStatementNode,
|
|
985
|
+
WhileStatementNode,
|
|
986
|
+
SwitchStatementNode,
|
|
987
|
+
SwitchCaseNode,
|
|
988
|
+
ThrowStatementNode,
|
|
989
|
+
BreakContinueNode,
|
|
990
|
+
TryStatementNode,
|
|
991
|
+
CatchClauseNode
|
|
680
992
|
]) {
|
|
681
993
|
for (const key of ["range"]) {
|
|
682
994
|
Object.defineProperty(
|
|
@@ -690,8 +1002,9 @@ for (const NodeClass of [
|
|
|
690
1002
|
|
|
691
1003
|
/**
|
|
692
1004
|
* Comment collected without slicing its text out of the source: only magic
|
|
693
|
-
* comments and pure annotations ever get their text read,
|
|
694
|
-
*
|
|
1005
|
+
* comments and pure annotations ever get their text read, and only binary
|
|
1006
|
+
* searches around magic-comment sites read `range`, so the text slice and the
|
|
1007
|
+
* range array are both deferred to first access and memoized like `loc`.
|
|
695
1008
|
*/
|
|
696
1009
|
class LazyComment {
|
|
697
1010
|
/**
|
|
@@ -706,12 +1019,30 @@ class LazyComment {
|
|
|
706
1019
|
this.type = block ? "Block" : "Line";
|
|
707
1020
|
this.start = start;
|
|
708
1021
|
this.end = end;
|
|
709
|
-
/** @type {Range} */
|
|
710
|
-
this.range = [start, end];
|
|
711
1022
|
this[kSource] = source;
|
|
712
1023
|
this[kTextStart] = textStart;
|
|
713
1024
|
}
|
|
714
1025
|
|
|
1026
|
+
/**
|
|
1027
|
+
* Memoized like `LazyLocNode#range`; offsets are final at construction so
|
|
1028
|
+
* the slot is cached unconditionally.
|
|
1029
|
+
* @returns {Range} source range
|
|
1030
|
+
*/
|
|
1031
|
+
get range() {
|
|
1032
|
+
const cached = this[kRange];
|
|
1033
|
+
if (cached !== undefined) return cached;
|
|
1034
|
+
/** @type {Range} */
|
|
1035
|
+
const range = [this.start, this.end];
|
|
1036
|
+
return (this[kRange] = range);
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
/**
|
|
1040
|
+
* @param {Range} value source range
|
|
1041
|
+
*/
|
|
1042
|
+
set range(value) {
|
|
1043
|
+
this[kRange] = value;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
715
1046
|
/**
|
|
716
1047
|
* @returns {string} comment text without the delimiters
|
|
717
1048
|
*/
|
|
@@ -786,9 +1117,10 @@ class Scope {
|
|
|
786
1117
|
* parseLiteral: (value: unknown) => Node,
|
|
787
1118
|
* awaitIdentPos: number,
|
|
788
1119
|
* lastTokStart: number,
|
|
1120
|
+
* lastTokStartLoc?: Position,
|
|
789
1121
|
* yieldPos: number,
|
|
790
1122
|
* awaitPos: number,
|
|
791
|
-
* parseExpression: () => Expression,
|
|
1123
|
+
* parseExpression: (forInit?: boolean | string, refDestructuringErrors?: DestructuringErrorsShim | null) => Expression,
|
|
792
1124
|
* parseSpread: (refDestructuringErrors?: DestructuringErrorsShim | null) => Node,
|
|
793
1125
|
* braceIsBlock: (prevType: TokenType) => boolean,
|
|
794
1126
|
* _gapHasNewline: () => boolean,
|
|
@@ -800,10 +1132,11 @@ class Scope {
|
|
|
800
1132
|
* checkPatternErrors: (refDestructuringErrors: DestructuringErrorsShim, isAssign: boolean) => void,
|
|
801
1133
|
* checkYieldAwaitInDefaultParams: () => void,
|
|
802
1134
|
* checkExpressionErrors: (refDestructuringErrors?: DestructuringErrorsShim | null, andThrow?: boolean) => boolean,
|
|
803
|
-
* parseSubscript: (base: Expression, startPos: number, startLoc: Position | undefined, noCalls: boolean | undefined, maybeAsyncArrow: boolean, optionalChained: boolean, forInit
|
|
1135
|
+
* parseSubscript: (base: Expression, startPos: number, startLoc: Position | undefined, noCalls: boolean | undefined, maybeAsyncArrow: boolean, optionalChained: boolean, forInit?: boolean | string) => Expression,
|
|
804
1136
|
* parseExprAtom: (refDestructuringErrors?: DestructuringErrorsShim | null, forInit?: boolean | string, forNew?: boolean) => Expression,
|
|
805
1137
|
* buildBinary: (startPos: number, startLoc: Position | undefined, left: Expression, right: Expression, op: string, logical: boolean) => Expression,
|
|
806
1138
|
* parseMaybeAssign: (forInit?: boolean | string, refDestructuringErrors?: DestructuringErrorsShim | null, afterLeftParse?: (this: unknown, left: Expression, startPos: number, startLoc?: Position) => Expression) => Expression,
|
|
1139
|
+
* _parseTrivialAtom: (forInit?: boolean | string) => Expression | null,
|
|
807
1140
|
* parseMaybeConditional: (forInit?: boolean | string, refDestructuringErrors?: DestructuringErrorsShim | null) => Expression,
|
|
808
1141
|
* parseMaybeUnary: (refDestructuringErrors: DestructuringErrorsShim | null, sawUnary: boolean, incDec: boolean, forInit?: boolean | string) => Expression,
|
|
809
1142
|
* parseExprSubscripts: (refDestructuringErrors?: DestructuringErrorsShim | null, forInit?: boolean | string) => Expression,
|
|
@@ -835,6 +1168,18 @@ class Scope {
|
|
|
835
1168
|
* _propHashDepth: number,
|
|
836
1169
|
* _acquireDestructuringErrors: () => DestructuringErrorsShim,
|
|
837
1170
|
* _releaseDestructuringErrors: () => void,
|
|
1171
|
+
* _arrStack: EXPECTED_ANY[][],
|
|
1172
|
+
* _arrDepth: number,
|
|
1173
|
+
* _acquireScratch: () => EXPECTED_ANY[],
|
|
1174
|
+
* _releaseScratch: (scratch: EXPECTED_ANY[], count: number) => EXPECTED_ANY[],
|
|
1175
|
+
* parseRestBinding: () => Node,
|
|
1176
|
+
* parseBindingListItem: (param: Node) => Node,
|
|
1177
|
+
* parseAssignableListItem: (allowModifiers?: boolean) => Node,
|
|
1178
|
+
* parseParenItem: (item: Expression | Node) => Expression,
|
|
1179
|
+
* shouldParseArrow: (exprList: Expression[]) => boolean,
|
|
1180
|
+
* parseParenArrowList: (startPos: number, startLoc: Position | undefined, exprList: Expression[], forInit?: boolean | string) => Expression,
|
|
1181
|
+
* finishNodeAt: (node: Node, type: string, pos: number, loc?: Position) => Node,
|
|
1182
|
+
* parseParenAndDistinguishExpression: (canBeArrow: boolean, forInit?: boolean | string) => Expression,
|
|
838
1183
|
* parseSubscripts: (base: Expression, startPos: number, startLoc: Position | undefined, noCalls?: boolean, forInit?: boolean | string) => Expression,
|
|
839
1184
|
* parseNew: () => Expression,
|
|
840
1185
|
* parseTemplateElement: (opts: { isTagged: boolean }) => Node,
|
|
@@ -851,7 +1196,9 @@ class Scope {
|
|
|
851
1196
|
* parseFunction: (node: Node, statement: number, allowExpressionBody?: boolean, isAsync?: boolean, forInit?: boolean | string) => Expression,
|
|
852
1197
|
* parseArrowExpression: (node: Node, params: Node[], isAsync: boolean, forInit?: boolean | string) => Expression,
|
|
853
1198
|
* _subscriptFastPath: boolean,
|
|
854
|
-
* checkLValSimple: (expr: Node, bindingType?: number) => void,
|
|
1199
|
+
* checkLValSimple: (expr: Node, bindingType?: number, checkClashes?: Record<string, boolean> | null) => void,
|
|
1200
|
+
* checkLValInnerPattern: (expr: Node, bindingType?: number, checkClashes?: Record<string, boolean> | null) => void,
|
|
1201
|
+
* declareName: (name: string, bindingType: number, pos: number) => void,
|
|
855
1202
|
* startNode: () => Node,
|
|
856
1203
|
* startNodeAt: (pos: number, loc?: Position) => Node,
|
|
857
1204
|
* finishNode: (node: Node, type: string) => Node,
|
|
@@ -867,6 +1214,19 @@ class Scope {
|
|
|
867
1214
|
* readNumber: (startsWithDot: boolean) => void,
|
|
868
1215
|
* readRadixNumber: (radix: number) => void,
|
|
869
1216
|
* readTmplToken: () => void,
|
|
1217
|
+
* invalidStringToken: (position: number, message: string) => void,
|
|
1218
|
+
* _readInt: (radix: number, len?: number, maybeLegacyOctal?: boolean) => number | null,
|
|
1219
|
+
* _readCodePoint: () => number,
|
|
1220
|
+
* _readHexChar: (len: number) => number,
|
|
1221
|
+
* _readEscapedChar: (inTemplate: boolean) => string,
|
|
1222
|
+
* _readStringCold: (quote: number) => void,
|
|
1223
|
+
* _readTmplTokenCold: () => void,
|
|
1224
|
+
* _readNumberCold: (startsWithDot: boolean) => void,
|
|
1225
|
+
* _readRadixNumber: (radix: number) => void,
|
|
1226
|
+
* _readWord1Cold: () => string,
|
|
1227
|
+
* _finishWordSlow: (word: string) => void,
|
|
1228
|
+
* _skipSpaceCold: () => void,
|
|
1229
|
+
* _getUnknownOrPrivate: (code: number) => void,
|
|
870
1230
|
* finishToken: (type: TokenType, value?: unknown) => void,
|
|
871
1231
|
* context: TokContextShim[],
|
|
872
1232
|
* pos: number,
|
|
@@ -902,6 +1262,20 @@ class Scope {
|
|
|
902
1262
|
* parseExprImport: (forNew: boolean) => Expression,
|
|
903
1263
|
* parseImportMeta: (node: Node) => Expression,
|
|
904
1264
|
* parseDynamicImport: (node: Node) => Expression,
|
|
1265
|
+
* updateContext: (prevType: TokenType) => void,
|
|
1266
|
+
* finishOp: (type: TokenType, size: number) => void,
|
|
1267
|
+
* readToken_dot: () => void,
|
|
1268
|
+
* readToken_slash: () => void,
|
|
1269
|
+
* readToken_mult_modulo_exp: (code: number) => void,
|
|
1270
|
+
* readToken_pipe_amp: (code: number) => void,
|
|
1271
|
+
* readToken_caret: () => void,
|
|
1272
|
+
* readToken_plus_min: (code: number) => void,
|
|
1273
|
+
* readToken_lt_gt: (code: number) => void,
|
|
1274
|
+
* readToken_eq_excl: (code: number) => void,
|
|
1275
|
+
* readToken_question: () => void,
|
|
1276
|
+
* readToken_numberSign: () => void,
|
|
1277
|
+
* _tokenFastPath: boolean,
|
|
1278
|
+
* _inlineFinish: boolean,
|
|
905
1279
|
* _lazy: boolean,
|
|
906
1280
|
* _importPhase: ImportPhase | null,
|
|
907
1281
|
* _importPhasesEnabled: boolean,
|
|
@@ -909,13 +1283,53 @@ class Scope {
|
|
|
909
1283
|
* _newlineBefore: 0 | 1 | 2,
|
|
910
1284
|
* _fullTokenFastPath: boolean,
|
|
911
1285
|
* _stmtFastPath: boolean,
|
|
1286
|
+
* _lastArrow: Expression | null,
|
|
1287
|
+
* _arrowFastPath: boolean,
|
|
1288
|
+
* labels: { kind?: string | null, name?: string, statementStart?: number }[],
|
|
1289
|
+
* initFunction: (node: Node) => void,
|
|
1290
|
+
* parseFunctionStatement: (node: Node, isAsync: boolean, declarationPosition: boolean) => Node,
|
|
1291
|
+
* parseFunctionBody: (node: Node, isArrowFunction: boolean, isMethod: boolean, forInit?: boolean | string) => void,
|
|
1292
|
+
* parseFunctionParams: (node: Node) => void,
|
|
1293
|
+
* isSimpleParamList: (params: Node[]) => boolean,
|
|
1294
|
+
* checkParams: (node: Node, allowDuplicates: boolean) => void,
|
|
1295
|
+
* adaptDirectivePrologue: (statements: Node[]) => void,
|
|
1296
|
+
* toAssignableList: (exprList: Node[], isBinding: boolean) => Node[],
|
|
1297
|
+
* parseBindingList: (close: TokenType, allowEmpty: boolean, allowTrailingComma: boolean, allowModifiers?: boolean) => Node[],
|
|
1298
|
+
* strictDirective: (start: number) => boolean,
|
|
1299
|
+
* _funcFastPath: boolean,
|
|
1300
|
+
* _funcStmtOwn: boolean,
|
|
1301
|
+
* _parseFunctionAt: (start: number, statement: number, allowExpressionBody: boolean, isAsync: boolean, forInit?: boolean | string) => Expression,
|
|
912
1302
|
* isLet: (context?: string | null) => boolean,
|
|
913
1303
|
* parseLabeledStatement: (node: Node, maybeName: string, expr: Identifier, context: string | null) => Node,
|
|
914
|
-
* _parseVarInto: (declarations: Node[], isFor: boolean, kind: string, allowMissingInitializer?: boolean) =>
|
|
1304
|
+
* _parseVarInto: (declarations: Node[], isFor: boolean, kind: string, allowMissingInitializer?: boolean) => number,
|
|
915
1305
|
* _parseVarStatementAt: (start: number, kind: string, allowMissingInitializer?: boolean) => Node,
|
|
916
1306
|
* _parseIfStatementAt: (start: number) => Node,
|
|
917
1307
|
* _parseReturnStatementAt: (start: number) => Node,
|
|
918
1308
|
* _parseExpressionStatementAt: (start: number, expr: Expression) => Node,
|
|
1309
|
+
* eatContextual: (name: string) => boolean,
|
|
1310
|
+
* isUsing: (isFor: boolean) => boolean,
|
|
1311
|
+
* isAwaitUsing: (isFor: boolean) => boolean,
|
|
1312
|
+
* parseForStatement: (node: Node) => Node,
|
|
1313
|
+
* parseFor: (node: Node, init: Node | null) => Node,
|
|
1314
|
+
* parseForIn: (node: Node, init: Node) => Node,
|
|
1315
|
+
* parseForAfterInit: (node: Node, init: Node, awaitAt: number) => Node,
|
|
1316
|
+
* parseWhileStatement: (node: Node) => Node,
|
|
1317
|
+
* parseSwitchStatement: (node: Node) => Node,
|
|
1318
|
+
* parseThrowStatement: (node: Node) => Node,
|
|
1319
|
+
* parseTryStatement: (node: Node) => Node,
|
|
1320
|
+
* parseBreakContinueStatement: (node: Node, keyword: string) => Node,
|
|
1321
|
+
* parseCatchClauseParam: () => Node,
|
|
1322
|
+
* _stmt2FastPath: boolean,
|
|
1323
|
+
* _exprFastPath: boolean,
|
|
1324
|
+
* _parseForStatementAt: (start: number) => Node,
|
|
1325
|
+
* _parseForAt: (start: number, init: Node | null) => Node,
|
|
1326
|
+
* _parseForInAt: (start: number, isAwait: boolean, init: Node) => Node,
|
|
1327
|
+
* _parseForAfterInitAt: (start: number, init: Node, awaitAt: number) => Node,
|
|
1328
|
+
* _parseWhileStatementAt: (start: number) => Node,
|
|
1329
|
+
* _parseSwitchStatementAt: (start: number) => Node,
|
|
1330
|
+
* _parseThrowStatementAt: (start: number) => Node,
|
|
1331
|
+
* _parseTryStatementAt: (start: number) => Node,
|
|
1332
|
+
* _parseBreakContinueStatementAt: (start: number, keyword: string) => Node,
|
|
919
1333
|
* _moduleFallback: boolean,
|
|
920
1334
|
* _moduleSyntaxSeen: boolean,
|
|
921
1335
|
* _tryModuleFallback: () => boolean,
|
|
@@ -993,6 +1407,10 @@ const createDestructuringErrors = () => {
|
|
|
993
1407
|
* @property {Map<string, ReservedKind>} reservedKinds identifier name → reserved kind
|
|
994
1408
|
* @property {number} reservedMaxLen longest key in `reservedKinds`
|
|
995
1409
|
* @property {{ test: (name: string) => boolean }} reservedBindTest strict-mode binding check, a Set-backed stand-in for acorn's `reservedWordsStrictBind` regexp
|
|
1410
|
+
* @property {Set<string>} reservedBindSet strict-mode binding-reserved names
|
|
1411
|
+
* @property {number} reservedBindMinLen shortest key in `reservedBindSet`
|
|
1412
|
+
* @property {number} reservedBindMaxLen longest key in `reservedBindSet`
|
|
1413
|
+
* @property {number} id owner tag for the shared `WORD_TYPES` classification memo
|
|
996
1414
|
*/
|
|
997
1415
|
|
|
998
1416
|
// One entry per distinct keyword/reserved-word set; webpack parses with a
|
|
@@ -1001,20 +1419,6 @@ const createDestructuringErrors = () => {
|
|
|
1001
1419
|
/** @type {Map<string, WordLookups>} */
|
|
1002
1420
|
const wordLookupsCache = new Map();
|
|
1003
1421
|
|
|
1004
|
-
/**
|
|
1005
|
-
* @param {string} word interned candidate
|
|
1006
|
-
* @param {string} input source code
|
|
1007
|
-
* @param {number} start word start offset
|
|
1008
|
-
* @param {number} len word length (already known equal to `word.length`)
|
|
1009
|
-
* @returns {boolean} whether the source span spells `word`
|
|
1010
|
-
*/
|
|
1011
|
-
const sameWord = (word, input, start, len) => {
|
|
1012
|
-
for (let i = 0; i < len; i++) {
|
|
1013
|
-
if (word.charCodeAt(i) !== input.charCodeAt(start + i)) return false;
|
|
1014
|
-
}
|
|
1015
|
-
return true;
|
|
1016
|
-
};
|
|
1017
|
-
|
|
1018
1422
|
// Direct-mapped identifier cache for `readWord1`: one slot per hash, verified
|
|
1019
1423
|
// by char compare, overwritten on collision. Shared across parses — hits are
|
|
1020
1424
|
// content-checked, so a stale entry is merely a miss. Only words short enough
|
|
@@ -1024,12 +1428,60 @@ const WORD_CACHE_MASK = 0x1fff;
|
|
|
1024
1428
|
const WORD_CACHE = Array.from({ length: WORD_CACHE_MASK + 1 }, () => null);
|
|
1025
1429
|
const WORD_CACHE_MAX_LEN = 12;
|
|
1026
1430
|
|
|
1431
|
+
// Classification memo parallel to `WORD_CACHE`, same slot: every cache write
|
|
1432
|
+
// also writes the word's token type plus the id of the keyword set that
|
|
1433
|
+
// classified it, so a hit skips `classifyWord` and another option set (or a
|
|
1434
|
+
// `readWord1` write, owner 0) invalidates instead of mis-classifying. Keying
|
|
1435
|
+
// by the cache's own slot adds no extra string references — the memo can
|
|
1436
|
+
// never retain a word the cache itself dropped.
|
|
1437
|
+
/** @type {(TokenType | null)[]} */
|
|
1438
|
+
const WORD_TYPES = Array.from({ length: WORD_CACHE_MASK + 1 }, () => null);
|
|
1439
|
+
const WORD_TYPE_OWNERS = new Int32Array(WORD_CACHE_MASK + 1);
|
|
1440
|
+
let nextWordLookupsId = 1;
|
|
1441
|
+
|
|
1442
|
+
/**
|
|
1443
|
+
* Keyword-or-name classification: pure in (word, keywords), so it can be
|
|
1444
|
+
* memoized per `WORD_CACHE` slot.
|
|
1445
|
+
* @param {string} word word
|
|
1446
|
+
* @param {Map<string, TokenType>} keywords keyword name → token type
|
|
1447
|
+
* @returns {TokenType} token type for `word`
|
|
1448
|
+
*/
|
|
1449
|
+
const classifyWord = (word, keywords) => {
|
|
1450
|
+
const len = word.length;
|
|
1451
|
+
// every acorn keyword is 2-10 lowercase ASCII chars (`do`…`instanceof`)
|
|
1452
|
+
if (len >= 2 && len <= 10) {
|
|
1453
|
+
const first = word.charCodeAt(0);
|
|
1454
|
+
if (first >= 97 && first <= 122) return keywords.get(word) || tokTypes.name;
|
|
1455
|
+
}
|
|
1456
|
+
return tokTypes.name;
|
|
1457
|
+
};
|
|
1458
|
+
|
|
1027
1459
|
// Multi-char operator strings for `finishOp` (`=>`, `===`, `&&=`, …), keyed by
|
|
1028
1460
|
// their char codes packed 7 bits apart — collision-free for ASCII operators up
|
|
1029
1461
|
// to acorn's maximum of 4 chars (`>>>=`), so the set stays ~40 entries.
|
|
1030
1462
|
/** @type {Map<number, string>} */
|
|
1031
1463
|
const OP_CACHE = new Map();
|
|
1032
1464
|
|
|
1465
|
+
// The regexp flag whitelist depends only on the ecmaVersion, so build one
|
|
1466
|
+
// string per version instead of a fresh one in every parser constructor.
|
|
1467
|
+
/** @type {Map<number, string>} */
|
|
1468
|
+
const VALID_REGEXP_FLAGS = new Map();
|
|
1469
|
+
|
|
1470
|
+
/**
|
|
1471
|
+
* @param {number} ecmaVersion normalized acorn ecmaVersion
|
|
1472
|
+
* @returns {string} the regexp flags allowed at `ecmaVersion`
|
|
1473
|
+
*/
|
|
1474
|
+
const getValidRegexpFlags = (ecmaVersion) => {
|
|
1475
|
+
let flags = VALID_REGEXP_FLAGS.get(ecmaVersion);
|
|
1476
|
+
if (flags === undefined) {
|
|
1477
|
+
flags = `gim${ecmaVersion >= 6 ? "uy" : ""}${ecmaVersion >= 9 ? "s" : ""}${
|
|
1478
|
+
ecmaVersion >= 13 ? "d" : ""
|
|
1479
|
+
}${ecmaVersion >= 15 ? "v" : ""}`;
|
|
1480
|
+
VALID_REGEXP_FLAGS.set(ecmaVersion, flags);
|
|
1481
|
+
}
|
|
1482
|
+
return flags;
|
|
1483
|
+
};
|
|
1484
|
+
|
|
1033
1485
|
// Sticky mirrors of acorn's `skipWhiteSpace` / string-literal / `lineBreak`
|
|
1034
1486
|
// regexes for the owned `strictDirective` (they scan at an offset, no slice).
|
|
1035
1487
|
const STRICT_SKIP_WS = /(?:\s|\/\/.*|\/\*[^]*?\*\/)*/g;
|
|
@@ -1101,6 +1553,14 @@ const getWordLookups = (parser) => {
|
|
|
1101
1553
|
// keyword classification wins, matching acorn's keyword-first check
|
|
1102
1554
|
for (const name of keywords.keys()) reservedKinds.set(name, 1);
|
|
1103
1555
|
const reservedBind = wordsRegexpToSet(parser.reservedWordsStrictBind);
|
|
1556
|
+
// length bounds so the owned checkLValSimple can skip the Set probe for
|
|
1557
|
+
// most identifiers
|
|
1558
|
+
let reservedBindMinLen = 0x7fffffff;
|
|
1559
|
+
let reservedBindMaxLen = 0;
|
|
1560
|
+
for (const name of reservedBind) {
|
|
1561
|
+
if (name.length < reservedBindMinLen) reservedBindMinLen = name.length;
|
|
1562
|
+
if (name.length > reservedBindMaxLen) reservedBindMaxLen = name.length;
|
|
1563
|
+
}
|
|
1104
1564
|
let reservedMaxLen = 0;
|
|
1105
1565
|
for (const name of reservedKinds.keys()) {
|
|
1106
1566
|
if (name.length > reservedMaxLen) reservedMaxLen = name.length;
|
|
@@ -1110,7 +1570,11 @@ const getWordLookups = (parser) => {
|
|
|
1110
1570
|
keywords,
|
|
1111
1571
|
reservedKinds,
|
|
1112
1572
|
reservedMaxLen,
|
|
1113
|
-
reservedBindTest: { test: (name) => reservedBind.has(name) }
|
|
1573
|
+
reservedBindTest: { test: (name) => reservedBind.has(name) },
|
|
1574
|
+
reservedBindSet: reservedBind,
|
|
1575
|
+
reservedBindMinLen,
|
|
1576
|
+
reservedBindMaxLen,
|
|
1577
|
+
id: nextWordLookupsId++
|
|
1114
1578
|
};
|
|
1115
1579
|
wordLookupsCache.set(key, lookups);
|
|
1116
1580
|
lastWordLookups = lookups;
|
|
@@ -1189,9 +1653,50 @@ class WebpackParser extends BaseParser {
|
|
|
1189
1653
|
// the owned parseSubscript assumes optional chaining exists (it bakes
|
|
1190
1654
|
// `optional` into the node shape), so gate it on the normalized version
|
|
1191
1655
|
this._subscriptFastPath = lazy && this._ecmaVersion >= 11;
|
|
1656
|
+
const proto = WebpackParser.prototype;
|
|
1657
|
+
const self = /** @type {ParserInternals} */ (/** @type {unknown} */ (this));
|
|
1658
|
+
// the owned per-token loop (nextToken/finishToken/next) also serves the
|
|
1659
|
+
// public non-lazy tokenizer(): locations off, no onToken, and none of the
|
|
1660
|
+
// acorn tokenizer methods it inlines or skips overridden by a plugin
|
|
1661
|
+
// (`nextToken`'s punct/dot/eq shortcuts bypass `getTokenFromCode`,
|
|
1662
|
+
// `finishOp`, `readToken_dot` and `readToken_eq_excl` even when the full
|
|
1663
|
+
// token path below is off, so their overrides must gate this loop too)
|
|
1664
|
+
this._tokenFastPath =
|
|
1665
|
+
lazy ||
|
|
1666
|
+
(this._noLocations &&
|
|
1667
|
+
!normalizedOptions.onToken &&
|
|
1668
|
+
this.nextToken === proto.nextToken &&
|
|
1669
|
+
this.finishToken === proto.finishToken &&
|
|
1670
|
+
this.next === proto.next &&
|
|
1671
|
+
this.skipSpace === proto.skipSpace &&
|
|
1672
|
+
this.getTokenFromCode === proto.getTokenFromCode &&
|
|
1673
|
+
this.finishOp === proto.finishOp &&
|
|
1674
|
+
self.readToken === base.readToken &&
|
|
1675
|
+
self.updateContext === base.updateContext &&
|
|
1676
|
+
self.readToken_dot === base.readToken_dot &&
|
|
1677
|
+
self.readToken_eq_excl === base.readToken_eq_excl);
|
|
1192
1678
|
// the owned getTokenFromCode bakes in every ES2021 operator (?., ??=,
|
|
1193
|
-
// &&=, ...), so it needs at least that version
|
|
1194
|
-
|
|
1679
|
+
// &&=, ...), so it needs at least that version; outside lazy mode it also
|
|
1680
|
+
// bypasses acorn's readToken_* family, so any override there turns it off
|
|
1681
|
+
this._fullTokenFastPath =
|
|
1682
|
+
this._ecmaVersion >= 12 &&
|
|
1683
|
+
(lazy ||
|
|
1684
|
+
(this._tokenFastPath &&
|
|
1685
|
+
self.readToken_slash === base.readToken_slash &&
|
|
1686
|
+
self.readToken_mult_modulo_exp === base.readToken_mult_modulo_exp &&
|
|
1687
|
+
self.readToken_pipe_amp === base.readToken_pipe_amp &&
|
|
1688
|
+
self.readToken_caret === base.readToken_caret &&
|
|
1689
|
+
self.readToken_plus_min === base.readToken_plus_min &&
|
|
1690
|
+
self.readToken_lt_gt === base.readToken_lt_gt &&
|
|
1691
|
+
self.readToken_question === base.readToken_question &&
|
|
1692
|
+
self.readToken_numberSign === base.readToken_numberSign &&
|
|
1693
|
+
self.readRadixNumber === base.readRadixNumber));
|
|
1694
|
+
// the owned nextToken/readWord finish the commonest tokens in place,
|
|
1695
|
+
// which skips this.finishToken: needs the fast token loop (readWord runs
|
|
1696
|
+
// in every mode) and no finishToken override by a plugin
|
|
1697
|
+
this._inlineFinish =
|
|
1698
|
+
this._tokenFastPath &&
|
|
1699
|
+
this.finishToken === WebpackParser.prototype.finishToken;
|
|
1195
1700
|
// whether the gap before the current token holds a line terminator:
|
|
1196
1701
|
// 0 no, 1 yes, 2 unknown (canInsertSemicolon then scans the gap)
|
|
1197
1702
|
/** @type {0 | 1 | 2} */
|
|
@@ -1210,13 +1715,16 @@ class WebpackParser extends BaseParser {
|
|
|
1210
1715
|
/** @type {{ proto: boolean }[]} */
|
|
1211
1716
|
this._propHashStack = [];
|
|
1212
1717
|
this._propHashDepth = 0;
|
|
1718
|
+
// LIFO pool of scratch arrays for list productions: elements are written
|
|
1719
|
+
// by index, then copied out exactly sized — a push-grown array retains
|
|
1720
|
+
// ~17 slots of capacity slack per list otherwise
|
|
1721
|
+
/** @type {unknown[][]} */
|
|
1722
|
+
this._arrStack = [];
|
|
1723
|
+
this._arrDepth = 0;
|
|
1213
1724
|
// `readRegexp`'s flag whitelist depends only on the ecmaVersion
|
|
1214
|
-
this._validRegexpFlags =
|
|
1215
|
-
this._ecmaVersion >= 9 ? "s" : ""
|
|
1216
|
-
}${this._ecmaVersion >= 13 ? "d" : ""}${this._ecmaVersion >= 15 ? "v" : ""}`;
|
|
1725
|
+
this._validRegexpFlags = getValidRegexpFlags(this._ecmaVersion);
|
|
1217
1726
|
// the owned parseStatement inlines these methods, so a parser plugin
|
|
1218
1727
|
// overriding any of them turns the statement fast path off
|
|
1219
|
-
const proto = WebpackParser.prototype;
|
|
1220
1728
|
this._stmtFastPath =
|
|
1221
1729
|
lazy &&
|
|
1222
1730
|
this.parseVarStatement === proto.parseVarStatement &&
|
|
@@ -1224,6 +1732,62 @@ class WebpackParser extends BaseParser {
|
|
|
1224
1732
|
this.parseIfStatement === proto.parseIfStatement &&
|
|
1225
1733
|
this.parseReturnStatement === proto.parseReturnStatement &&
|
|
1226
1734
|
this.parseExpressionStatement === proto.parseExpressionStatement;
|
|
1735
|
+
// last arrow finished by parseArrowExpression: `expr === this._lastArrow`
|
|
1736
|
+
// replaces the megamorphic `expr.type === "ArrowFunctionExpression"`
|
|
1737
|
+
// probes on the expression spine (arrows are created in exactly one place
|
|
1738
|
+
// and never backtracked, so identity captures the type test)
|
|
1739
|
+
/** @type {Expression | null} */
|
|
1740
|
+
this._lastArrow = null;
|
|
1741
|
+
// arrows must flow through parseArrowExpression for the identity probe;
|
|
1742
|
+
// a plugin overriding it falls back to the type-based probes
|
|
1743
|
+
this._arrowFastPath =
|
|
1744
|
+
lazy && this.parseArrowExpression === proto.parseArrowExpression;
|
|
1745
|
+
// the owned parseFunction/parseFunctionBody inline initFunction and
|
|
1746
|
+
// isSimpleParamList; a plugin overriding either turns the fast path off
|
|
1747
|
+
const internals = /** @type {ParserInternals} */ (
|
|
1748
|
+
/** @type {unknown} */ (this)
|
|
1749
|
+
);
|
|
1750
|
+
this._funcFastPath =
|
|
1751
|
+
lazy &&
|
|
1752
|
+
this._ecmaVersion >= 9 &&
|
|
1753
|
+
internals.initFunction === base.initFunction &&
|
|
1754
|
+
internals.isSimpleParamList === base.isSimpleParamList;
|
|
1755
|
+
// the owned parseStatement inlines parseFunctionStatement's body
|
|
1756
|
+
this._funcStmtOwn =
|
|
1757
|
+
this._funcFastPath &&
|
|
1758
|
+
internals.parseFunctionStatement === base.parseFunctionStatement &&
|
|
1759
|
+
this.parseFunction === proto.parseFunction;
|
|
1760
|
+
// the owned parseStatement inlines these statement parsers too; any
|
|
1761
|
+
// override falls back to acorn's dispatch for these heads
|
|
1762
|
+
this._stmt2FastPath =
|
|
1763
|
+
lazy &&
|
|
1764
|
+
this._ecmaVersion >= 9 &&
|
|
1765
|
+
internals.parseForStatement === base.parseForStatement &&
|
|
1766
|
+
internals.parseFor === base.parseFor &&
|
|
1767
|
+
internals.parseForIn === base.parseForIn &&
|
|
1768
|
+
internals.parseForAfterInit === base.parseForAfterInit &&
|
|
1769
|
+
this.parseVar === proto.parseVar &&
|
|
1770
|
+
internals.parseWhileStatement === base.parseWhileStatement &&
|
|
1771
|
+
internals.parseSwitchStatement === base.parseSwitchStatement &&
|
|
1772
|
+
internals.parseThrowStatement === base.parseThrowStatement &&
|
|
1773
|
+
internals.parseTryStatement === base.parseTryStatement &&
|
|
1774
|
+
internals.parseBreakContinueStatement ===
|
|
1775
|
+
base.parseBreakContinueStatement;
|
|
1776
|
+
// `parseMaybeAssign`'s trivial-atom fast path returns the atom without
|
|
1777
|
+
// descending the seven-layer expression chain, so every layer it skips
|
|
1778
|
+
// must be the owned one
|
|
1779
|
+
this._exprFastPath =
|
|
1780
|
+
lazy &&
|
|
1781
|
+
this.parseMaybeConditional === proto.parseMaybeConditional &&
|
|
1782
|
+
this.parseExprOps === proto.parseExprOps &&
|
|
1783
|
+
this.parseExprOp === proto.parseExprOp &&
|
|
1784
|
+
this.parseMaybeUnary === proto.parseMaybeUnary &&
|
|
1785
|
+
this.parseExprSubscripts === proto.parseExprSubscripts &&
|
|
1786
|
+
this.parseSubscripts === proto.parseSubscripts &&
|
|
1787
|
+
this.parseSubscript === proto.parseSubscript &&
|
|
1788
|
+
this.parseExprAtom === proto.parseExprAtom &&
|
|
1789
|
+
this.checkExpressionErrors === proto.checkExpressionErrors &&
|
|
1790
|
+
internals.isContextual === base.isContextual;
|
|
1227
1791
|
}
|
|
1228
1792
|
|
|
1229
1793
|
/**
|
|
@@ -1258,27 +1822,62 @@ class WebpackParser extends BaseParser {
|
|
|
1258
1822
|
this._deDepth--;
|
|
1259
1823
|
}
|
|
1260
1824
|
|
|
1825
|
+
/**
|
|
1826
|
+
* Fetches a scratch array for a list production: write elements by index,
|
|
1827
|
+
* then materialize with `_releaseScratch`. Entries past the caller's write
|
|
1828
|
+
* index are stale and meaningless.
|
|
1829
|
+
* @returns {EXPECTED_ANY[]} scratch array
|
|
1830
|
+
* @this {ParserInternals}
|
|
1831
|
+
*/
|
|
1832
|
+
_acquireScratch() {
|
|
1833
|
+
const stack = this._arrStack;
|
|
1834
|
+
const depth = this._arrDepth++;
|
|
1835
|
+
const cached = stack[depth];
|
|
1836
|
+
if (cached !== undefined) return cached;
|
|
1837
|
+
return (stack[depth] = []);
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
/**
|
|
1841
|
+
* @param {EXPECTED_ANY[]} scratch scratch array from `_acquireScratch`
|
|
1842
|
+
* @param {number} count number of elements written
|
|
1843
|
+
* @returns {EXPECTED_ANY[]} exactly-sized copy of the first `count` entries
|
|
1844
|
+
* @this {ParserInternals}
|
|
1845
|
+
*/
|
|
1846
|
+
_releaseScratch(scratch, count) {
|
|
1847
|
+
this._arrDepth--;
|
|
1848
|
+
return scratch.slice(0, count);
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1261
1851
|
// ----- tokenizer fast paths -----
|
|
1262
1852
|
|
|
1263
1853
|
/**
|
|
1264
1854
|
* Owned per-token loop: acorn's `nextToken` chains `skipSpace` →
|
|
1265
1855
|
* `fullCharCodeAtPos` → `readToken` → `isIdentifierStart` with a dead
|
|
1266
|
-
* `locations` check at each step. For the common
|
|
1856
|
+
* `locations` check at each step. For the common non-template context of
|
|
1857
|
+
* `_tokenFastPath` mode (lazy, or locations-off with no tokenizer overrides)
|
|
1267
1858
|
* this folds whitespace and comment skipping and the ASCII token dispatch
|
|
1268
1859
|
* into one function so nothing re-enters acorn's per-step option checks.
|
|
1269
|
-
* Template/`preserveSpace` contexts and
|
|
1860
|
+
* Template/`preserveSpace` contexts and other modes use acorn's tokenizer.
|
|
1861
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
1270
1862
|
* @returns {void}
|
|
1271
1863
|
* @this {ParserInternals}
|
|
1272
1864
|
*/
|
|
1273
1865
|
nextToken() {
|
|
1274
1866
|
const context = this.context;
|
|
1275
1867
|
const curContext = context[context.length - 1];
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1868
|
+
let slow;
|
|
1869
|
+
if (curContext !== undefined) {
|
|
1870
|
+
const flagged =
|
|
1871
|
+
/** @type {TokContextShim & { [kSlowContext]?: boolean }} */
|
|
1872
|
+
(curContext);
|
|
1873
|
+
slow = flagged[kSlowContext];
|
|
1874
|
+
if (slow === undefined) {
|
|
1875
|
+
slow = flagged[kSlowContext] = Boolean(
|
|
1876
|
+
curContext.preserveSpace || curContext.override
|
|
1877
|
+
);
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
if (!this._tokenFastPath || curContext === undefined || slow) {
|
|
1282
1881
|
this._newlineBefore = 2;
|
|
1283
1882
|
return base.nextToken.call(this);
|
|
1284
1883
|
}
|
|
@@ -1300,9 +1899,9 @@ class WebpackParser extends BaseParser {
|
|
|
1300
1899
|
cls = CHAR_CLASS[code];
|
|
1301
1900
|
if (cls < CLS_SPACE) {
|
|
1302
1901
|
if (cls === CLS_UNICODE) {
|
|
1303
|
-
// unicode whitespace / line terminators:
|
|
1902
|
+
// unicode whitespace / line terminators: the cold reader consumes them
|
|
1304
1903
|
this.pos = pos;
|
|
1305
|
-
|
|
1904
|
+
this._skipSpaceCold();
|
|
1306
1905
|
pos = this.pos;
|
|
1307
1906
|
if (newline === 0) newline = 2;
|
|
1308
1907
|
code = pos < len ? input.charCodeAt(pos) : 0;
|
|
@@ -1342,9 +1941,71 @@ class WebpackParser extends BaseParser {
|
|
|
1342
1941
|
switch (cls) {
|
|
1343
1942
|
case CLS_IDENT:
|
|
1344
1943
|
return this.readWord();
|
|
1345
|
-
case CLS_PUNCT:
|
|
1944
|
+
case CLS_PUNCT: {
|
|
1945
|
+
const type = /** @type {TokenType} */ (SIMPLE_PUNCT[code]);
|
|
1346
1946
|
this.pos = pos + 1;
|
|
1347
|
-
return this.finishToken(
|
|
1947
|
+
if (!this._inlineFinish) return this.finishToken(type);
|
|
1948
|
+
// finishToken inlined for the simple punctuators (no value, and
|
|
1949
|
+
// their context updates are per-char static)
|
|
1950
|
+
this.end = pos + 1;
|
|
1951
|
+
const prevType = this.type;
|
|
1952
|
+
this.type = type;
|
|
1953
|
+
this.value = undefined;
|
|
1954
|
+
switch (code) {
|
|
1955
|
+
case 41:
|
|
1956
|
+
case 125: {
|
|
1957
|
+
// parenR/braceR.updateContext, inlined
|
|
1958
|
+
if (context.length === 1) {
|
|
1959
|
+
this.exprAllowed = true;
|
|
1960
|
+
break;
|
|
1961
|
+
}
|
|
1962
|
+
let out = /** @type {TokContextShim} */ (context.pop());
|
|
1963
|
+
if (
|
|
1964
|
+
out === CTX_B_STAT &&
|
|
1965
|
+
/** @type {TokContextShim} */ (context[context.length - 1])
|
|
1966
|
+
.token === "function"
|
|
1967
|
+
) {
|
|
1968
|
+
out = /** @type {TokContextShim} */ (context.pop());
|
|
1969
|
+
}
|
|
1970
|
+
this.exprAllowed = !out.isExpr;
|
|
1971
|
+
break;
|
|
1972
|
+
}
|
|
1973
|
+
case 123:
|
|
1974
|
+
// braceL.updateContext, inlined
|
|
1975
|
+
context.push(this.braceIsBlock(prevType) ? CTX_B_STAT : CTX_B_EXPR);
|
|
1976
|
+
this.exprAllowed = true;
|
|
1977
|
+
break;
|
|
1978
|
+
case 40: {
|
|
1979
|
+
// parenL.updateContext, inlined
|
|
1980
|
+
const statementParens =
|
|
1981
|
+
prevType === tokTypes._if ||
|
|
1982
|
+
prevType === tokTypes._for ||
|
|
1983
|
+
prevType === tokTypes._with ||
|
|
1984
|
+
prevType === tokTypes._while;
|
|
1985
|
+
context.push(statementParens ? CTX_P_STAT : CTX_P_EXPR);
|
|
1986
|
+
this.exprAllowed = true;
|
|
1987
|
+
break;
|
|
1988
|
+
}
|
|
1989
|
+
case 58:
|
|
1990
|
+
// colon.updateContext, inlined
|
|
1991
|
+
if (
|
|
1992
|
+
/** @type {TokContextShim} */ (context[context.length - 1])
|
|
1993
|
+
.token === "function"
|
|
1994
|
+
) {
|
|
1995
|
+
context.pop();
|
|
1996
|
+
}
|
|
1997
|
+
this.exprAllowed = true;
|
|
1998
|
+
break;
|
|
1999
|
+
case 93:
|
|
2000
|
+
// bracketR: no context hook, beforeExpr is false
|
|
2001
|
+
this.exprAllowed = false;
|
|
2002
|
+
break;
|
|
2003
|
+
default:
|
|
2004
|
+
// semi, comma, bracketL: no context hook, beforeExpr is true
|
|
2005
|
+
this.exprAllowed = true;
|
|
2006
|
+
}
|
|
2007
|
+
return;
|
|
2008
|
+
}
|
|
1348
2009
|
case CLS_DOT: {
|
|
1349
2010
|
// `.` not starting `.5` or `...`: skip readToken_dot's re-dispatch
|
|
1350
2011
|
const next = input.charCodeAt(pos + 1);
|
|
@@ -1371,17 +2032,18 @@ class WebpackParser extends BaseParser {
|
|
|
1371
2032
|
}
|
|
1372
2033
|
|
|
1373
2034
|
/**
|
|
1374
|
-
*
|
|
1375
|
-
* `endLoc` write on every token and reaches `updateContext` through an
|
|
1376
|
-
* method call. Skip the probe and inline acorn's `updateContext` body —
|
|
1377
|
-
* runs once per token. Other modes use acorn's.
|
|
2035
|
+
* `_tokenFastPath` `finishToken`: acorn probes `options.locations` for a
|
|
2036
|
+
* dead `endLoc` write on every token and reaches `updateContext` through an
|
|
2037
|
+
* extra method call. Skip the probe and inline acorn's `updateContext` body —
|
|
2038
|
+
* this runs once per token. Other modes use acorn's.
|
|
2039
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
1378
2040
|
* @param {TokenType} type token type
|
|
1379
2041
|
* @param {unknown=} value token value
|
|
1380
2042
|
* @returns {void}
|
|
1381
2043
|
* @this {ParserInternals}
|
|
1382
2044
|
*/
|
|
1383
2045
|
finishToken(type, value) {
|
|
1384
|
-
if (!this.
|
|
2046
|
+
if (!this._tokenFastPath) {
|
|
1385
2047
|
return base.finishToken.call(this, type, value);
|
|
1386
2048
|
}
|
|
1387
2049
|
this.end = this.pos;
|
|
@@ -1400,41 +2062,53 @@ class WebpackParser extends BaseParser {
|
|
|
1400
2062
|
(value === "yield" && this.inGeneratorContext())) &&
|
|
1401
2063
|
prevType !== tokTypes.dot &&
|
|
1402
2064
|
this._ecmaVersion >= 6;
|
|
1403
|
-
} else
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
2065
|
+
} else {
|
|
2066
|
+
const update = internal.updateContext;
|
|
2067
|
+
if (update === null) {
|
|
2068
|
+
// no context hook (most punctuation, operators, literals and
|
|
2069
|
+
// keywords): acorn's keyword-after-dot probe, else `beforeExpr` —
|
|
2070
|
+
// checked first so this majority skips the per-type compares below
|
|
2071
|
+
this.exprAllowed =
|
|
2072
|
+
prevType === tokTypes.dot && internal.keyword !== undefined
|
|
2073
|
+
? false
|
|
2074
|
+
: internal.beforeExpr;
|
|
2075
|
+
} else if (type === tokTypes.parenR || type === tokTypes.braceR) {
|
|
2076
|
+
// parenR/braceR.updateContext, inlined
|
|
2077
|
+
const context = this.context;
|
|
2078
|
+
if (context.length === 1) {
|
|
2079
|
+
this.exprAllowed = true;
|
|
2080
|
+
} else {
|
|
2081
|
+
let out = /** @type {TokContextShim} */ (context.pop());
|
|
2082
|
+
if (
|
|
2083
|
+
out === CTX_B_STAT &&
|
|
2084
|
+
/** @type {TokContextShim} */ (context[context.length - 1])
|
|
2085
|
+
.token === "function"
|
|
2086
|
+
) {
|
|
2087
|
+
out = /** @type {TokContextShim} */ (context.pop());
|
|
2088
|
+
}
|
|
2089
|
+
this.exprAllowed = !out.isExpr;
|
|
2090
|
+
}
|
|
2091
|
+
} else if (type === tokTypes.braceL) {
|
|
2092
|
+
// braceL.updateContext, inlined
|
|
2093
|
+
this.context.push(
|
|
2094
|
+
this.braceIsBlock(prevType) ? CTX_B_STAT : CTX_B_EXPR
|
|
2095
|
+
);
|
|
1409
2096
|
this.exprAllowed = true;
|
|
2097
|
+
} else if (type === tokTypes.parenL) {
|
|
2098
|
+
// parenL.updateContext, inlined
|
|
2099
|
+
const statementParens =
|
|
2100
|
+
prevType === tokTypes._if ||
|
|
2101
|
+
prevType === tokTypes._for ||
|
|
2102
|
+
prevType === tokTypes._with ||
|
|
2103
|
+
prevType === tokTypes._while;
|
|
2104
|
+
this.context.push(statementParens ? CTX_P_STAT : CTX_P_EXPR);
|
|
2105
|
+
this.exprAllowed = true;
|
|
2106
|
+
} else if (internal.keyword !== undefined && prevType === tokTypes.dot) {
|
|
2107
|
+
// `.function` etc.: keyword-after-dot wins over the type's own hook
|
|
2108
|
+
this.exprAllowed = false;
|
|
1410
2109
|
} else {
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
out === CTX_B_STAT &&
|
|
1414
|
-
/** @type {TokContextShim} */ (context[context.length - 1]).token ===
|
|
1415
|
-
"function"
|
|
1416
|
-
) {
|
|
1417
|
-
out = /** @type {TokContextShim} */ (context.pop());
|
|
1418
|
-
}
|
|
1419
|
-
this.exprAllowed = !out.isExpr;
|
|
1420
|
-
}
|
|
1421
|
-
} else if (type === tokTypes.braceL) {
|
|
1422
|
-
// braceL.updateContext, inlined
|
|
1423
|
-
this.context.push(this.braceIsBlock(prevType) ? CTX_B_STAT : CTX_B_EXPR);
|
|
1424
|
-
this.exprAllowed = true;
|
|
1425
|
-
} else if (type === tokTypes.parenL) {
|
|
1426
|
-
// parenL.updateContext, inlined
|
|
1427
|
-
const statementParens =
|
|
1428
|
-
prevType === tokTypes._if ||
|
|
1429
|
-
prevType === tokTypes._for ||
|
|
1430
|
-
prevType === tokTypes._with ||
|
|
1431
|
-
prevType === tokTypes._while;
|
|
1432
|
-
this.context.push(statementParens ? CTX_P_STAT : CTX_P_EXPR);
|
|
1433
|
-
this.exprAllowed = true;
|
|
1434
|
-
} else if (internal.updateContext) {
|
|
1435
|
-
internal.updateContext.call(this, prevType);
|
|
1436
|
-
} else {
|
|
1437
|
-
this.exprAllowed = internal.beforeExpr;
|
|
2110
|
+
update.call(this, prevType);
|
|
2111
|
+
}
|
|
1438
2112
|
}
|
|
1439
2113
|
}
|
|
1440
2114
|
|
|
@@ -1442,6 +2116,7 @@ class WebpackParser extends BaseParser {
|
|
|
1442
2116
|
* Owned `braceIsBlock`, acorn's verbatim except the line-terminator probe:
|
|
1443
2117
|
* acorn slices the inter-token gap and runs a regexp; `_gapHasNewline`
|
|
1444
2118
|
* answers from the tokenizer's newline flag (scanning only when unknown).
|
|
2119
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokencontext.js
|
|
1445
2120
|
* @param {TokenType} prevType type of the previous token
|
|
1446
2121
|
* @returns {boolean} whether a `{` opens a block in this context
|
|
1447
2122
|
* @this {ParserInternals}
|
|
@@ -1513,18 +2188,21 @@ class WebpackParser extends BaseParser {
|
|
|
1513
2188
|
/**
|
|
1514
2189
|
* Owned per-token advance: acorn's `next` writes `lastTokEndLoc`/
|
|
1515
2190
|
* `lastTokStartLoc` and probes `options.onToken` on every token, both dead in
|
|
1516
|
-
*
|
|
1517
|
-
* writes and the keyword-escape guard. Other modes use acorn's.
|
|
2191
|
+
* `_tokenFastPath` mode (locations off, no token stream), leaving only the
|
|
2192
|
+
* two offset writes and the keyword-escape guard. Other modes use acorn's.
|
|
2193
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
1518
2194
|
* @param {boolean=} ignoreEscapeSequenceInKeyword whether an escape in a keyword is allowed here
|
|
1519
2195
|
* @returns {void}
|
|
1520
2196
|
* @this {ParserInternals}
|
|
1521
2197
|
*/
|
|
1522
2198
|
next(ignoreEscapeSequenceInKeyword) {
|
|
1523
|
-
if (!this.
|
|
2199
|
+
if (!this._tokenFastPath) {
|
|
1524
2200
|
return base.next.call(this, ignoreEscapeSequenceInKeyword);
|
|
1525
2201
|
}
|
|
1526
2202
|
const type = this.type;
|
|
1527
|
-
|
|
2203
|
+
// `containsEsc` is a parser field and almost always false; testing it first
|
|
2204
|
+
// keeps the TokenType load off the common path.
|
|
2205
|
+
if (this.containsEsc && !ignoreEscapeSequenceInKeyword && type.keyword) {
|
|
1528
2206
|
this.raiseRecoverable(
|
|
1529
2207
|
this.start,
|
|
1530
2208
|
`Escape sequence in keyword ${type.keyword}`
|
|
@@ -1540,6 +2218,7 @@ class WebpackParser extends BaseParser {
|
|
|
1540
2218
|
* every operator token, allocating a fresh 2-4 char string per `=>`, `===`,
|
|
1541
2219
|
* `&&` etc. Serve those from `OP_CACHE` instead; single-char operators keep
|
|
1542
2220
|
* the direct slice, which V8 serves from its single-character table.
|
|
2221
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
1543
2222
|
* @param {TokenType} type token type
|
|
1544
2223
|
* @param {number} size operator length
|
|
1545
2224
|
* @returns {void}
|
|
@@ -1571,7 +2250,9 @@ class WebpackParser extends BaseParser {
|
|
|
1571
2250
|
* `readToken_*` methods that each end in `finishOp`'s source slice. Resolve
|
|
1572
2251
|
* every operator by direct char peeks to a static string instead (yuku's
|
|
1573
2252
|
* `scanPunctuation`) — no method chain, no slice, no `OP_CACHE` probe. The
|
|
1574
|
-
* HTML-comment forms (`<!--`, `-->`)
|
|
2253
|
+
* HTML-comment forms (`<!--`, `-->`) inline acorn's line-comment handling;
|
|
2254
|
+
* `#` and unknown chars use the owned cold reader.
|
|
2255
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
1575
2256
|
* @param {number} code current char code
|
|
1576
2257
|
* @returns {void}
|
|
1577
2258
|
* @this {ParserInternals}
|
|
@@ -1697,8 +2378,17 @@ class WebpackParser extends BaseParser {
|
|
|
1697
2378
|
// '-': --, -= or -; `-->` may open an HTML line comment
|
|
1698
2379
|
const next = input.charCodeAt(pos + 1);
|
|
1699
2380
|
if (next === 45) {
|
|
1700
|
-
|
|
1701
|
-
|
|
2381
|
+
// `-->` opens an HTML line comment only at the start of a line
|
|
2382
|
+
// (acorn readToken_plus_min): https://github.com/acornjs/acorn/blob/8.15.0/acorn/src/tokenize.js#L599-L618
|
|
2383
|
+
if (
|
|
2384
|
+
input.charCodeAt(pos + 2) === 62 &&
|
|
2385
|
+
!this.inModule &&
|
|
2386
|
+
(this.lastTokEnd === 0 ||
|
|
2387
|
+
lineBreak.test(input.slice(this.lastTokEnd, pos)))
|
|
2388
|
+
) {
|
|
2389
|
+
this.skipLineComment(3);
|
|
2390
|
+
this.skipSpace();
|
|
2391
|
+
return this.nextToken();
|
|
1702
2392
|
}
|
|
1703
2393
|
this.pos = pos + 2;
|
|
1704
2394
|
return this.finishToken(tokTypes.incDec, "--");
|
|
@@ -1727,7 +2417,11 @@ class WebpackParser extends BaseParser {
|
|
|
1727
2417
|
input.charCodeAt(pos + 2) === 45 &&
|
|
1728
2418
|
input.charCodeAt(pos + 3) === 45
|
|
1729
2419
|
) {
|
|
1730
|
-
|
|
2420
|
+
// `<!--` opens an HTML line comment (acorn readToken_lt_gt):
|
|
2421
|
+
// https://github.com/acornjs/acorn/blob/8.15.0/acorn/src/tokenize.js#L620-L649
|
|
2422
|
+
this.skipLineComment(4);
|
|
2423
|
+
this.skipSpace();
|
|
2424
|
+
return this.nextToken();
|
|
1731
2425
|
}
|
|
1732
2426
|
if (next === 61) {
|
|
1733
2427
|
this.pos = pos + 2;
|
|
@@ -1828,9 +2522,9 @@ class WebpackParser extends BaseParser {
|
|
|
1828
2522
|
case 48: {
|
|
1829
2523
|
// '0': radix literals split off before the decimal reader
|
|
1830
2524
|
const next = input.charCodeAt(pos + 1);
|
|
1831
|
-
if (next === 120 || next === 88) return this.
|
|
1832
|
-
if (next === 111 || next === 79) return this.
|
|
1833
|
-
if (next === 98 || next === 66) return this.
|
|
2525
|
+
if (next === 120 || next === 88) return this._readRadixNumber(16);
|
|
2526
|
+
if (next === 111 || next === 79) return this._readRadixNumber(8);
|
|
2527
|
+
if (next === 98 || next === 66) return this._readRadixNumber(2);
|
|
1834
2528
|
return this.readNumber(false);
|
|
1835
2529
|
}
|
|
1836
2530
|
case 49:
|
|
@@ -1847,18 +2541,19 @@ class WebpackParser extends BaseParser {
|
|
|
1847
2541
|
case 39:
|
|
1848
2542
|
return this.readString(code);
|
|
1849
2543
|
default:
|
|
1850
|
-
return
|
|
2544
|
+
return this._getUnknownOrPrivate(code);
|
|
1851
2545
|
}
|
|
1852
2546
|
}
|
|
1853
2547
|
|
|
1854
2548
|
/**
|
|
1855
2549
|
* ASCII fast path for acorn's `readWord1`, which pays a surrogate-aware
|
|
1856
2550
|
* method call and a range-check helper per character. Escapes, non-ASCII
|
|
1857
|
-
* and astral input restart the
|
|
2551
|
+
* and astral input restart the owned cold reader from the word start.
|
|
1858
2552
|
* Words are deduplicated through `WORD_CACHE` so repeated identifiers —
|
|
1859
2553
|
* which dominate real code — reuse one string instead of slicing a fresh
|
|
1860
2554
|
* one per occurrence; sharing also keeps their cached string hashes warm
|
|
1861
2555
|
* for the keyword/scope Map lookups downstream.
|
|
2556
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
1862
2557
|
* @this {ParserInternals}
|
|
1863
2558
|
* @returns {string} the word
|
|
1864
2559
|
*/
|
|
@@ -1876,13 +2571,13 @@ class WebpackParser extends BaseParser {
|
|
|
1876
2571
|
if (ch < 128) {
|
|
1877
2572
|
if (IDENT_CHAR[ch] === 0) {
|
|
1878
2573
|
// backslash escape: restart cold so escape rules see the word
|
|
1879
|
-
if (ch === 92) return
|
|
2574
|
+
if (ch === 92) return this._readWord1Cold();
|
|
1880
2575
|
break;
|
|
1881
2576
|
}
|
|
1882
2577
|
hash = (Math.imul(hash, 33) + ch) | 0;
|
|
1883
2578
|
pos++;
|
|
1884
2579
|
} else {
|
|
1885
|
-
return
|
|
2580
|
+
return this._readWord1Cold();
|
|
1886
2581
|
}
|
|
1887
2582
|
}
|
|
1888
2583
|
this.containsEsc = false;
|
|
@@ -1896,23 +2591,27 @@ class WebpackParser extends BaseParser {
|
|
|
1896
2591
|
if (
|
|
1897
2592
|
cached !== null &&
|
|
1898
2593
|
cached.length === wordLen &&
|
|
1899
|
-
|
|
2594
|
+
// length already matched, so a prefix test is an exact compare —
|
|
2595
|
+
// one builtin instead of a charCodeAt loop per cached character
|
|
2596
|
+
input.startsWith(cached, start)
|
|
1900
2597
|
) {
|
|
1901
2598
|
return cached;
|
|
1902
2599
|
}
|
|
1903
2600
|
const word = input.slice(start, pos);
|
|
1904
2601
|
WORD_CACHE[slot] = word;
|
|
2602
|
+
WORD_TYPE_OWNERS[slot] = 0;
|
|
1905
2603
|
return word;
|
|
1906
2604
|
}
|
|
1907
2605
|
return input.slice(start, pos);
|
|
1908
2606
|
}
|
|
1909
2607
|
|
|
1910
2608
|
/**
|
|
1911
|
-
* String fast path: one scan
|
|
1912
|
-
*
|
|
1913
|
-
*
|
|
1914
|
-
*
|
|
1915
|
-
*
|
|
2609
|
+
* String fast path: one scan finds the closing quote and cooks the common
|
|
2610
|
+
* single-char escapes (`\n \t \\ \" \'` …) and line continuations inline.
|
|
2611
|
+
* Hex/unicode/octal escapes (`\x`, `\u`, `\0`-`\9`) restart the owned cold
|
|
2612
|
+
* reader, which owns their readers and strict-mode errors; old ecmaVersions
|
|
2613
|
+
* (LS/PS terminate strings there) and location tracking use acorn's own.
|
|
2614
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
1916
2615
|
* @this {ParserInternals}
|
|
1917
2616
|
* @param {number} quote quote char code
|
|
1918
2617
|
* @returns {void}
|
|
@@ -1923,33 +2622,94 @@ class WebpackParser extends BaseParser {
|
|
|
1923
2622
|
}
|
|
1924
2623
|
const input = this.input;
|
|
1925
2624
|
const len = input.length;
|
|
1926
|
-
const
|
|
2625
|
+
const quotePos = this.pos;
|
|
2626
|
+
const start = quotePos + 1;
|
|
1927
2627
|
let pos = start;
|
|
2628
|
+
// spans between escapes accumulate here; a plain string never touches
|
|
2629
|
+
// `out` and slices once at the end
|
|
2630
|
+
let out = "";
|
|
2631
|
+
let chunkStart = start;
|
|
1928
2632
|
for (;;) {
|
|
1929
2633
|
if (pos >= len) this.raise(this.start, "Unterminated string constant");
|
|
1930
2634
|
const ch = input.charCodeAt(pos);
|
|
1931
2635
|
if (ch === quote) break;
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
2636
|
+
if (ch === 92) {
|
|
2637
|
+
const esc = input.charCodeAt(pos + 1);
|
|
2638
|
+
// hex/unicode/octal escapes (and a trailing `\`) need the cold
|
|
2639
|
+
// reader's escape handling; restart from the quote (this.pos unmoved)
|
|
2640
|
+
if (
|
|
2641
|
+
pos + 1 >= len ||
|
|
2642
|
+
esc === 120 ||
|
|
2643
|
+
esc === 117 ||
|
|
2644
|
+
(esc >= 48 && esc <= 57)
|
|
2645
|
+
) {
|
|
2646
|
+
this.pos = quotePos;
|
|
2647
|
+
return this._readStringCold(quote);
|
|
2648
|
+
}
|
|
2649
|
+
let rep;
|
|
2650
|
+
let advance = 2;
|
|
2651
|
+
switch (esc) {
|
|
2652
|
+
case 110:
|
|
2653
|
+
rep = "\n";
|
|
2654
|
+
break;
|
|
2655
|
+
case 114:
|
|
2656
|
+
rep = "\r";
|
|
2657
|
+
break;
|
|
2658
|
+
case 116:
|
|
2659
|
+
rep = "\t";
|
|
2660
|
+
break;
|
|
2661
|
+
case 98:
|
|
2662
|
+
rep = "\b";
|
|
2663
|
+
break;
|
|
2664
|
+
case 102:
|
|
2665
|
+
rep = "\f";
|
|
2666
|
+
break;
|
|
2667
|
+
case 118:
|
|
2668
|
+
rep = "\u000B";
|
|
2669
|
+
break;
|
|
2670
|
+
case 13:
|
|
2671
|
+
// `\` + CR(LF): line continuation cooked away
|
|
2672
|
+
rep = "";
|
|
2673
|
+
if (input.charCodeAt(pos + 2) === 10) advance = 3;
|
|
2674
|
+
break;
|
|
2675
|
+
case 10:
|
|
2676
|
+
case 0x2028:
|
|
2677
|
+
case 0x2029:
|
|
2678
|
+
rep = "";
|
|
2679
|
+
break;
|
|
2680
|
+
default:
|
|
2681
|
+
// any other escape is the escaped code unit verbatim (`\\`, `\q`)
|
|
2682
|
+
rep = input[pos + 1];
|
|
2683
|
+
}
|
|
2684
|
+
out += input.slice(chunkStart, pos) + rep;
|
|
2685
|
+
pos += advance;
|
|
2686
|
+
chunkStart = pos;
|
|
2687
|
+
} else if (ch === 10 || ch === 13) {
|
|
2688
|
+
// bare LF/CR is unterminated; LS/PS stay valid at ES2019+
|
|
2689
|
+
this.raise(this.start, "Unterminated string constant");
|
|
2690
|
+
} else {
|
|
2691
|
+
pos++;
|
|
1935
2692
|
}
|
|
1936
|
-
pos++;
|
|
1937
2693
|
}
|
|
1938
2694
|
this.pos = pos + 1;
|
|
1939
|
-
|
|
2695
|
+
if (chunkStart === start) {
|
|
2696
|
+
return this.finishToken(tokTypes.string, input.slice(start, pos));
|
|
2697
|
+
}
|
|
2698
|
+
this.finishToken(tokTypes.string, out + input.slice(chunkStart, pos));
|
|
1940
2699
|
}
|
|
1941
2700
|
|
|
1942
2701
|
/**
|
|
1943
2702
|
* Number fast path: plain integer literals (no leading zero, up to 15
|
|
1944
2703
|
* digits so the float is exact) are accumulated numerically — no slice,
|
|
1945
2704
|
* no parseFloat, no separator handling. Everything else (dots, exponents,
|
|
1946
|
-
* bigints, separators, octal forms) restarts
|
|
2705
|
+
* bigints, separators, octal forms) restarts the owned cold reader.
|
|
2706
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
1947
2707
|
* @this {ParserInternals}
|
|
1948
2708
|
* @param {boolean} startsWithDot whether the number started with a dot
|
|
1949
2709
|
* @returns {void}
|
|
1950
2710
|
*/
|
|
1951
2711
|
readNumber(startsWithDot) {
|
|
1952
|
-
if (startsWithDot) return
|
|
2712
|
+
if (startsWithDot) return this._readNumberCold(startsWithDot);
|
|
1953
2713
|
const input = this.input;
|
|
1954
2714
|
const start = this.pos;
|
|
1955
2715
|
const len = input.length;
|
|
@@ -1962,7 +2722,7 @@ class WebpackParser extends BaseParser {
|
|
|
1962
2722
|
pos = start + 1;
|
|
1963
2723
|
} else if (c1 > 127 || IDENT_CHAR[c1] === 1) {
|
|
1964
2724
|
// 0x/0o/0b, 0e…, 0n, 0_, legacy `0NN`, or `0`+identifier: acorn
|
|
1965
|
-
return
|
|
2725
|
+
return this._readNumberCold(startsWithDot);
|
|
1966
2726
|
} else {
|
|
1967
2727
|
// bare `0` before punctuation/operator/whitespace/EOF
|
|
1968
2728
|
this.pos = start + 1;
|
|
@@ -1993,18 +2753,18 @@ class WebpackParser extends BaseParser {
|
|
|
1993
2753
|
after > 127 ||
|
|
1994
2754
|
IDENT_CHAR[after] === 1
|
|
1995
2755
|
) {
|
|
1996
|
-
return
|
|
2756
|
+
return this._readNumberCold(startsWithDot);
|
|
1997
2757
|
}
|
|
1998
2758
|
// 15 digits always fit exactly into a double
|
|
1999
2759
|
if (pos - start > 15) {
|
|
2000
|
-
return
|
|
2760
|
+
return this._readNumberCold(startsWithDot);
|
|
2001
2761
|
}
|
|
2002
2762
|
this.pos = pos;
|
|
2003
2763
|
return this.finishToken(tokTypes.num, value);
|
|
2004
2764
|
}
|
|
2005
2765
|
// a fraction follows the integer part
|
|
2006
2766
|
} else {
|
|
2007
|
-
return
|
|
2767
|
+
return this._readNumberCold(startsWithDot);
|
|
2008
2768
|
}
|
|
2009
2769
|
// decimal fraction: `pos` is at the '.'
|
|
2010
2770
|
pos++;
|
|
@@ -2024,7 +2784,7 @@ class WebpackParser extends BaseParser {
|
|
|
2024
2784
|
after > 127 ||
|
|
2025
2785
|
IDENT_CHAR[after] === 1
|
|
2026
2786
|
) {
|
|
2027
|
-
return
|
|
2787
|
+
return this._readNumberCold(startsWithDot);
|
|
2028
2788
|
}
|
|
2029
2789
|
this.pos = pos;
|
|
2030
2790
|
this.finishToken(tokTypes.num, Number.parseFloat(input.slice(start, pos)));
|
|
@@ -2035,6 +2795,7 @@ class WebpackParser extends BaseParser {
|
|
|
2035
2795
|
* `this.input.slice(start)` — a fresh sliced string per (sloppy-mode)
|
|
2036
2796
|
* function body. Sticky regexes at the offset scan the same grammar with no
|
|
2037
2797
|
* slice. Same directive-prologue semantics, including the ASI tail checks.
|
|
2798
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/parseutil.js
|
|
2038
2799
|
* @param {number} start offset of the function body's first statement
|
|
2039
2800
|
* @returns {boolean} true when a 'use strict' directive leads the prologue
|
|
2040
2801
|
* @this {ParserInternals & { input: string, options: { ecmaVersion: number } }}
|
|
@@ -2079,9 +2840,10 @@ class WebpackParser extends BaseParser {
|
|
|
2079
2840
|
|
|
2080
2841
|
/**
|
|
2081
2842
|
* Template fast path: when the chunk contains no backslash and no CR, the
|
|
2082
|
-
* cooked value is one slice (LF/LS/PS cook to themselves). Escapes
|
|
2083
|
-
* normalization
|
|
2084
|
-
*
|
|
2843
|
+
* cooked value is one slice (LF/LS/PS cook to themselves). Escapes and CR
|
|
2844
|
+
* normalization restart the owned cold reader (its exact errors); location
|
|
2845
|
+
* tracking uses acorn's own.
|
|
2846
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
2085
2847
|
* @this {ParserInternals}
|
|
2086
2848
|
* @returns {void}
|
|
2087
2849
|
*/
|
|
@@ -2109,9 +2871,9 @@ class WebpackParser extends BaseParser {
|
|
|
2109
2871
|
this.pos = pos;
|
|
2110
2872
|
return this.finishToken(tokTypes.template, input.slice(start, pos));
|
|
2111
2873
|
}
|
|
2112
|
-
// backslash and CR need
|
|
2874
|
+
// backslash and CR need the cooked-string building of the cold reader
|
|
2113
2875
|
if (ch === 92 || ch === 13) {
|
|
2114
|
-
return
|
|
2876
|
+
return this._readTmplTokenCold();
|
|
2115
2877
|
}
|
|
2116
2878
|
pos++;
|
|
2117
2879
|
}
|
|
@@ -2119,8 +2881,9 @@ class WebpackParser extends BaseParser {
|
|
|
2119
2881
|
}
|
|
2120
2882
|
|
|
2121
2883
|
/**
|
|
2122
|
-
* Fast path for the common run of plain ASCII whitespace; comments
|
|
2123
|
-
* unicode whitespace
|
|
2884
|
+
* Fast path for the common run of plain ASCII whitespace; comments and
|
|
2885
|
+
* unicode whitespace use the owned cold reader, location tracking acorn's.
|
|
2886
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
2124
2887
|
* @this {ParserInternals & { pos: number }}
|
|
2125
2888
|
* @returns {void}
|
|
2126
2889
|
*/
|
|
@@ -2135,9 +2898,9 @@ class WebpackParser extends BaseParser {
|
|
|
2135
2898
|
if (ch === 32 || (ch > 8 && ch < 14)) {
|
|
2136
2899
|
pos++;
|
|
2137
2900
|
} else if (ch === 47 || ch > 127) {
|
|
2138
|
-
// comments or unicode whitespace:
|
|
2901
|
+
// comments or unicode whitespace: hand off to the cold reader
|
|
2139
2902
|
this.pos = pos;
|
|
2140
|
-
return
|
|
2903
|
+
return this._skipSpaceCold();
|
|
2141
2904
|
} else {
|
|
2142
2905
|
break;
|
|
2143
2906
|
}
|
|
@@ -2145,30 +2908,563 @@ class WebpackParser extends BaseParser {
|
|
|
2145
2908
|
this.pos = pos;
|
|
2146
2909
|
}
|
|
2147
2910
|
|
|
2148
|
-
// -----
|
|
2911
|
+
// ----- cold-path readers (ported from acorn's tokenizer, reached only from
|
|
2912
|
+
// the lazy fast paths above; non-lazy mode keeps acorn's own prototype
|
|
2913
|
+
// methods so plugins that patch them still see acorn's tokenizer) -----
|
|
2149
2914
|
|
|
2150
2915
|
/**
|
|
2151
|
-
*
|
|
2152
|
-
*
|
|
2153
|
-
*
|
|
2916
|
+
* acorn `readInt`: reads `radix`-base digits (optionally exactly `len` of
|
|
2917
|
+
* them), honoring ES2021 `_` separators.
|
|
2918
|
+
* https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
2154
2919
|
* @this {ParserInternals}
|
|
2155
|
-
* @
|
|
2920
|
+
* @param {number} radix numeric radix
|
|
2921
|
+
* @param {number=} len fixed digit count (for escapes), else read greedily
|
|
2922
|
+
* @param {boolean=} maybeLegacyOctal whether a leading zero disallows separators
|
|
2923
|
+
* @returns {number | null} the integer value, or null when no digits matched
|
|
2156
2924
|
*/
|
|
2157
|
-
|
|
2158
|
-
const
|
|
2159
|
-
|
|
2160
|
-
const
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2925
|
+
_readInt(radix, len, maybeLegacyOctal) {
|
|
2926
|
+
const input = this.input;
|
|
2927
|
+
const allowSeparators = this._ecmaVersion >= 12 && len === undefined;
|
|
2928
|
+
const isLegacyOctal =
|
|
2929
|
+
maybeLegacyOctal === true && input.charCodeAt(this.pos) === 48;
|
|
2930
|
+
const start = this.pos;
|
|
2931
|
+
let total = 0;
|
|
2932
|
+
let lastCode = 0;
|
|
2933
|
+
for (
|
|
2934
|
+
let i = 0, e = len === undefined ? Infinity : len;
|
|
2935
|
+
i < e;
|
|
2936
|
+
++i, ++this.pos
|
|
2937
|
+
) {
|
|
2938
|
+
const code = input.charCodeAt(this.pos);
|
|
2939
|
+
let val;
|
|
2940
|
+
if (allowSeparators && code === 95) {
|
|
2941
|
+
if (isLegacyOctal) {
|
|
2942
|
+
this.raiseRecoverable(
|
|
2943
|
+
this.pos,
|
|
2944
|
+
"Numeric separator is not allowed in legacy octal numeric literals"
|
|
2945
|
+
);
|
|
2946
|
+
}
|
|
2947
|
+
if (lastCode === 95) {
|
|
2948
|
+
this.raiseRecoverable(
|
|
2949
|
+
this.pos,
|
|
2950
|
+
"Numeric separator must be exactly one underscore"
|
|
2951
|
+
);
|
|
2952
|
+
}
|
|
2953
|
+
if (i === 0) {
|
|
2954
|
+
this.raiseRecoverable(
|
|
2955
|
+
this.pos,
|
|
2956
|
+
"Numeric separator is not allowed at the first of digits"
|
|
2957
|
+
);
|
|
2958
|
+
}
|
|
2959
|
+
lastCode = code;
|
|
2960
|
+
continue;
|
|
2961
|
+
}
|
|
2962
|
+
if (code >= 97) val = code - 97 + 10;
|
|
2963
|
+
else if (code >= 65) val = code - 65 + 10;
|
|
2964
|
+
else if (code >= 48 && code <= 57) val = code - 48;
|
|
2965
|
+
else val = Infinity;
|
|
2966
|
+
if (val >= radix) break;
|
|
2967
|
+
lastCode = code;
|
|
2968
|
+
total = total * radix + val;
|
|
2969
|
+
}
|
|
2970
|
+
if (allowSeparators && lastCode === 95) {
|
|
2971
|
+
this.raiseRecoverable(
|
|
2972
|
+
this.pos - 1,
|
|
2973
|
+
"Numeric separator is not allowed at the last of digits"
|
|
2974
|
+
);
|
|
2975
|
+
}
|
|
2976
|
+
if (this.pos === start || (len !== undefined && this.pos - start !== len)) {
|
|
2977
|
+
return null;
|
|
2978
|
+
}
|
|
2979
|
+
return total;
|
|
2980
|
+
}
|
|
2981
|
+
|
|
2982
|
+
/**
|
|
2983
|
+
* acorn `readRadixNumber`: `0x`/`0o`/`0b` integer or bigint literals.
|
|
2984
|
+
* https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
2985
|
+
* @this {ParserInternals}
|
|
2986
|
+
* @param {number} radix numeric radix (2/8/16)
|
|
2987
|
+
* @returns {void}
|
|
2988
|
+
*/
|
|
2989
|
+
_readRadixNumber(radix) {
|
|
2990
|
+
const input = this.input;
|
|
2991
|
+
const start = this.pos;
|
|
2992
|
+
this.pos += 2;
|
|
2993
|
+
let val = this._readInt(radix);
|
|
2994
|
+
if (val === null) {
|
|
2995
|
+
this.raise(this.start + 2, `Expected number in radix ${radix}`);
|
|
2996
|
+
}
|
|
2997
|
+
if (this._ecmaVersion >= 11 && input.charCodeAt(this.pos) === 110) {
|
|
2998
|
+
val = /** @type {EXPECTED_ANY} */ (
|
|
2999
|
+
stringToBigInt(input.slice(start, this.pos))
|
|
3000
|
+
);
|
|
3001
|
+
++this.pos;
|
|
3002
|
+
} else if (isIdentifierStart(this.fullCharCodeAtPos())) {
|
|
3003
|
+
this.raise(this.pos, "Identifier directly after number");
|
|
3004
|
+
}
|
|
3005
|
+
return this.finishToken(tokTypes.num, val);
|
|
3006
|
+
}
|
|
3007
|
+
|
|
3008
|
+
/**
|
|
3009
|
+
* acorn `readNumber`: decimal/float/legacy-octal/bigint literals (the fast
|
|
3010
|
+
* path handles only plain integers and simple fractions).
|
|
3011
|
+
* https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
3012
|
+
* @this {ParserInternals}
|
|
3013
|
+
* @param {boolean} startsWithDot whether the literal started with `.`
|
|
3014
|
+
* @returns {void}
|
|
3015
|
+
*/
|
|
3016
|
+
_readNumberCold(startsWithDot) {
|
|
3017
|
+
const input = this.input;
|
|
3018
|
+
const start = this.pos;
|
|
3019
|
+
if (!startsWithDot && this._readInt(10, undefined, true) === null) {
|
|
3020
|
+
this.raise(start, "Invalid number");
|
|
3021
|
+
}
|
|
3022
|
+
let octal = this.pos - start >= 2 && input.charCodeAt(start) === 48;
|
|
3023
|
+
if (octal && this.strict) this.raise(start, "Invalid number");
|
|
3024
|
+
let next = input.charCodeAt(this.pos);
|
|
3025
|
+
if (!octal && !startsWithDot && this._ecmaVersion >= 11 && next === 110) {
|
|
3026
|
+
const val = stringToBigInt(input.slice(start, this.pos));
|
|
3027
|
+
++this.pos;
|
|
3028
|
+
if (isIdentifierStart(this.fullCharCodeAtPos())) {
|
|
3029
|
+
this.raise(this.pos, "Identifier directly after number");
|
|
3030
|
+
}
|
|
3031
|
+
return this.finishToken(tokTypes.num, /** @type {EXPECTED_ANY} */ (val));
|
|
3032
|
+
}
|
|
3033
|
+
if (octal && /[89]/.test(input.slice(start, this.pos))) octal = false;
|
|
3034
|
+
if (next === 46 && !octal) {
|
|
3035
|
+
++this.pos;
|
|
3036
|
+
this._readInt(10);
|
|
3037
|
+
next = input.charCodeAt(this.pos);
|
|
3038
|
+
}
|
|
3039
|
+
if ((next === 69 || next === 101) && !octal) {
|
|
3040
|
+
next = input.charCodeAt(++this.pos);
|
|
3041
|
+
if (next === 43 || next === 45) ++this.pos;
|
|
3042
|
+
if (this._readInt(10) === null) this.raise(start, "Invalid number");
|
|
3043
|
+
}
|
|
3044
|
+
if (isIdentifierStart(this.fullCharCodeAtPos())) {
|
|
3045
|
+
this.raise(this.pos, "Identifier directly after number");
|
|
3046
|
+
}
|
|
3047
|
+
const val = stringToNumber(input.slice(start, this.pos), octal);
|
|
3048
|
+
return this.finishToken(tokTypes.num, val);
|
|
3049
|
+
}
|
|
3050
|
+
|
|
3051
|
+
/**
|
|
3052
|
+
* acorn `readCodePoint`: a `\u{...}` or `\uXXXX` escape.
|
|
3053
|
+
* https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
3054
|
+
* @this {ParserInternals}
|
|
3055
|
+
* @returns {number} the escaped code point
|
|
3056
|
+
*/
|
|
3057
|
+
_readCodePoint() {
|
|
3058
|
+
const input = this.input;
|
|
3059
|
+
const ch = input.charCodeAt(this.pos);
|
|
3060
|
+
let code;
|
|
3061
|
+
if (ch === 123) {
|
|
3062
|
+
if (this._ecmaVersion < 6) this.unexpected();
|
|
3063
|
+
const codePos = ++this.pos;
|
|
3064
|
+
code = this._readHexChar(input.indexOf("}", this.pos) - this.pos);
|
|
3065
|
+
++this.pos;
|
|
3066
|
+
if (code > 0x10ffff) {
|
|
3067
|
+
this.invalidStringToken(codePos, "Code point out of bounds");
|
|
3068
|
+
}
|
|
3069
|
+
} else {
|
|
3070
|
+
code = this._readHexChar(4);
|
|
3071
|
+
}
|
|
3072
|
+
return code;
|
|
3073
|
+
}
|
|
3074
|
+
|
|
3075
|
+
/**
|
|
3076
|
+
* acorn `readHexChar`: exactly `len` hex digits.
|
|
3077
|
+
* https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
3078
|
+
* @this {ParserInternals}
|
|
3079
|
+
* @param {number} len number of hex digits
|
|
3080
|
+
* @returns {number} the parsed code
|
|
3081
|
+
*/
|
|
3082
|
+
_readHexChar(len) {
|
|
3083
|
+
const codePos = this.pos;
|
|
3084
|
+
const n = this._readInt(16, len);
|
|
3085
|
+
if (n === null) {
|
|
3086
|
+
this.invalidStringToken(codePos, "Bad character escape sequence");
|
|
3087
|
+
}
|
|
3088
|
+
return /** @type {number} */ (n);
|
|
3089
|
+
}
|
|
3090
|
+
|
|
3091
|
+
/**
|
|
3092
|
+
* acorn `readString`: the escape-bearing string reader (the fast path cooks
|
|
3093
|
+
* only the common single-char escapes inline).
|
|
3094
|
+
* https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
3095
|
+
* @this {ParserInternals}
|
|
3096
|
+
* @param {number} quote quote char code
|
|
3097
|
+
* @returns {void}
|
|
3098
|
+
*/
|
|
3099
|
+
_readStringCold(quote) {
|
|
3100
|
+
const input = this.input;
|
|
3101
|
+
let out = "";
|
|
3102
|
+
let chunkStart = ++this.pos;
|
|
3103
|
+
for (;;) {
|
|
3104
|
+
if (this.pos >= input.length) {
|
|
3105
|
+
this.raise(this.start, "Unterminated string constant");
|
|
3106
|
+
}
|
|
3107
|
+
const ch = input.charCodeAt(this.pos);
|
|
3108
|
+
if (ch === quote) break;
|
|
3109
|
+
if (ch === 92) {
|
|
3110
|
+
out += input.slice(chunkStart, this.pos);
|
|
3111
|
+
out += this._readEscapedChar(false);
|
|
3112
|
+
chunkStart = this.pos;
|
|
3113
|
+
} else if (ch === 0x2028 || ch === 0x2029) {
|
|
3114
|
+
if (this._ecmaVersion < 10) {
|
|
3115
|
+
this.raise(this.start, "Unterminated string constant");
|
|
3116
|
+
}
|
|
3117
|
+
++this.pos;
|
|
3118
|
+
} else {
|
|
3119
|
+
if (isNewLine(ch)) {
|
|
3120
|
+
this.raise(this.start, "Unterminated string constant");
|
|
3121
|
+
}
|
|
3122
|
+
++this.pos;
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
out += input.slice(chunkStart, this.pos++);
|
|
3126
|
+
return this.finishToken(tokTypes.string, out);
|
|
3127
|
+
}
|
|
3128
|
+
|
|
3129
|
+
/**
|
|
3130
|
+
* acorn `readTmplToken`: the escape/CR-normalizing template reader. Invalid
|
|
3131
|
+
* escapes throw acorn's sentinel via `invalidStringToken`, which acorn's own
|
|
3132
|
+
* `tryReadTemplateToken` (not overridden here) catches to re-read raw.
|
|
3133
|
+
* https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
3134
|
+
* @this {ParserInternals}
|
|
3135
|
+
* @returns {void}
|
|
3136
|
+
*/
|
|
3137
|
+
_readTmplTokenCold() {
|
|
3138
|
+
const input = this.input;
|
|
3139
|
+
let out = "";
|
|
3140
|
+
let chunkStart = this.pos;
|
|
3141
|
+
for (;;) {
|
|
3142
|
+
if (this.pos >= input.length) {
|
|
3143
|
+
this.raise(this.start, "Unterminated template");
|
|
3144
|
+
}
|
|
3145
|
+
const ch = input.charCodeAt(this.pos);
|
|
3146
|
+
if (ch === 96 || (ch === 36 && input.charCodeAt(this.pos + 1) === 123)) {
|
|
3147
|
+
if (
|
|
3148
|
+
this.pos === this.start &&
|
|
3149
|
+
(this.type === tokTypes.template ||
|
|
3150
|
+
this.type === tokTypes.invalidTemplate)
|
|
3151
|
+
) {
|
|
3152
|
+
if (ch === 36) {
|
|
3153
|
+
this.pos += 2;
|
|
3154
|
+
return this.finishToken(tokTypes.dollarBraceL);
|
|
3155
|
+
}
|
|
3156
|
+
++this.pos;
|
|
3157
|
+
return this.finishToken(tokTypes.backQuote);
|
|
3158
|
+
}
|
|
3159
|
+
out += input.slice(chunkStart, this.pos);
|
|
3160
|
+
return this.finishToken(tokTypes.template, out);
|
|
3161
|
+
}
|
|
3162
|
+
if (ch === 92) {
|
|
3163
|
+
out += input.slice(chunkStart, this.pos);
|
|
3164
|
+
out += this._readEscapedChar(true);
|
|
3165
|
+
chunkStart = this.pos;
|
|
3166
|
+
} else if (isNewLine(ch)) {
|
|
3167
|
+
out += input.slice(chunkStart, this.pos);
|
|
3168
|
+
++this.pos;
|
|
3169
|
+
if (ch === 13 && input.charCodeAt(this.pos) === 10) ++this.pos;
|
|
3170
|
+
out += "\n";
|
|
3171
|
+
chunkStart = this.pos;
|
|
3172
|
+
} else {
|
|
3173
|
+
++this.pos;
|
|
3174
|
+
}
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
|
|
3178
|
+
/**
|
|
3179
|
+
* acorn `readEscapedChar`: cooks one backslash escape in a string/template.
|
|
3180
|
+
* https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
3181
|
+
* @this {ParserInternals}
|
|
3182
|
+
* @param {boolean} inTemplate whether the escape is in a template literal
|
|
3183
|
+
* @returns {string} the cooked replacement (may be `""`)
|
|
3184
|
+
*/
|
|
3185
|
+
_readEscapedChar(inTemplate) {
|
|
3186
|
+
const input = this.input;
|
|
3187
|
+
let ch = input.charCodeAt(++this.pos);
|
|
3188
|
+
++this.pos;
|
|
3189
|
+
switch (ch) {
|
|
3190
|
+
case 110:
|
|
3191
|
+
return "\n";
|
|
3192
|
+
case 114:
|
|
3193
|
+
return "\r";
|
|
3194
|
+
case 120:
|
|
3195
|
+
return String.fromCharCode(this._readHexChar(2));
|
|
3196
|
+
case 117:
|
|
3197
|
+
return codePointToString(this._readCodePoint());
|
|
3198
|
+
case 116:
|
|
3199
|
+
return "\t";
|
|
3200
|
+
case 98:
|
|
3201
|
+
return "\b";
|
|
3202
|
+
case 118:
|
|
3203
|
+
return "\u000B";
|
|
3204
|
+
case 102:
|
|
3205
|
+
return "\f";
|
|
3206
|
+
case 13:
|
|
3207
|
+
if (input.charCodeAt(this.pos) === 10) ++this.pos;
|
|
3208
|
+
// falls through
|
|
3209
|
+
case 10:
|
|
3210
|
+
return "";
|
|
3211
|
+
case 56:
|
|
3212
|
+
case 57:
|
|
3213
|
+
if (this.strict) {
|
|
3214
|
+
this.invalidStringToken(this.pos - 1, "Invalid escape sequence");
|
|
3215
|
+
}
|
|
3216
|
+
if (inTemplate) {
|
|
3217
|
+
this.invalidStringToken(
|
|
3218
|
+
this.pos - 1,
|
|
3219
|
+
"Invalid escape sequence in template string"
|
|
3220
|
+
);
|
|
3221
|
+
}
|
|
3222
|
+
// falls through
|
|
3223
|
+
default:
|
|
3224
|
+
if (ch >= 48 && ch <= 55) {
|
|
3225
|
+
let octalStr = /** @type {RegExpMatchArray} */ (
|
|
3226
|
+
input.slice(this.pos - 1, this.pos + 2).match(/^[0-7]+/)
|
|
3227
|
+
)[0];
|
|
3228
|
+
let octal = Number.parseInt(octalStr, 8);
|
|
3229
|
+
if (octal > 255) {
|
|
3230
|
+
octalStr = octalStr.slice(0, -1);
|
|
3231
|
+
octal = Number.parseInt(octalStr, 8);
|
|
3232
|
+
}
|
|
3233
|
+
this.pos += octalStr.length - 1;
|
|
3234
|
+
ch = input.charCodeAt(this.pos);
|
|
3235
|
+
if (
|
|
3236
|
+
(octalStr !== "0" || ch === 56 || ch === 57) &&
|
|
3237
|
+
(this.strict || inTemplate)
|
|
3238
|
+
) {
|
|
3239
|
+
this.invalidStringToken(
|
|
3240
|
+
this.pos - 1 - octalStr.length,
|
|
3241
|
+
inTemplate
|
|
3242
|
+
? "Octal literal in template string"
|
|
3243
|
+
: "Octal literal in strict mode"
|
|
3244
|
+
);
|
|
3245
|
+
}
|
|
3246
|
+
return String.fromCharCode(octal);
|
|
3247
|
+
}
|
|
3248
|
+
if (isNewLine(ch)) return "";
|
|
3249
|
+
return String.fromCharCode(ch);
|
|
3250
|
+
}
|
|
3251
|
+
}
|
|
3252
|
+
|
|
3253
|
+
/**
|
|
3254
|
+
* acorn `readWord1`: the escape-/astral-aware identifier reader (the fast
|
|
3255
|
+
* path handles pure-ASCII words).
|
|
3256
|
+
* https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
3257
|
+
* @this {ParserInternals}
|
|
3258
|
+
* @returns {string} the (possibly escape-cooked) word
|
|
3259
|
+
*/
|
|
3260
|
+
_readWord1Cold() {
|
|
3261
|
+
const input = this.input;
|
|
3262
|
+
this.containsEsc = false;
|
|
3263
|
+
let word = "";
|
|
3264
|
+
let first = true;
|
|
3265
|
+
let chunkStart = this.pos;
|
|
3266
|
+
const astral = this._ecmaVersion >= 6;
|
|
3267
|
+
while (this.pos < input.length) {
|
|
3268
|
+
const ch = this.fullCharCodeAtPos();
|
|
3269
|
+
if (isIdentifierChar(ch, astral)) {
|
|
3270
|
+
this.pos += ch <= 0xffff ? 1 : 2;
|
|
3271
|
+
} else if (ch === 92) {
|
|
3272
|
+
this.containsEsc = true;
|
|
3273
|
+
word += input.slice(chunkStart, this.pos);
|
|
3274
|
+
const escStart = this.pos;
|
|
3275
|
+
if (input.charCodeAt(++this.pos) !== 117) {
|
|
3276
|
+
this.invalidStringToken(
|
|
3277
|
+
this.pos,
|
|
3278
|
+
"Expecting Unicode escape sequence \\uXXXX"
|
|
3279
|
+
);
|
|
3280
|
+
}
|
|
3281
|
+
++this.pos;
|
|
3282
|
+
const esc = this._readCodePoint();
|
|
3283
|
+
if (!(first ? isIdentifierStart : isIdentifierChar)(esc, astral)) {
|
|
3284
|
+
this.invalidStringToken(escStart, "Invalid Unicode escape");
|
|
3285
|
+
}
|
|
3286
|
+
word += codePointToString(esc);
|
|
3287
|
+
chunkStart = this.pos;
|
|
3288
|
+
} else {
|
|
3289
|
+
break;
|
|
3290
|
+
}
|
|
3291
|
+
first = false;
|
|
3292
|
+
}
|
|
3293
|
+
return word + input.slice(chunkStart, this.pos);
|
|
3294
|
+
}
|
|
3295
|
+
|
|
3296
|
+
/**
|
|
3297
|
+
* acorn `skipSpace` (location-free): unicode whitespace and comments. Only
|
|
3298
|
+
* reached from the lazy fast paths, which keep no line bookkeeping.
|
|
3299
|
+
* https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
3300
|
+
* @this {ParserInternals}
|
|
3301
|
+
* @returns {void}
|
|
3302
|
+
*/
|
|
3303
|
+
_skipSpaceCold() {
|
|
3304
|
+
const input = this.input;
|
|
3305
|
+
const len = input.length;
|
|
3306
|
+
loop: while (this.pos < len) {
|
|
3307
|
+
const ch = input.charCodeAt(this.pos);
|
|
3308
|
+
switch (ch) {
|
|
3309
|
+
case 32:
|
|
3310
|
+
case 160:
|
|
3311
|
+
++this.pos;
|
|
3312
|
+
break;
|
|
3313
|
+
case 13:
|
|
3314
|
+
if (input.charCodeAt(this.pos + 1) === 10) ++this.pos;
|
|
3315
|
+
// falls through
|
|
3316
|
+
case 10:
|
|
3317
|
+
case 8232:
|
|
3318
|
+
case 8233:
|
|
3319
|
+
++this.pos;
|
|
3320
|
+
break;
|
|
3321
|
+
case 47:
|
|
3322
|
+
switch (input.charCodeAt(this.pos + 1)) {
|
|
3323
|
+
case 42:
|
|
3324
|
+
this.skipBlockComment();
|
|
3325
|
+
break;
|
|
3326
|
+
case 47:
|
|
3327
|
+
this.skipLineComment(2);
|
|
3328
|
+
break;
|
|
3329
|
+
default:
|
|
3330
|
+
break loop;
|
|
3331
|
+
}
|
|
3332
|
+
break;
|
|
3333
|
+
default:
|
|
3334
|
+
if (
|
|
3335
|
+
(ch > 8 && ch < 14) ||
|
|
3336
|
+
(ch >= 5760 && nonASCIIwhitespace.test(String.fromCharCode(ch)))
|
|
3337
|
+
) {
|
|
3338
|
+
++this.pos;
|
|
3339
|
+
} else {
|
|
3340
|
+
break loop;
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3343
|
+
}
|
|
3344
|
+
}
|
|
3345
|
+
|
|
3346
|
+
/**
|
|
3347
|
+
* acorn `readToken_numberSign` plus `getTokenFromCode`'s default: a private
|
|
3348
|
+
* identifier (`#x`) or an unexpected-character error.
|
|
3349
|
+
* https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
3350
|
+
* @this {ParserInternals}
|
|
3351
|
+
* @param {number} code current char code
|
|
3352
|
+
* @returns {void}
|
|
3353
|
+
*/
|
|
3354
|
+
_getUnknownOrPrivate(code) {
|
|
3355
|
+
if (code === 35 && this._ecmaVersion >= 13) {
|
|
3356
|
+
++this.pos;
|
|
3357
|
+
const next = this.fullCharCodeAtPos();
|
|
3358
|
+
if (isIdentifierStart(next, true) || next === 92) {
|
|
3359
|
+
return this.finishToken(tokTypes.privateId, this.readWord1());
|
|
3360
|
+
}
|
|
3361
|
+
this.raise(this.pos, `Unexpected character '${codePointToString(next)}'`);
|
|
3362
|
+
}
|
|
3363
|
+
this.raise(this.pos, `Unexpected character '${codePointToString(code)}'`);
|
|
3364
|
+
}
|
|
3365
|
+
|
|
3366
|
+
// ----- word classification (Map/Set lookups, replaces acorn's regexps) -----
|
|
3367
|
+
|
|
3368
|
+
/**
|
|
3369
|
+
* Replaces acorn's `readWord`: `readWord1`'s ASCII fast path inlined so the
|
|
3370
|
+
* token type can be memoized per `WORD_CACHE` slot (classification is pure in
|
|
3371
|
+
* the word and the per-option keyword set) — a cache hit serves the type by
|
|
3372
|
+
* identity compare instead of a keywords Map probe.
|
|
3373
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
3374
|
+
* @this {ParserInternals}
|
|
3375
|
+
* @returns {void}
|
|
3376
|
+
*/
|
|
3377
|
+
readWord() {
|
|
3378
|
+
const input = this.input;
|
|
3379
|
+
const start = this.pos;
|
|
3380
|
+
const len = input.length;
|
|
3381
|
+
let hash = 0;
|
|
3382
|
+
let pos = start;
|
|
3383
|
+
while (pos < len) {
|
|
3384
|
+
const ch = input.charCodeAt(pos);
|
|
3385
|
+
if (ch < 128) {
|
|
3386
|
+
if (IDENT_CHAR[ch] === 0) {
|
|
3387
|
+
// backslash escape: restart cold so escape rules see the word
|
|
3388
|
+
if (ch === 92) return this._finishWordSlow(this._readWord1Cold());
|
|
3389
|
+
break;
|
|
3390
|
+
}
|
|
3391
|
+
hash = (Math.imul(hash, 33) + ch) | 0;
|
|
3392
|
+
pos++;
|
|
3393
|
+
} else {
|
|
3394
|
+
return this._finishWordSlow(this._readWord1Cold());
|
|
3395
|
+
}
|
|
3396
|
+
}
|
|
3397
|
+
this.containsEsc = false;
|
|
3398
|
+
this.pos = pos;
|
|
3399
|
+
const wordLen = pos - start;
|
|
3400
|
+
if (wordLen >= 2 && wordLen <= WORD_CACHE_MAX_LEN) {
|
|
3401
|
+
const slot = hash & WORD_CACHE_MASK;
|
|
3402
|
+
const lookups = this._wordLookups;
|
|
3403
|
+
const owner = lookups.id;
|
|
3404
|
+
const cached = WORD_CACHE[slot];
|
|
3405
|
+
/** @type {string} */
|
|
3406
|
+
let word;
|
|
3407
|
+
/** @type {TokenType} */
|
|
3408
|
+
let type;
|
|
3409
|
+
if (
|
|
3410
|
+
cached !== null &&
|
|
3411
|
+
cached.length === wordLen &&
|
|
3412
|
+
// length already matched, so a prefix test is an exact compare —
|
|
3413
|
+
// one builtin instead of a charCodeAt loop per cached character
|
|
3414
|
+
input.startsWith(cached, start)
|
|
3415
|
+
) {
|
|
3416
|
+
word = cached;
|
|
3417
|
+
if (WORD_TYPE_OWNERS[slot] === owner) {
|
|
3418
|
+
type = /** @type {TokenType} */ (WORD_TYPES[slot]);
|
|
3419
|
+
} else {
|
|
3420
|
+
type = classifyWord(cached, lookups.keywords);
|
|
3421
|
+
WORD_TYPES[slot] = type;
|
|
3422
|
+
WORD_TYPE_OWNERS[slot] = owner;
|
|
3423
|
+
}
|
|
3424
|
+
} else {
|
|
3425
|
+
word = input.slice(start, pos);
|
|
3426
|
+
WORD_CACHE[slot] = word;
|
|
3427
|
+
type = classifyWord(word, lookups.keywords);
|
|
3428
|
+
WORD_TYPES[slot] = type;
|
|
3429
|
+
WORD_TYPE_OWNERS[slot] = owner;
|
|
3430
|
+
}
|
|
3431
|
+
if (type === tokTypes.name && this._inlineFinish) {
|
|
3432
|
+
// finishToken(name) inlined: offset/type/value stores plus
|
|
3433
|
+
// name.updateContext (as in the owned finishToken)
|
|
3434
|
+
this.end = pos;
|
|
3435
|
+
const prevType = this.type;
|
|
3436
|
+
this.type = type;
|
|
3437
|
+
this.value = word;
|
|
3438
|
+
this.exprAllowed =
|
|
3439
|
+
((word === "of" && !this.exprAllowed) ||
|
|
3440
|
+
(word === "yield" && this.inGeneratorContext())) &&
|
|
3441
|
+
prevType !== tokTypes.dot &&
|
|
3442
|
+
this._ecmaVersion >= 6;
|
|
3443
|
+
return;
|
|
3444
|
+
}
|
|
3445
|
+
return this.finishToken(type, word);
|
|
3446
|
+
}
|
|
3447
|
+
// Every keyword is 2-10 chars, so a word outside the cacheable range is a
|
|
3448
|
+
// plain name and can be neither `of` nor `yield`.
|
|
3449
|
+
if (this._inlineFinish) {
|
|
3450
|
+
this.end = pos;
|
|
3451
|
+
this.type = tokTypes.name;
|
|
3452
|
+
this.value = input.slice(start, pos);
|
|
3453
|
+
this.exprAllowed = false;
|
|
3454
|
+
return;
|
|
3455
|
+
}
|
|
3456
|
+
return this._finishWordSlow(input.slice(start, pos));
|
|
3457
|
+
}
|
|
3458
|
+
|
|
3459
|
+
/**
|
|
3460
|
+
* Uncached tail of `readWord`: escaped/non-ASCII, 1-char and over-long words.
|
|
3461
|
+
* @this {ParserInternals}
|
|
3462
|
+
* @param {string} word the word
|
|
3463
|
+
* @returns {void}
|
|
3464
|
+
*/
|
|
3465
|
+
_finishWordSlow(word) {
|
|
3466
|
+
this.finishToken(classifyWord(word, this._wordLookups.keywords), word);
|
|
3467
|
+
}
|
|
2172
3468
|
|
|
2173
3469
|
/**
|
|
2174
3470
|
* Mirror of acorn's `checkUnreserved` with its two per-identifier regexp
|
|
@@ -2176,6 +3472,7 @@ class WebpackParser extends BaseParser {
|
|
|
2176
3472
|
* single `reservedKinds` lookup — one hash probe instead of two, and the
|
|
2177
3473
|
* common plain identifier misses it and returns. Branches and error
|
|
2178
3474
|
* messages match acorn exactly.
|
|
3475
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
2179
3476
|
* @param {Identifier} ref identifier node
|
|
2180
3477
|
* @this {ParserInternals}
|
|
2181
3478
|
*/
|
|
@@ -2239,38 +3536,196 @@ class WebpackParser extends BaseParser {
|
|
|
2239
3536
|
}
|
|
2240
3537
|
|
|
2241
3538
|
/**
|
|
2242
|
-
*
|
|
2243
|
-
*
|
|
2244
|
-
*
|
|
2245
|
-
*
|
|
2246
|
-
*
|
|
3539
|
+
* Owned `checkLValSimple`, an exact-semantics copy of acorn 8's with the
|
|
3540
|
+
* strict-bind probe inlined: the constructor-installed Set stand-in is one
|
|
3541
|
+
* `has` behind a length gate instead of a closure call per checked name.
|
|
3542
|
+
* A runtime-replaced `reservedWordsStrictBind` falls back to `.test()`.
|
|
3543
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/lval.js
|
|
3544
|
+
* @param {Node} expr assignment/binding target
|
|
3545
|
+
* @param {number=} bindingType acorn BIND_* binding type
|
|
3546
|
+
* @param {Record<string, boolean> | null=} checkClashes param-name clash record
|
|
3547
|
+
* @returns {void}
|
|
2247
3548
|
* @this {ParserInternals}
|
|
2248
3549
|
*/
|
|
2249
|
-
|
|
2250
|
-
if (
|
|
2251
|
-
|
|
3550
|
+
checkLValSimple(expr, bindingType, checkClashes) {
|
|
3551
|
+
if (bindingType === undefined) bindingType = BIND_NONE;
|
|
3552
|
+
const isBind = bindingType !== BIND_NONE;
|
|
3553
|
+
const type = expr.type;
|
|
3554
|
+
if (type === "Identifier") {
|
|
3555
|
+
const name = /** @type {Identifier} */ (expr).name;
|
|
3556
|
+
if (this.strict) {
|
|
3557
|
+
const lookups = this._wordLookups;
|
|
3558
|
+
let reserved;
|
|
3559
|
+
if (this.reservedWordsStrictBind === lookups.reservedBindTest) {
|
|
3560
|
+
const len = name.length;
|
|
3561
|
+
reserved =
|
|
3562
|
+
len >= lookups.reservedBindMinLen &&
|
|
3563
|
+
len <= lookups.reservedBindMaxLen &&
|
|
3564
|
+
lookups.reservedBindSet.has(name);
|
|
3565
|
+
} else {
|
|
3566
|
+
reserved = this.reservedWordsStrictBind.test(name);
|
|
3567
|
+
}
|
|
3568
|
+
if (reserved) {
|
|
3569
|
+
this.raiseRecoverable(
|
|
3570
|
+
expr.start,
|
|
3571
|
+
`${isBind ? "Binding " : "Assigning to "}${name} in strict mode`
|
|
3572
|
+
);
|
|
3573
|
+
}
|
|
3574
|
+
}
|
|
3575
|
+
if (isBind) {
|
|
3576
|
+
if (bindingType === BIND_LEXICAL && name === "let") {
|
|
3577
|
+
this.raiseRecoverable(
|
|
3578
|
+
expr.start,
|
|
3579
|
+
"let is disallowed as a lexically bound name"
|
|
3580
|
+
);
|
|
3581
|
+
}
|
|
3582
|
+
if (checkClashes) {
|
|
3583
|
+
if (Object.prototype.hasOwnProperty.call(checkClashes, name)) {
|
|
3584
|
+
this.raiseRecoverable(expr.start, "Argument name clash");
|
|
3585
|
+
}
|
|
3586
|
+
checkClashes[name] = true;
|
|
3587
|
+
}
|
|
3588
|
+
if (bindingType !== BIND_OUTSIDE) {
|
|
3589
|
+
this.declareName(name, bindingType, expr.start);
|
|
3590
|
+
}
|
|
3591
|
+
}
|
|
3592
|
+
return;
|
|
2252
3593
|
}
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
3594
|
+
if (type === "ChainExpression") {
|
|
3595
|
+
this.raiseRecoverable(
|
|
3596
|
+
expr.start,
|
|
3597
|
+
"Optional chaining cannot appear in left-hand side"
|
|
3598
|
+
);
|
|
3599
|
+
return;
|
|
3600
|
+
}
|
|
3601
|
+
if (type === "MemberExpression") {
|
|
3602
|
+
if (isBind) {
|
|
3603
|
+
this.raiseRecoverable(expr.start, "Binding member expression");
|
|
3604
|
+
}
|
|
3605
|
+
return;
|
|
3606
|
+
}
|
|
3607
|
+
if (type === "ParenthesizedExpression") {
|
|
3608
|
+
if (isBind) {
|
|
3609
|
+
this.raiseRecoverable(expr.start, "Binding parenthesized expression");
|
|
3610
|
+
}
|
|
3611
|
+
return this.checkLValSimple(
|
|
3612
|
+
/** @type {Node} */ (
|
|
3613
|
+
/** @type {Node & { expression?: Node }} */ (expr).expression
|
|
3614
|
+
),
|
|
3615
|
+
bindingType,
|
|
3616
|
+
checkClashes
|
|
3617
|
+
);
|
|
3618
|
+
}
|
|
3619
|
+
this.raise(expr.start, `${isBind ? "Binding" : "Assigning to"} rvalue`);
|
|
2256
3620
|
}
|
|
2257
3621
|
|
|
2258
|
-
// ----- comment collection without eager text slicing -----
|
|
2259
|
-
|
|
2260
3622
|
/**
|
|
2261
|
-
*
|
|
2262
|
-
*
|
|
2263
|
-
*
|
|
2264
|
-
* @
|
|
2265
|
-
* @param {number}
|
|
3623
|
+
* Owned `checkLValPattern`, acorn's verbatim, so declarator/assignment
|
|
3624
|
+
* targets stay on owned code down to `checkLValSimple`/`declareName`.
|
|
3625
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/lval.js
|
|
3626
|
+
* @param {Node} expr binding pattern
|
|
3627
|
+
* @param {number=} bindingType acorn BIND_* binding type
|
|
3628
|
+
* @param {Record<string, boolean> | null=} checkClashes param-name clash record
|
|
2266
3629
|
* @returns {void}
|
|
3630
|
+
* @this {ParserInternals}
|
|
2267
3631
|
*/
|
|
2268
|
-
|
|
2269
|
-
const
|
|
2270
|
-
if (
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
3632
|
+
checkLValPattern(expr, bindingType, checkClashes) {
|
|
3633
|
+
const type = expr.type;
|
|
3634
|
+
if (type === "ObjectPattern") {
|
|
3635
|
+
const properties = /** @type {Node & { properties: Node[] }} */ (expr)
|
|
3636
|
+
.properties;
|
|
3637
|
+
for (let i = 0; i < properties.length; i++) {
|
|
3638
|
+
this.checkLValInnerPattern(properties[i], bindingType, checkClashes);
|
|
3639
|
+
}
|
|
3640
|
+
} else if (type === "ArrayPattern") {
|
|
3641
|
+
const elements = /** @type {Node & { elements: (Node | null)[] }} */ (
|
|
3642
|
+
expr
|
|
3643
|
+
).elements;
|
|
3644
|
+
for (let i = 0; i < elements.length; i++) {
|
|
3645
|
+
const element = elements[i];
|
|
3646
|
+
if (element) {
|
|
3647
|
+
this.checkLValInnerPattern(element, bindingType, checkClashes);
|
|
3648
|
+
}
|
|
3649
|
+
}
|
|
3650
|
+
} else {
|
|
3651
|
+
this.checkLValSimple(expr, bindingType, checkClashes);
|
|
3652
|
+
}
|
|
3653
|
+
}
|
|
3654
|
+
|
|
3655
|
+
/**
|
|
3656
|
+
* Owned `checkLValInnerPattern`, acorn's verbatim.
|
|
3657
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/lval.js
|
|
3658
|
+
* @param {Node} expr pattern element
|
|
3659
|
+
* @param {number=} bindingType acorn BIND_* binding type
|
|
3660
|
+
* @param {Record<string, boolean> | null=} checkClashes param-name clash record
|
|
3661
|
+
* @returns {void}
|
|
3662
|
+
* @this {ParserInternals}
|
|
3663
|
+
*/
|
|
3664
|
+
checkLValInnerPattern(expr, bindingType, checkClashes) {
|
|
3665
|
+
const type = expr.type;
|
|
3666
|
+
if (type === "Property") {
|
|
3667
|
+
// AssignmentProperty has type === "Property"
|
|
3668
|
+
this.checkLValInnerPattern(
|
|
3669
|
+
/** @type {Node} */ (
|
|
3670
|
+
/** @type {Node & { value?: Node }} */ (expr).value
|
|
3671
|
+
),
|
|
3672
|
+
bindingType,
|
|
3673
|
+
checkClashes
|
|
3674
|
+
);
|
|
3675
|
+
} else if (type === "AssignmentPattern") {
|
|
3676
|
+
this.checkLValPattern(
|
|
3677
|
+
/** @type {Node} */ (/** @type {Node & { left?: Node }} */ (expr).left),
|
|
3678
|
+
bindingType,
|
|
3679
|
+
checkClashes
|
|
3680
|
+
);
|
|
3681
|
+
} else if (type === "RestElement") {
|
|
3682
|
+
this.checkLValPattern(
|
|
3683
|
+
/** @type {Node} */ (
|
|
3684
|
+
/** @type {Node & { argument?: Node }} */ (expr).argument
|
|
3685
|
+
),
|
|
3686
|
+
bindingType,
|
|
3687
|
+
checkClashes
|
|
3688
|
+
);
|
|
3689
|
+
} else {
|
|
3690
|
+
this.checkLValPattern(expr, bindingType, checkClashes);
|
|
3691
|
+
}
|
|
3692
|
+
}
|
|
3693
|
+
|
|
3694
|
+
/**
|
|
3695
|
+
* Replaces acorn's `canInsertSemicolon`, whose line-break check slices the
|
|
3696
|
+
* inter-token gap and runs a regexp on it for every ASI decision (hundreds
|
|
3697
|
+
* of thousands per file). Scan the gap for a line terminator instead — no
|
|
3698
|
+
* slice, no regexp.
|
|
3699
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/parseutil.js
|
|
3700
|
+
* @returns {boolean} whether a semicolon may be inserted here
|
|
3701
|
+
* @this {ParserInternals}
|
|
3702
|
+
*/
|
|
3703
|
+
canInsertSemicolon() {
|
|
3704
|
+
if (this.type === tokTypes.eof || this.type === tokTypes.braceR) {
|
|
3705
|
+
return true;
|
|
3706
|
+
}
|
|
3707
|
+
// the owned nextToken already classified the gap; 2 (comment/unicode in
|
|
3708
|
+
// the gap, or a token from acorn's tokenizer) falls back to the scan
|
|
3709
|
+
return this._gapHasNewline();
|
|
3710
|
+
}
|
|
3711
|
+
|
|
3712
|
+
// ----- comment collection without eager text slicing -----
|
|
3713
|
+
|
|
3714
|
+
/**
|
|
3715
|
+
* Replaces acorn's `skipLineComment` when comments are collected lazily:
|
|
3716
|
+
* the same scan, but no text slice and no position objects. Acorn calls
|
|
3717
|
+
* this for `//`, hashbangs and HTML-style comments (varying `startSkip`).
|
|
3718
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
3719
|
+
* @this {ParserInternals}
|
|
3720
|
+
* @param {number} startSkip length of the comment opener
|
|
3721
|
+
* @returns {void}
|
|
3722
|
+
*/
|
|
3723
|
+
skipLineComment(startSkip) {
|
|
3724
|
+
const comments = this._lazyComments;
|
|
3725
|
+
if (comments === undefined) {
|
|
3726
|
+
return base.skipLineComment.call(this, startSkip);
|
|
3727
|
+
}
|
|
3728
|
+
const input = this.input;
|
|
2274
3729
|
const start = this.pos;
|
|
2275
3730
|
const len = input.length;
|
|
2276
3731
|
let pos = start + startSkip;
|
|
@@ -2287,6 +3742,7 @@ class WebpackParser extends BaseParser {
|
|
|
2287
3742
|
/**
|
|
2288
3743
|
* Replaces acorn's `skipBlockComment` when comments are collected lazily.
|
|
2289
3744
|
* Locations are always off in lazy mode, so line breaks need no handling.
|
|
3745
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
2290
3746
|
* @this {ParserInternals}
|
|
2291
3747
|
* @returns {void}
|
|
2292
3748
|
*/
|
|
@@ -2307,6 +3763,7 @@ class WebpackParser extends BaseParser {
|
|
|
2307
3763
|
// ----- lazy range -----
|
|
2308
3764
|
|
|
2309
3765
|
/**
|
|
3766
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/node.js
|
|
2310
3767
|
* @returns {Node} new node
|
|
2311
3768
|
* @this {ParserInternals}
|
|
2312
3769
|
*/
|
|
@@ -2316,6 +3773,7 @@ class WebpackParser extends BaseParser {
|
|
|
2316
3773
|
}
|
|
2317
3774
|
|
|
2318
3775
|
/**
|
|
3776
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/node.js
|
|
2319
3777
|
* @param {number} pos start offset
|
|
2320
3778
|
* @param {Position=} loc start position when acorn tracks locations
|
|
2321
3779
|
* @returns {Node} new node
|
|
@@ -2330,6 +3788,7 @@ class WebpackParser extends BaseParser {
|
|
|
2330
3788
|
* Lazy-mode `finishNode`: acorn's `locations`/`ranges` writes are dead when
|
|
2331
3789
|
* `range` is served lazily and `loc` not at all, so skip them and the `finishNodeAt`
|
|
2332
3790
|
* indirection. Runs once per node.
|
|
3791
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/node.js
|
|
2333
3792
|
* @param {Node} node node to finish
|
|
2334
3793
|
* @param {string} type node type
|
|
2335
3794
|
* @returns {Node} the finished node
|
|
@@ -2345,6 +3804,7 @@ class WebpackParser extends BaseParser {
|
|
|
2345
3804
|
/**
|
|
2346
3805
|
* Mirror of acorn's `copyNode`, which bypasses `startNodeAt` via
|
|
2347
3806
|
* `new Node(...)` and would otherwise produce non-lazy nodes.
|
|
3807
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/node.js
|
|
2348
3808
|
* @param {Node} node node to copy
|
|
2349
3809
|
* @returns {Node} copied node
|
|
2350
3810
|
* @this {ParserInternals}
|
|
@@ -2369,6 +3829,7 @@ class WebpackParser extends BaseParser {
|
|
|
2369
3829
|
* `IdentifierNode` directly, skipping acorn's `parseIdentNode`/`startNode`/
|
|
2370
3830
|
* `finishNode` chain and its keyword branches. Keyword-as-identifier
|
|
2371
3831
|
* (`obj.class`) and non-lazy mode delegate to acorn.
|
|
3832
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
2372
3833
|
* @param {boolean=} liberal whether reserved words are allowed
|
|
2373
3834
|
* @returns {Identifier} identifier node
|
|
2374
3835
|
* @this {ParserInternals}
|
|
@@ -2396,6 +3857,79 @@ class WebpackParser extends BaseParser {
|
|
|
2396
3857
|
return node;
|
|
2397
3858
|
}
|
|
2398
3859
|
|
|
3860
|
+
/**
|
|
3861
|
+
* Owned `parseSubscripts`, an exact-semantics copy of acorn 8's with the
|
|
3862
|
+
* async-arrow-head probe reordered cheapest-first (all operands are pure)
|
|
3863
|
+
* and the arrow exit probe served by `_lastArrow` identity instead of the
|
|
3864
|
+
* megamorphic `.type` load. Delegates when either fast path is off.
|
|
3865
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
3866
|
+
* @param {Expression} baseExpr subscript base
|
|
3867
|
+
* @param {number} startPos expression start offset
|
|
3868
|
+
* @param {Position | undefined} startLoc expression start position
|
|
3869
|
+
* @param {boolean=} noCalls whether calls are forbidden (`new` callee)
|
|
3870
|
+
* @param {boolean | string=} forInit for-init context flag
|
|
3871
|
+
* @returns {Expression} expression with subscripts applied
|
|
3872
|
+
* @this {ParserInternals}
|
|
3873
|
+
*/
|
|
3874
|
+
parseSubscripts(baseExpr, startPos, startLoc, noCalls, forInit) {
|
|
3875
|
+
if (!this._subscriptFastPath || !this._arrowFastPath) {
|
|
3876
|
+
return base.parseSubscripts.call(
|
|
3877
|
+
this,
|
|
3878
|
+
baseExpr,
|
|
3879
|
+
startPos,
|
|
3880
|
+
startLoc,
|
|
3881
|
+
noCalls,
|
|
3882
|
+
forInit
|
|
3883
|
+
);
|
|
3884
|
+
}
|
|
3885
|
+
// acorn's probe order is (ecmaVersion, type, name, offsets, ASI,
|
|
3886
|
+
// potentialArrowAt); every operand is pure, so the SMI compares run
|
|
3887
|
+
// first and the megamorphic `.type` load only when `async` matched
|
|
3888
|
+
const maybeAsyncArrow =
|
|
3889
|
+
baseExpr.start === this.potentialArrowAt &&
|
|
3890
|
+
baseExpr.end - baseExpr.start === 5 &&
|
|
3891
|
+
this.lastTokEnd === baseExpr.end &&
|
|
3892
|
+
this._ecmaVersion >= 8 &&
|
|
3893
|
+
/** @type {Identifier} */ (baseExpr).name === "async" &&
|
|
3894
|
+
baseExpr.type === "Identifier" &&
|
|
3895
|
+
!this.canInsertSemicolon();
|
|
3896
|
+
let optionalChained = false;
|
|
3897
|
+
for (;;) {
|
|
3898
|
+
const element = this.parseSubscript(
|
|
3899
|
+
baseExpr,
|
|
3900
|
+
startPos,
|
|
3901
|
+
startLoc,
|
|
3902
|
+
noCalls,
|
|
3903
|
+
maybeAsyncArrow,
|
|
3904
|
+
optionalChained,
|
|
3905
|
+
forInit
|
|
3906
|
+
);
|
|
3907
|
+
if (
|
|
3908
|
+
/** @type {Expression & { optional?: boolean }} */ (element).optional
|
|
3909
|
+
) {
|
|
3910
|
+
optionalChained = true;
|
|
3911
|
+
}
|
|
3912
|
+
if (element === baseExpr || element === this._lastArrow) {
|
|
3913
|
+
if (optionalChained) {
|
|
3914
|
+
const chainNode =
|
|
3915
|
+
/** @type {Node & { expression?: Expression }} */
|
|
3916
|
+
(this.startNodeAt(startPos, startLoc));
|
|
3917
|
+
chainNode.expression = element;
|
|
3918
|
+
return /** @type {Expression} */ (
|
|
3919
|
+
/** @type {unknown} */ (
|
|
3920
|
+
this.finishNode(
|
|
3921
|
+
/** @type {Node} */ (chainNode),
|
|
3922
|
+
"ChainExpression"
|
|
3923
|
+
)
|
|
3924
|
+
)
|
|
3925
|
+
);
|
|
3926
|
+
}
|
|
3927
|
+
return element;
|
|
3928
|
+
}
|
|
3929
|
+
baseExpr = element;
|
|
3930
|
+
}
|
|
3931
|
+
}
|
|
3932
|
+
|
|
2399
3933
|
/**
|
|
2400
3934
|
* Owned `parseSubscript`, an exact-semantics copy of acorn 8's with the
|
|
2401
3935
|
* node construction replaced: member and call nodes are built fully-formed
|
|
@@ -2403,6 +3937,7 @@ class WebpackParser extends BaseParser {
|
|
|
2403
3937
|
* reachable during it), landing on `MemberExpressionNode`/
|
|
2404
3938
|
* `CallExpressionNode`'s single shapes. Pre-optional-chaining ecmaVersions
|
|
2405
3939
|
* and non-lazy mode delegate to acorn.
|
|
3940
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
2406
3941
|
* @param {Expression} baseExpr subscript base
|
|
2407
3942
|
* @param {number} startPos expression start offset
|
|
2408
3943
|
* @param {Position | undefined} startLoc expression start position
|
|
@@ -2554,6 +4089,7 @@ class WebpackParser extends BaseParser {
|
|
|
2554
4089
|
* blocks and plain expression statements) without it; everything rarer, the
|
|
2555
4090
|
* `name`-token ambiguities (`let`/`async`/`using`/`await` heads) and
|
|
2556
4091
|
* plugin-overridden parsers delegate to acorn.
|
|
4092
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
2557
4093
|
* @param {string | null} context statement context
|
|
2558
4094
|
* @param {boolean=} topLevel whether parsing top-level statements
|
|
2559
4095
|
* @param {unknown=} exports export tracking object
|
|
@@ -2579,17 +4115,65 @@ class WebpackParser extends BaseParser {
|
|
|
2579
4115
|
case tokTypes.braceL:
|
|
2580
4116
|
// the owned parseBlock never reads the started node
|
|
2581
4117
|
return this.parseBlock(true);
|
|
4118
|
+
case tokTypes._function: {
|
|
4119
|
+
if (!this._funcStmtOwn) {
|
|
4120
|
+
return base.parseStatement.call(this, context, topLevel, exports);
|
|
4121
|
+
}
|
|
4122
|
+
// acorn's hanging-function guard (context = single-statement position)
|
|
4123
|
+
if (
|
|
4124
|
+
context &&
|
|
4125
|
+
(this.strict || (context !== "if" && context !== "label"))
|
|
4126
|
+
) {
|
|
4127
|
+
this.unexpected();
|
|
4128
|
+
}
|
|
4129
|
+
// parseFunctionStatement, inlined without the started node
|
|
4130
|
+
const start = this.start;
|
|
4131
|
+
this.next();
|
|
4132
|
+
return this._parseFunctionAt(
|
|
4133
|
+
start,
|
|
4134
|
+
FUNC_STATEMENT | (context ? FUNC_HANGING_STATEMENT : 0),
|
|
4135
|
+
false,
|
|
4136
|
+
false,
|
|
4137
|
+
undefined
|
|
4138
|
+
);
|
|
4139
|
+
}
|
|
2582
4140
|
case tokTypes._break:
|
|
2583
4141
|
case tokTypes._continue:
|
|
2584
|
-
|
|
2585
|
-
|
|
4142
|
+
if (!this._stmt2FastPath) {
|
|
4143
|
+
return base.parseStatement.call(this, context, topLevel, exports);
|
|
4144
|
+
}
|
|
4145
|
+
return this._parseBreakContinueStatementAt(
|
|
4146
|
+
this.start,
|
|
4147
|
+
/** @type {string} */ (startType.keyword)
|
|
4148
|
+
);
|
|
2586
4149
|
case tokTypes._for:
|
|
2587
|
-
|
|
2588
|
-
|
|
4150
|
+
if (!this._stmt2FastPath) {
|
|
4151
|
+
return base.parseStatement.call(this, context, topLevel, exports);
|
|
4152
|
+
}
|
|
4153
|
+
return this._parseForStatementAt(this.start);
|
|
2589
4154
|
case tokTypes._switch:
|
|
4155
|
+
if (!this._stmt2FastPath) {
|
|
4156
|
+
return base.parseStatement.call(this, context, topLevel, exports);
|
|
4157
|
+
}
|
|
4158
|
+
return this._parseSwitchStatementAt(this.start);
|
|
2590
4159
|
case tokTypes._throw:
|
|
4160
|
+
if (!this._stmt2FastPath) {
|
|
4161
|
+
return base.parseStatement.call(this, context, topLevel, exports);
|
|
4162
|
+
}
|
|
4163
|
+
return this._parseThrowStatementAt(this.start);
|
|
2591
4164
|
case tokTypes._try:
|
|
4165
|
+
if (!this._stmt2FastPath) {
|
|
4166
|
+
return base.parseStatement.call(this, context, topLevel, exports);
|
|
4167
|
+
}
|
|
4168
|
+
return this._parseTryStatementAt(this.start);
|
|
2592
4169
|
case tokTypes._while:
|
|
4170
|
+
if (!this._stmt2FastPath) {
|
|
4171
|
+
return base.parseStatement.call(this, context, topLevel, exports);
|
|
4172
|
+
}
|
|
4173
|
+
return this._parseWhileStatementAt(this.start);
|
|
4174
|
+
case tokTypes._debugger:
|
|
4175
|
+
case tokTypes._do:
|
|
4176
|
+
case tokTypes._class:
|
|
2593
4177
|
case tokTypes._with:
|
|
2594
4178
|
case tokTypes.semi:
|
|
2595
4179
|
case tokTypes._export:
|
|
@@ -2641,6 +4225,7 @@ class WebpackParser extends BaseParser {
|
|
|
2641
4225
|
* Owned `parseVarStatement`: the passed started node is filled by
|
|
2642
4226
|
* `parseVar` as acorn expects, then the finished statement lands on
|
|
2643
4227
|
* `VariableDeclarationNode`'s single shape. Non-lazy mode delegates.
|
|
4228
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
2644
4229
|
* @param {Node} node started statement node from `parseStatement`
|
|
2645
4230
|
* @param {string} kind declaration kind
|
|
2646
4231
|
* @param {boolean=} allowMissingInitializer whether `const x;` is allowed
|
|
@@ -2662,6 +4247,7 @@ class WebpackParser extends BaseParser {
|
|
|
2662
4247
|
/**
|
|
2663
4248
|
* Statement-position `var`/`let`/`const` without a started node: the
|
|
2664
4249
|
* declaration lands directly on `VariableDeclarationNode`'s single shape.
|
|
4250
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
2665
4251
|
* @param {number} start statement start offset
|
|
2666
4252
|
* @param {string} kind declaration kind
|
|
2667
4253
|
* @param {boolean=} allowMissingInitializer whether `const x;` is allowed
|
|
@@ -2670,9 +4256,14 @@ class WebpackParser extends BaseParser {
|
|
|
2670
4256
|
*/
|
|
2671
4257
|
_parseVarStatementAt(start, kind, allowMissingInitializer) {
|
|
2672
4258
|
this.next();
|
|
2673
|
-
|
|
2674
|
-
const
|
|
2675
|
-
|
|
4259
|
+
const scratch = this._acquireScratch();
|
|
4260
|
+
const count = this._parseVarInto(
|
|
4261
|
+
scratch,
|
|
4262
|
+
false,
|
|
4263
|
+
kind,
|
|
4264
|
+
allowMissingInitializer
|
|
4265
|
+
);
|
|
4266
|
+
const declarations = this._releaseScratch(scratch, count);
|
|
2676
4267
|
this.semicolon();
|
|
2677
4268
|
return /** @type {Node} */ (
|
|
2678
4269
|
/** @type {unknown} */ (
|
|
@@ -2686,6 +4277,7 @@ class WebpackParser extends BaseParser {
|
|
|
2686
4277
|
* declarator fully-formed on `VariableDeclaratorNode`'s single shape. The
|
|
2687
4278
|
* passed node keeps receiving `declarations`/`kind` because
|
|
2688
4279
|
* `parseForStatement` finishes it itself. Non-lazy mode delegates.
|
|
4280
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
2689
4281
|
* @param {Node} node declaration node to fill
|
|
2690
4282
|
* @param {boolean} isFor whether parsing a `for` head
|
|
2691
4283
|
* @param {string} kind declaration kind
|
|
@@ -2703,29 +4295,41 @@ class WebpackParser extends BaseParser {
|
|
|
2703
4295
|
allowMissingInitializer
|
|
2704
4296
|
);
|
|
2705
4297
|
}
|
|
2706
|
-
/** @type {Node[]} */
|
|
2707
|
-
const declarations = [];
|
|
2708
4298
|
const target =
|
|
2709
|
-
/** @type {Node & { declarations: Node[], kind: string }} */ (
|
|
2710
|
-
|
|
4299
|
+
/** @type {Node & { declarations: Node[] | null, kind: string }} */ (
|
|
4300
|
+
node
|
|
4301
|
+
);
|
|
4302
|
+
// null placeholder keeps acorn's declarations-then-kind key order while
|
|
4303
|
+
// the list is built in scratch (the node is a local in every caller
|
|
4304
|
+
// until this returns, so the placeholder is unobservable)
|
|
4305
|
+
target.declarations = null;
|
|
2711
4306
|
target.kind = kind;
|
|
2712
|
-
this.
|
|
4307
|
+
const scratch = this._acquireScratch();
|
|
4308
|
+
const count = this._parseVarInto(
|
|
4309
|
+
scratch,
|
|
4310
|
+
isFor,
|
|
4311
|
+
kind,
|
|
4312
|
+
allowMissingInitializer
|
|
4313
|
+
);
|
|
4314
|
+
target.declarations = this._releaseScratch(scratch, count);
|
|
2713
4315
|
return node;
|
|
2714
4316
|
}
|
|
2715
4317
|
|
|
2716
4318
|
/**
|
|
2717
4319
|
* The declarator loop of the owned `parseVar`, shared with the owned
|
|
2718
4320
|
* `parseStatement`'s node-free statement path.
|
|
2719
|
-
*
|
|
4321
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
4322
|
+
* @param {Node[]} declarations scratch array for the declarators
|
|
2720
4323
|
* @param {boolean} isFor whether parsing a `for` head
|
|
2721
4324
|
* @param {string} kind declaration kind
|
|
2722
4325
|
* @param {boolean=} allowMissingInitializer whether `const x;` is allowed
|
|
2723
|
-
* @returns {
|
|
4326
|
+
* @returns {number} number of declarators written
|
|
2724
4327
|
* @this {ParserInternals}
|
|
2725
4328
|
*/
|
|
2726
4329
|
_parseVarInto(declarations, isFor, kind, allowMissingInitializer) {
|
|
2727
4330
|
const ecmaVersion = this._ecmaVersion;
|
|
2728
4331
|
const usingKind = kind === "using" || kind === "await using";
|
|
4332
|
+
let count = 0;
|
|
2729
4333
|
for (;;) {
|
|
2730
4334
|
const declStart = this.start;
|
|
2731
4335
|
const id = usingKind ? this.parseIdent() : this.parseBindingAtom();
|
|
@@ -2768,21 +4372,21 @@ class WebpackParser extends BaseParser {
|
|
|
2768
4372
|
"Complex binding patterns require an initialization value"
|
|
2769
4373
|
);
|
|
2770
4374
|
}
|
|
2771
|
-
declarations
|
|
2772
|
-
/** @type {
|
|
2773
|
-
|
|
2774
|
-
new VariableDeclaratorNode(declStart, this.lastTokEnd, id, init)
|
|
2775
|
-
)
|
|
4375
|
+
declarations[count++] = /** @type {Node} */ (
|
|
4376
|
+
/** @type {unknown} */ (
|
|
4377
|
+
new VariableDeclaratorNode(declStart, this.lastTokEnd, id, init)
|
|
2776
4378
|
)
|
|
2777
4379
|
);
|
|
2778
4380
|
if (!this.eat(tokTypes.comma)) break;
|
|
2779
4381
|
}
|
|
4382
|
+
return count;
|
|
2780
4383
|
}
|
|
2781
4384
|
|
|
2782
4385
|
/**
|
|
2783
4386
|
* Owned `parseExpressionStatement`: the statement lands on
|
|
2784
4387
|
* `ExpressionStatementNode`'s single shape (the passed started node is
|
|
2785
4388
|
* discarded, matching acorn's observable output). Non-lazy mode delegates.
|
|
4389
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
2786
4390
|
* @param {Node} node started statement node from `parseStatement`
|
|
2787
4391
|
* @param {Expression} expr the parsed expression
|
|
2788
4392
|
* @returns {Node} expression statement
|
|
@@ -2797,6 +4401,7 @@ class WebpackParser extends BaseParser {
|
|
|
2797
4401
|
|
|
2798
4402
|
/**
|
|
2799
4403
|
* `parseExpressionStatement` without a started node.
|
|
4404
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
2800
4405
|
* @param {number} start statement start offset
|
|
2801
4406
|
* @param {Expression} expr the parsed expression
|
|
2802
4407
|
* @returns {Node} expression statement
|
|
@@ -2814,6 +4419,7 @@ class WebpackParser extends BaseParser {
|
|
|
2814
4419
|
/**
|
|
2815
4420
|
* Owned `parseBlock`, an exact-semantics copy of acorn 8's landing on
|
|
2816
4421
|
* `BlockStatementNode`'s single shape. Non-lazy mode delegates.
|
|
4422
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
2817
4423
|
* @param {boolean=} createNewLexicalScope whether the block opens a scope
|
|
2818
4424
|
* @param {Node=} node started statement node, when called from `parseStatement`
|
|
2819
4425
|
* @param {boolean=} exitStrict whether to restore sloppy mode at the end
|
|
@@ -2831,19 +4437,23 @@ class WebpackParser extends BaseParser {
|
|
|
2831
4437
|
}
|
|
2832
4438
|
if (createNewLexicalScope === undefined) createNewLexicalScope = true;
|
|
2833
4439
|
const start = this.start;
|
|
2834
|
-
|
|
2835
|
-
|
|
4440
|
+
const scratch = this._acquireScratch();
|
|
4441
|
+
let count = 0;
|
|
2836
4442
|
this.expect(tokTypes.braceL);
|
|
2837
4443
|
if (createNewLexicalScope) this.enterScope(0);
|
|
2838
4444
|
while (this.type !== tokTypes.braceR) {
|
|
2839
|
-
|
|
4445
|
+
scratch[count++] = this.parseStatement(null);
|
|
2840
4446
|
}
|
|
2841
4447
|
if (exitStrict) this.strict = false;
|
|
2842
4448
|
this.next();
|
|
2843
4449
|
if (createNewLexicalScope) this.exitScope();
|
|
2844
4450
|
return /** @type {Node} */ (
|
|
2845
4451
|
/** @type {unknown} */ (
|
|
2846
|
-
new BlockStatementNode(
|
|
4452
|
+
new BlockStatementNode(
|
|
4453
|
+
start,
|
|
4454
|
+
this.lastTokEnd,
|
|
4455
|
+
this._releaseScratch(scratch, count)
|
|
4456
|
+
)
|
|
2847
4457
|
)
|
|
2848
4458
|
);
|
|
2849
4459
|
}
|
|
@@ -2851,6 +4461,7 @@ class WebpackParser extends BaseParser {
|
|
|
2851
4461
|
/**
|
|
2852
4462
|
* Owned `parseIfStatement` landing on `IfStatementNode`'s single shape.
|
|
2853
4463
|
* Non-lazy mode delegates to acorn.
|
|
4464
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
2854
4465
|
* @param {Node} node started statement node from `parseStatement`
|
|
2855
4466
|
* @returns {Node} if statement
|
|
2856
4467
|
* @this {ParserInternals}
|
|
@@ -2862,6 +4473,7 @@ class WebpackParser extends BaseParser {
|
|
|
2862
4473
|
|
|
2863
4474
|
/**
|
|
2864
4475
|
* `parseIfStatement` without a started node.
|
|
4476
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
2865
4477
|
* @param {number} start statement start offset
|
|
2866
4478
|
* @returns {Node} if statement
|
|
2867
4479
|
* @this {ParserInternals}
|
|
@@ -2884,6 +4496,7 @@ class WebpackParser extends BaseParser {
|
|
|
2884
4496
|
/**
|
|
2885
4497
|
* Owned `parseReturnStatement` landing on `ReturnStatementNode`'s single
|
|
2886
4498
|
* shape. Non-lazy mode delegates to acorn.
|
|
4499
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
2887
4500
|
* @param {Node} node started statement node from `parseStatement`
|
|
2888
4501
|
* @returns {Node} return statement
|
|
2889
4502
|
* @this {ParserInternals}
|
|
@@ -2896,116 +4509,1169 @@ class WebpackParser extends BaseParser {
|
|
|
2896
4509
|
return this._parseReturnStatementAt(node.start);
|
|
2897
4510
|
}
|
|
2898
4511
|
|
|
2899
|
-
/**
|
|
2900
|
-
* In `auto` source type a top-level `return` is script-only syntax. When the
|
|
2901
|
-
* strict module parse reaches it with no module construct seen yet, downgrade
|
|
2902
|
-
* to a sloppy script in place: the prefix parsed under stricter rules stays a
|
|
2903
|
-
* valid sloppy prefix, so the second full parse is avoided.
|
|
2904
|
-
* @returns {boolean} true when the parse was downgraded to script
|
|
2905
|
-
* @this {ParserInternals}
|
|
2906
|
-
*/
|
|
2907
|
-
_tryModuleFallback() {
|
|
4512
|
+
/**
|
|
4513
|
+
* In `auto` source type a top-level `return` is script-only syntax. When the
|
|
4514
|
+
* strict module parse reaches it with no module construct seen yet, downgrade
|
|
4515
|
+
* to a sloppy script in place: the prefix parsed under stricter rules stays a
|
|
4516
|
+
* valid sloppy prefix, so the second full parse is avoided.
|
|
4517
|
+
* @returns {boolean} true when the parse was downgraded to script
|
|
4518
|
+
* @this {ParserInternals}
|
|
4519
|
+
*/
|
|
4520
|
+
_tryModuleFallback() {
|
|
4521
|
+
if (
|
|
4522
|
+
!this._moduleFallback ||
|
|
4523
|
+
this._moduleSyntaxSeen ||
|
|
4524
|
+
!(this.currentVarScope().flags & SCOPE_TOP)
|
|
4525
|
+
) {
|
|
4526
|
+
return false;
|
|
4527
|
+
}
|
|
4528
|
+
this.options.allowReturnOutsideFunction = true;
|
|
4529
|
+
// acorn stamps Program.sourceType from this at parseTopLevel's end
|
|
4530
|
+
this.options.sourceType = "script";
|
|
4531
|
+
this.strict = false;
|
|
4532
|
+
this.inModule = false;
|
|
4533
|
+
this._moduleFallback = false;
|
|
4534
|
+
return true;
|
|
4535
|
+
}
|
|
4536
|
+
|
|
4537
|
+
/**
|
|
4538
|
+
* `parseReturnStatement` without a started node.
|
|
4539
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
4540
|
+
* @param {number} start statement start offset
|
|
4541
|
+
* @returns {Node} return statement
|
|
4542
|
+
* @this {ParserInternals}
|
|
4543
|
+
*/
|
|
4544
|
+
_parseReturnStatementAt(start) {
|
|
4545
|
+
if (!this.allowReturn && !this._tryModuleFallback()) {
|
|
4546
|
+
this.raise(this.start, "'return' outside of function");
|
|
4547
|
+
}
|
|
4548
|
+
this.next();
|
|
4549
|
+
/** @type {Expression | null} */
|
|
4550
|
+
let argument = null;
|
|
4551
|
+
// `return` takes an optional argument, so eagerly look for a semicolon
|
|
4552
|
+
if (!(this.eat(tokTypes.semi) || this.insertSemicolon())) {
|
|
4553
|
+
argument = this.parseExpression();
|
|
4554
|
+
this.semicolon();
|
|
4555
|
+
}
|
|
4556
|
+
return /** @type {Node} */ (
|
|
4557
|
+
/** @type {unknown} */ (
|
|
4558
|
+
new ReturnStatementNode(start, this.lastTokEnd, argument)
|
|
4559
|
+
)
|
|
4560
|
+
);
|
|
4561
|
+
}
|
|
4562
|
+
|
|
4563
|
+
/**
|
|
4564
|
+
* `parseBreakContinueStatement` without a started node, landing on
|
|
4565
|
+
* `BreakContinueNode`'s single shape.
|
|
4566
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
4567
|
+
* @param {number} start statement start offset
|
|
4568
|
+
* @param {string} keyword `break` or `continue`
|
|
4569
|
+
* @returns {Node} break or continue statement
|
|
4570
|
+
* @this {ParserInternals}
|
|
4571
|
+
*/
|
|
4572
|
+
_parseBreakContinueStatementAt(start, keyword) {
|
|
4573
|
+
const isBreak = keyword === "break";
|
|
4574
|
+
this.next();
|
|
4575
|
+
/** @type {Identifier | null} */
|
|
4576
|
+
let label = null;
|
|
4577
|
+
if (this.eat(tokTypes.semi) || this.insertSemicolon()) {
|
|
4578
|
+
// no label
|
|
4579
|
+
} else if (this.type !== tokTypes.name) {
|
|
4580
|
+
this.unexpected();
|
|
4581
|
+
} else {
|
|
4582
|
+
label = this.parseIdent();
|
|
4583
|
+
this.semicolon();
|
|
4584
|
+
}
|
|
4585
|
+
// verify there is an actual destination to break or continue to
|
|
4586
|
+
const labels = this.labels;
|
|
4587
|
+
let i = 0;
|
|
4588
|
+
for (; i < labels.length; ++i) {
|
|
4589
|
+
const lab = labels[i];
|
|
4590
|
+
if (label === null || lab.name === label.name) {
|
|
4591
|
+
if (
|
|
4592
|
+
lab.kind !== null &&
|
|
4593
|
+
lab.kind !== undefined &&
|
|
4594
|
+
(isBreak || lab.kind === "loop")
|
|
4595
|
+
) {
|
|
4596
|
+
break;
|
|
4597
|
+
}
|
|
4598
|
+
if (label && isBreak) break;
|
|
4599
|
+
}
|
|
4600
|
+
}
|
|
4601
|
+
if (i === labels.length) this.raise(start, `Unsyntactic ${keyword}`);
|
|
4602
|
+
return /** @type {Node} */ (
|
|
4603
|
+
/** @type {unknown} */ (
|
|
4604
|
+
new BreakContinueNode(
|
|
4605
|
+
start,
|
|
4606
|
+
this.lastTokEnd,
|
|
4607
|
+
isBreak ? "BreakStatement" : "ContinueStatement",
|
|
4608
|
+
label
|
|
4609
|
+
)
|
|
4610
|
+
)
|
|
4611
|
+
);
|
|
4612
|
+
}
|
|
4613
|
+
|
|
4614
|
+
/**
|
|
4615
|
+
* `parseForStatement` without a started node (fast-path gate guarantees
|
|
4616
|
+
* `ecmaVersion >= 9`, folding acorn's version probes).
|
|
4617
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
4618
|
+
* @param {number} start statement start offset
|
|
4619
|
+
* @returns {Node} for/for-in/for-of statement
|
|
4620
|
+
* @this {ParserInternals}
|
|
4621
|
+
*/
|
|
4622
|
+
_parseForStatementAt(start) {
|
|
4623
|
+
this.next();
|
|
4624
|
+
const awaitAt =
|
|
4625
|
+
this.canAwait && this.eatContextual("await") ? this.lastTokStart : -1;
|
|
4626
|
+
this.labels.push(LOOP_LABEL);
|
|
4627
|
+
this.enterScope(0);
|
|
4628
|
+
this.expect(tokTypes.parenL);
|
|
4629
|
+
if (this.type === tokTypes.semi) {
|
|
4630
|
+
if (awaitAt > -1) this.unexpected(awaitAt);
|
|
4631
|
+
return this._parseForAt(start, null);
|
|
4632
|
+
}
|
|
4633
|
+
const isLet = this.isLet();
|
|
4634
|
+
if (this.type === tokTypes._var || this.type === tokTypes._const || isLet) {
|
|
4635
|
+
const initStart = this.start;
|
|
4636
|
+
const kind = isLet ? "let" : /** @type {string} */ (this.value);
|
|
4637
|
+
this.next();
|
|
4638
|
+
const scratch = this._acquireScratch();
|
|
4639
|
+
const count = this._parseVarInto(scratch, true, kind);
|
|
4640
|
+
const declarations = this._releaseScratch(scratch, count);
|
|
4641
|
+
const init = /** @type {Node} */ (
|
|
4642
|
+
/** @type {unknown} */ (
|
|
4643
|
+
new VariableDeclarationNode(
|
|
4644
|
+
initStart,
|
|
4645
|
+
this.lastTokEnd,
|
|
4646
|
+
declarations,
|
|
4647
|
+
kind
|
|
4648
|
+
)
|
|
4649
|
+
)
|
|
4650
|
+
);
|
|
4651
|
+
return this._parseForAfterInitAt(start, init, awaitAt);
|
|
4652
|
+
}
|
|
4653
|
+
const startsWithLet = this.isContextual("let");
|
|
4654
|
+
let isForOf = false;
|
|
4655
|
+
const usingKind = this.isUsing(true)
|
|
4656
|
+
? "using"
|
|
4657
|
+
: this.isAwaitUsing(true)
|
|
4658
|
+
? "await using"
|
|
4659
|
+
: null;
|
|
4660
|
+
if (usingKind) {
|
|
4661
|
+
const initStart = this.start;
|
|
4662
|
+
this.next();
|
|
4663
|
+
if (usingKind === "await using") {
|
|
4664
|
+
if (!this.canAwait) {
|
|
4665
|
+
this.raise(
|
|
4666
|
+
this.start,
|
|
4667
|
+
"Await using cannot appear outside of async function"
|
|
4668
|
+
);
|
|
4669
|
+
}
|
|
4670
|
+
this.next();
|
|
4671
|
+
}
|
|
4672
|
+
const scratch = this._acquireScratch();
|
|
4673
|
+
const count = this._parseVarInto(scratch, true, usingKind);
|
|
4674
|
+
const declarations = this._releaseScratch(scratch, count);
|
|
4675
|
+
const init = /** @type {Node} */ (
|
|
4676
|
+
/** @type {unknown} */ (
|
|
4677
|
+
new VariableDeclarationNode(
|
|
4678
|
+
initStart,
|
|
4679
|
+
this.lastTokEnd,
|
|
4680
|
+
declarations,
|
|
4681
|
+
usingKind
|
|
4682
|
+
)
|
|
4683
|
+
)
|
|
4684
|
+
);
|
|
4685
|
+
return this._parseForAfterInitAt(start, init, awaitAt);
|
|
4686
|
+
}
|
|
4687
|
+
const containsEsc = this.containsEsc;
|
|
4688
|
+
const refDestructuringErrors = this._acquireDestructuringErrors();
|
|
4689
|
+
const initPos = this.start;
|
|
4690
|
+
const init =
|
|
4691
|
+
awaitAt > -1
|
|
4692
|
+
? this.parseExprSubscripts(refDestructuringErrors, "await")
|
|
4693
|
+
: this.parseExpression(true, refDestructuringErrors);
|
|
4694
|
+
if (this.type === tokTypes._in || (isForOf = this.isContextual("of"))) {
|
|
4695
|
+
let isAwait = false;
|
|
4696
|
+
if (awaitAt > -1) {
|
|
4697
|
+
if (this.type === tokTypes._in) this.unexpected(awaitAt);
|
|
4698
|
+
isAwait = true;
|
|
4699
|
+
} else if (
|
|
4700
|
+
isForOf &&
|
|
4701
|
+
init.start === initPos &&
|
|
4702
|
+
!containsEsc &&
|
|
4703
|
+
init.type === "Identifier" &&
|
|
4704
|
+
/** @type {Identifier} */ (init).name === "async"
|
|
4705
|
+
) {
|
|
4706
|
+
this.unexpected();
|
|
4707
|
+
}
|
|
4708
|
+
if (startsWithLet && isForOf) {
|
|
4709
|
+
this.raise(
|
|
4710
|
+
init.start,
|
|
4711
|
+
"The left-hand side of a for-of loop may not start with 'let'."
|
|
4712
|
+
);
|
|
4713
|
+
}
|
|
4714
|
+
this.toAssignable(init, false, refDestructuringErrors);
|
|
4715
|
+
this.checkLValPattern(init);
|
|
4716
|
+
this._releaseDestructuringErrors();
|
|
4717
|
+
return this._parseForInAt(start, isAwait, /** @type {Node} */ (init));
|
|
4718
|
+
}
|
|
4719
|
+
this.checkExpressionErrors(refDestructuringErrors, true);
|
|
4720
|
+
this._releaseDestructuringErrors();
|
|
4721
|
+
if (awaitAt > -1) this.unexpected(awaitAt);
|
|
4722
|
+
return this._parseForAt(start, /** @type {Node} */ (init));
|
|
4723
|
+
}
|
|
4724
|
+
|
|
4725
|
+
/**
|
|
4726
|
+
* `parseForAfterInit` without a started node.
|
|
4727
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
4728
|
+
* @param {number} start statement start offset
|
|
4729
|
+
* @param {Node} init parsed variable declaration
|
|
4730
|
+
* @param {number} awaitAt offset of a consumed `await`, or -1
|
|
4731
|
+
* @returns {Node} for/for-in/for-of statement
|
|
4732
|
+
* @this {ParserInternals}
|
|
4733
|
+
*/
|
|
4734
|
+
_parseForAfterInitAt(start, init, awaitAt) {
|
|
4735
|
+
const target =
|
|
4736
|
+
/** @type {Node & { declarations: Node[], kind: string }} */ (init);
|
|
4737
|
+
if (
|
|
4738
|
+
(this.type === tokTypes._in || this.isContextual("of")) &&
|
|
4739
|
+
target.declarations.length === 1
|
|
4740
|
+
) {
|
|
4741
|
+
if (this.type === tokTypes._in) {
|
|
4742
|
+
if (
|
|
4743
|
+
(target.kind === "using" || target.kind === "await using") &&
|
|
4744
|
+
!(
|
|
4745
|
+
/** @type {Node & { init: Node | null }} */ (target.declarations[0])
|
|
4746
|
+
.init
|
|
4747
|
+
)
|
|
4748
|
+
) {
|
|
4749
|
+
this.raise(
|
|
4750
|
+
this.start,
|
|
4751
|
+
"Using declaration is not allowed in for-in loops"
|
|
4752
|
+
);
|
|
4753
|
+
}
|
|
4754
|
+
if (awaitAt > -1) this.unexpected(awaitAt);
|
|
4755
|
+
return this._parseForInAt(start, false, init);
|
|
4756
|
+
}
|
|
4757
|
+
return this._parseForInAt(start, awaitAt > -1, init);
|
|
4758
|
+
}
|
|
4759
|
+
if (awaitAt > -1) this.unexpected(awaitAt);
|
|
4760
|
+
return this._parseForAt(start, init);
|
|
4761
|
+
}
|
|
4762
|
+
|
|
4763
|
+
/**
|
|
4764
|
+
* `parseFor` without a started node, landing on `ForStatementNode`'s
|
|
4765
|
+
* single shape.
|
|
4766
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
4767
|
+
* @param {number} start statement start offset
|
|
4768
|
+
* @param {Node | null} init init clause
|
|
4769
|
+
* @returns {Node} for statement
|
|
4770
|
+
* @this {ParserInternals}
|
|
4771
|
+
*/
|
|
4772
|
+
_parseForAt(start, init) {
|
|
4773
|
+
this.expect(tokTypes.semi);
|
|
4774
|
+
const test = this.type === tokTypes.semi ? null : this.parseExpression();
|
|
4775
|
+
this.expect(tokTypes.semi);
|
|
4776
|
+
const update =
|
|
4777
|
+
this.type === tokTypes.parenR ? null : this.parseExpression();
|
|
4778
|
+
this.expect(tokTypes.parenR);
|
|
4779
|
+
const body = this.parseStatement("for");
|
|
4780
|
+
this.exitScope();
|
|
4781
|
+
this.labels.pop();
|
|
4782
|
+
return /** @type {Node} */ (
|
|
4783
|
+
/** @type {unknown} */ (
|
|
4784
|
+
new ForStatementNode(start, this.lastTokEnd, init, test, update, body)
|
|
4785
|
+
)
|
|
4786
|
+
);
|
|
4787
|
+
}
|
|
4788
|
+
|
|
4789
|
+
/**
|
|
4790
|
+
* `parseForIn` without a started node, landing on `ForInStatementNode`/
|
|
4791
|
+
* `ForOfStatementNode`'s single shapes.
|
|
4792
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
4793
|
+
* @param {number} start statement start offset
|
|
4794
|
+
* @param {boolean} isAwait whether this is `for await`
|
|
4795
|
+
* @param {Node} init loop target
|
|
4796
|
+
* @returns {Node} for-in or for-of statement
|
|
4797
|
+
* @this {ParserInternals}
|
|
4798
|
+
*/
|
|
4799
|
+
_parseForInAt(start, isAwait, init) {
|
|
4800
|
+
const isForIn = this.type === tokTypes._in;
|
|
4801
|
+
this.next();
|
|
4802
|
+
if (
|
|
4803
|
+
init.type === "VariableDeclaration" &&
|
|
4804
|
+
/** @type {Node & { init: Node | null }} */ (
|
|
4805
|
+
/** @type {Node & { declarations: Node[] }} */ (init).declarations[0]
|
|
4806
|
+
).init !== null &&
|
|
4807
|
+
(!isForIn ||
|
|
4808
|
+
this.strict ||
|
|
4809
|
+
/** @type {Node & { kind: string }} */ (init).kind !== "var" ||
|
|
4810
|
+
/** @type {Node & { id: Node }} */ (
|
|
4811
|
+
/** @type {Node & { declarations: Node[] }} */ (init).declarations[0]
|
|
4812
|
+
).id.type !== "Identifier")
|
|
4813
|
+
) {
|
|
4814
|
+
this.raise(
|
|
4815
|
+
init.start,
|
|
4816
|
+
`${
|
|
4817
|
+
isForIn ? "for-in" : "for-of"
|
|
4818
|
+
} loop variable declaration may not have an initializer`
|
|
4819
|
+
);
|
|
4820
|
+
}
|
|
4821
|
+
const right = isForIn ? this.parseExpression() : this.parseMaybeAssign();
|
|
4822
|
+
this.expect(tokTypes.parenR);
|
|
4823
|
+
const body = this.parseStatement("for");
|
|
4824
|
+
this.exitScope();
|
|
4825
|
+
this.labels.pop();
|
|
4826
|
+
return /** @type {Node} */ (
|
|
4827
|
+
/** @type {unknown} */ (
|
|
4828
|
+
isForIn
|
|
4829
|
+
? new ForInStatementNode(start, this.lastTokEnd, init, right, body)
|
|
4830
|
+
: new ForOfStatementNode(
|
|
4831
|
+
start,
|
|
4832
|
+
this.lastTokEnd,
|
|
4833
|
+
isAwait,
|
|
4834
|
+
init,
|
|
4835
|
+
right,
|
|
4836
|
+
body
|
|
4837
|
+
)
|
|
4838
|
+
)
|
|
4839
|
+
);
|
|
4840
|
+
}
|
|
4841
|
+
|
|
4842
|
+
/**
|
|
4843
|
+
* `parseSwitchStatement` without a started node, landing on
|
|
4844
|
+
* `SwitchStatementNode`'s single shape with pre-shaped `SwitchCaseNode`s.
|
|
4845
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
4846
|
+
* @param {number} start statement start offset
|
|
4847
|
+
* @returns {Node} switch statement
|
|
4848
|
+
* @this {ParserInternals}
|
|
4849
|
+
*/
|
|
4850
|
+
_parseSwitchStatementAt(start) {
|
|
4851
|
+
this.next();
|
|
4852
|
+
const discriminant = this.parseParenExpression();
|
|
4853
|
+
/** @type {Node[]} */
|
|
4854
|
+
const cases = [];
|
|
4855
|
+
this.expect(tokTypes.braceL);
|
|
4856
|
+
this.labels.push(SWITCH_LABEL);
|
|
4857
|
+
this.enterScope(SCOPE_SWITCH);
|
|
4858
|
+
/** @type {SwitchCaseNode | undefined} */
|
|
4859
|
+
let cur;
|
|
4860
|
+
for (let sawDefault = false; this.type !== tokTypes.braceR;) {
|
|
4861
|
+
if (this.type === tokTypes._case || this.type === tokTypes._default) {
|
|
4862
|
+
const isCase = this.type === tokTypes._case;
|
|
4863
|
+
if (cur) this.finishNode(/** @type {Node} */ (cur), "SwitchCase");
|
|
4864
|
+
cur = new SwitchCaseNode(this.start);
|
|
4865
|
+
cases.push(/** @type {Node} */ (cur));
|
|
4866
|
+
cur.consequent = [];
|
|
4867
|
+
this.next();
|
|
4868
|
+
if (isCase) {
|
|
4869
|
+
cur.test = this.parseExpression();
|
|
4870
|
+
} else {
|
|
4871
|
+
if (sawDefault) {
|
|
4872
|
+
this.raiseRecoverable(
|
|
4873
|
+
this.lastTokStart,
|
|
4874
|
+
"Multiple default clauses"
|
|
4875
|
+
);
|
|
4876
|
+
}
|
|
4877
|
+
sawDefault = true;
|
|
4878
|
+
cur.test = null;
|
|
4879
|
+
}
|
|
4880
|
+
this.expect(tokTypes.colon);
|
|
4881
|
+
} else {
|
|
4882
|
+
if (!cur) this.unexpected();
|
|
4883
|
+
/** @type {Node[]} */ (
|
|
4884
|
+
/** @type {SwitchCaseNode} */ (cur).consequent
|
|
4885
|
+
).push(this.parseStatement(null));
|
|
4886
|
+
}
|
|
4887
|
+
}
|
|
4888
|
+
this.exitScope();
|
|
4889
|
+
if (cur) this.finishNode(/** @type {Node} */ (cur), "SwitchCase");
|
|
4890
|
+
this.next(); // closing brace
|
|
4891
|
+
this.labels.pop();
|
|
4892
|
+
return /** @type {Node} */ (
|
|
4893
|
+
/** @type {unknown} */ (
|
|
4894
|
+
new SwitchStatementNode(start, this.lastTokEnd, discriminant, cases)
|
|
4895
|
+
)
|
|
4896
|
+
);
|
|
4897
|
+
}
|
|
4898
|
+
|
|
4899
|
+
/**
|
|
4900
|
+
* `parseThrowStatement` without a started node; the illegal-newline probe
|
|
4901
|
+
* runs on the tokenizer's newline flag instead of acorn's gap slice+regexp.
|
|
4902
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
4903
|
+
* @param {number} start statement start offset
|
|
4904
|
+
* @returns {Node} throw statement
|
|
4905
|
+
* @this {ParserInternals}
|
|
4906
|
+
*/
|
|
4907
|
+
_parseThrowStatementAt(start) {
|
|
4908
|
+
this.next();
|
|
4909
|
+
if (this._gapHasNewline()) {
|
|
4910
|
+
this.raise(this.lastTokEnd, "Illegal newline after throw");
|
|
4911
|
+
}
|
|
4912
|
+
const argument = this.parseExpression();
|
|
4913
|
+
this.semicolon();
|
|
4914
|
+
return /** @type {Node} */ (
|
|
4915
|
+
/** @type {unknown} */ (
|
|
4916
|
+
new ThrowStatementNode(start, this.lastTokEnd, argument)
|
|
4917
|
+
)
|
|
4918
|
+
);
|
|
4919
|
+
}
|
|
4920
|
+
|
|
4921
|
+
/**
|
|
4922
|
+
* `parseTryStatement` without a started node, landing on
|
|
4923
|
+
* `TryStatementNode`/`CatchClauseNode`'s single shapes.
|
|
4924
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
4925
|
+
* @param {number} start statement start offset
|
|
4926
|
+
* @returns {Node} try statement
|
|
4927
|
+
* @this {ParserInternals}
|
|
4928
|
+
*/
|
|
4929
|
+
_parseTryStatementAt(start) {
|
|
4930
|
+
this.next();
|
|
4931
|
+
const block = this.parseBlock();
|
|
4932
|
+
/** @type {Node | null} */
|
|
4933
|
+
let handler = null;
|
|
4934
|
+
if (this.type === tokTypes._catch) {
|
|
4935
|
+
const clauseStart = this.start;
|
|
4936
|
+
this.next();
|
|
4937
|
+
/** @type {Node | null} */
|
|
4938
|
+
let param;
|
|
4939
|
+
if (this.eat(tokTypes.parenL)) {
|
|
4940
|
+
param = this.parseCatchClauseParam();
|
|
4941
|
+
} else {
|
|
4942
|
+
if (this._ecmaVersion < 10) this.unexpected();
|
|
4943
|
+
param = null;
|
|
4944
|
+
this.enterScope(0);
|
|
4945
|
+
}
|
|
4946
|
+
const body = this.parseBlock(false);
|
|
4947
|
+
this.exitScope();
|
|
4948
|
+
handler = /** @type {Node} */ (
|
|
4949
|
+
/** @type {unknown} */ (
|
|
4950
|
+
new CatchClauseNode(clauseStart, this.lastTokEnd, param, body)
|
|
4951
|
+
)
|
|
4952
|
+
);
|
|
4953
|
+
}
|
|
4954
|
+
const finalizer = this.eat(tokTypes._finally) ? this.parseBlock() : null;
|
|
4955
|
+
if (!handler && !finalizer) {
|
|
4956
|
+
this.raise(start, "Missing catch or finally clause");
|
|
4957
|
+
}
|
|
4958
|
+
return /** @type {Node} */ (
|
|
4959
|
+
/** @type {unknown} */ (
|
|
4960
|
+
new TryStatementNode(start, this.lastTokEnd, block, handler, finalizer)
|
|
4961
|
+
)
|
|
4962
|
+
);
|
|
4963
|
+
}
|
|
4964
|
+
|
|
4965
|
+
/**
|
|
4966
|
+
* `parseWhileStatement` without a started node, landing on
|
|
4967
|
+
* `WhileStatementNode`'s single shape.
|
|
4968
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
4969
|
+
* @param {number} start statement start offset
|
|
4970
|
+
* @returns {Node} while statement
|
|
4971
|
+
* @this {ParserInternals}
|
|
4972
|
+
*/
|
|
4973
|
+
_parseWhileStatementAt(start) {
|
|
4974
|
+
this.next();
|
|
4975
|
+
const test = this.parseParenExpression();
|
|
4976
|
+
this.labels.push(LOOP_LABEL);
|
|
4977
|
+
const body = this.parseStatement("while");
|
|
4978
|
+
this.labels.pop();
|
|
4979
|
+
return /** @type {Node} */ (
|
|
4980
|
+
/** @type {unknown} */ (
|
|
4981
|
+
new WhileStatementNode(start, this.lastTokEnd, test, body)
|
|
4982
|
+
)
|
|
4983
|
+
);
|
|
4984
|
+
}
|
|
4985
|
+
|
|
4986
|
+
/**
|
|
4987
|
+
* Owned `parseSpread` landing on `RestSpreadNode`'s single shape.
|
|
4988
|
+
* Non-lazy mode delegates.
|
|
4989
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/lval.js
|
|
4990
|
+
* @param {DestructuringErrorsShim | null=} refDestructuringErrors destructuring errors to fill
|
|
4991
|
+
* @returns {Node} spread element
|
|
4992
|
+
* @this {ParserInternals}
|
|
4993
|
+
*/
|
|
4994
|
+
parseSpread(refDestructuringErrors) {
|
|
4995
|
+
if (!this._lazy) {
|
|
4996
|
+
return base.parseSpread.call(this, refDestructuringErrors);
|
|
4997
|
+
}
|
|
4998
|
+
const start = this.start;
|
|
4999
|
+
this.next();
|
|
5000
|
+
const argument = this.parseMaybeAssign(false, refDestructuringErrors);
|
|
5001
|
+
return /** @type {Node} */ (
|
|
5002
|
+
/** @type {unknown} */ (
|
|
5003
|
+
new RestSpreadNode(start, this.lastTokEnd, "SpreadElement", argument)
|
|
5004
|
+
)
|
|
5005
|
+
);
|
|
5006
|
+
}
|
|
5007
|
+
|
|
5008
|
+
/**
|
|
5009
|
+
* Owned `parseMaybeConditional` landing on
|
|
5010
|
+
* `ConditionalExpressionNode`'s single shape. Non-lazy mode delegates.
|
|
5011
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
5012
|
+
* @param {boolean | string=} forInit for-init context flag
|
|
5013
|
+
* @param {DestructuringErrorsShim | null=} refDestructuringErrors destructuring errors to fill
|
|
5014
|
+
* @returns {Expression} expression node
|
|
5015
|
+
* @this {ParserInternals}
|
|
5016
|
+
*/
|
|
5017
|
+
parseMaybeConditional(forInit, refDestructuringErrors) {
|
|
5018
|
+
if (!this._lazy) {
|
|
5019
|
+
return base.parseMaybeConditional.call(
|
|
5020
|
+
this,
|
|
5021
|
+
forInit,
|
|
5022
|
+
refDestructuringErrors
|
|
5023
|
+
);
|
|
5024
|
+
}
|
|
5025
|
+
const startPos = this.start;
|
|
5026
|
+
const expr = this.parseExprOps(forInit, refDestructuringErrors);
|
|
5027
|
+
if (this.checkExpressionErrors(refDestructuringErrors)) return expr;
|
|
5028
|
+
const isArrowAtStart = this._arrowFastPath
|
|
5029
|
+
? expr === this._lastArrow && expr.start === startPos
|
|
5030
|
+
: expr.type === "ArrowFunctionExpression" && expr.start === startPos;
|
|
5031
|
+
if (!isArrowAtStart && this.eat(tokTypes.question)) {
|
|
5032
|
+
const consequent = this.parseMaybeAssign();
|
|
5033
|
+
this.expect(tokTypes.colon);
|
|
5034
|
+
const alternate = this.parseMaybeAssign(forInit);
|
|
5035
|
+
return /** @type {Expression} */ (
|
|
5036
|
+
/** @type {unknown} */ (
|
|
5037
|
+
new ConditionalExpressionNode(
|
|
5038
|
+
startPos,
|
|
5039
|
+
this.lastTokEnd,
|
|
5040
|
+
expr,
|
|
5041
|
+
consequent,
|
|
5042
|
+
alternate
|
|
5043
|
+
)
|
|
5044
|
+
)
|
|
5045
|
+
);
|
|
5046
|
+
}
|
|
5047
|
+
return expr;
|
|
5048
|
+
}
|
|
5049
|
+
|
|
5050
|
+
/**
|
|
5051
|
+
* acorn's `parseArrowExpression` plus `_lastArrow` tracking — arrows are
|
|
5052
|
+
* created and returned only here, so the expression-spine probes can test
|
|
5053
|
+
* node identity instead of the megamorphic `.type` load. A plugin fabricating
|
|
5054
|
+
* arrow nodes in an overridden `parseExprAtom` bypasses the gate (same
|
|
5055
|
+
* acceptance class as `_stmtFastPath`).
|
|
5056
|
+
* @param {Node} node started node
|
|
5057
|
+
* @param {Node[]} params parameter expressions
|
|
5058
|
+
* @param {boolean} isAsync async arrow
|
|
5059
|
+
* @param {boolean | string=} forInit for-init context flag
|
|
5060
|
+
* @returns {Expression} arrow function expression
|
|
5061
|
+
* @this {ParserInternals}
|
|
5062
|
+
*/
|
|
5063
|
+
parseArrowExpression(node, params, isAsync, forInit) {
|
|
5064
|
+
if (!this._funcFastPath) {
|
|
5065
|
+
const result = base.parseArrowExpression.call(
|
|
5066
|
+
this,
|
|
5067
|
+
node,
|
|
5068
|
+
params,
|
|
5069
|
+
isAsync,
|
|
5070
|
+
forInit
|
|
5071
|
+
);
|
|
5072
|
+
this._lastArrow = result;
|
|
5073
|
+
return result;
|
|
5074
|
+
}
|
|
5075
|
+
// acorn's body with the started node replaced by the pre-shaped
|
|
5076
|
+
// FunctionNode (initFunction's writes are its constructor defaults)
|
|
5077
|
+
const functionNode = /** @type {Node} */ (
|
|
5078
|
+
/** @type {unknown} */ (new FunctionNode(node.start))
|
|
5079
|
+
);
|
|
5080
|
+
const oldYieldPos = this.yieldPos;
|
|
5081
|
+
const oldAwaitPos = this.awaitPos;
|
|
5082
|
+
const oldAwaitIdentPos = this.awaitIdentPos;
|
|
5083
|
+
this.enterScope(SCOPE_FUNCTION | (isAsync ? SCOPE_ASYNC : 0) | SCOPE_ARROW);
|
|
5084
|
+
/** @type {Node & { async: boolean, params?: Node[] }} */ (
|
|
5085
|
+
functionNode
|
|
5086
|
+
).async = Boolean(isAsync);
|
|
5087
|
+
this.yieldPos = 0;
|
|
5088
|
+
this.awaitPos = 0;
|
|
5089
|
+
this.awaitIdentPos = 0;
|
|
5090
|
+
/** @type {Node & { params?: Node[] }} */ (functionNode).params =
|
|
5091
|
+
/** @type {Node[]} */ (this.toAssignableList(params, true));
|
|
5092
|
+
this.parseFunctionBody(functionNode, true, false, forInit);
|
|
5093
|
+
this.yieldPos = oldYieldPos;
|
|
5094
|
+
this.awaitPos = oldAwaitPos;
|
|
5095
|
+
this.awaitIdentPos = oldAwaitIdentPos;
|
|
5096
|
+
const result = /** @type {Expression} */ (
|
|
5097
|
+
/** @type {unknown} */ (
|
|
5098
|
+
this.finishNode(functionNode, "ArrowFunctionExpression")
|
|
5099
|
+
)
|
|
5100
|
+
);
|
|
5101
|
+
this._lastArrow = result;
|
|
5102
|
+
return result;
|
|
5103
|
+
}
|
|
5104
|
+
|
|
5105
|
+
/**
|
|
5106
|
+
* Owned `parseFunction`, an exact-semantics copy of acorn 8's landing on
|
|
5107
|
+
* `FunctionNode`'s pre-declared shape (the passed started node is discarded,
|
|
5108
|
+
* matching acorn's observable output; `initFunction`'s writes are the
|
|
5109
|
+
* constructor defaults). Non-lazy mode and plugin overrides delegate.
|
|
5110
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
5111
|
+
* @param {Node} node started node from the caller
|
|
5112
|
+
* @param {number} statement FUNC_* statement bit flags
|
|
5113
|
+
* @param {boolean=} allowExpressionBody whether an expression body is allowed
|
|
5114
|
+
* @param {boolean=} isAsync whether the function is async
|
|
5115
|
+
* @param {boolean | string=} forInit for-init context flag
|
|
5116
|
+
* @returns {Expression} function declaration or expression
|
|
5117
|
+
* @this {ParserInternals}
|
|
5118
|
+
*/
|
|
5119
|
+
parseFunction(node, statement, allowExpressionBody, isAsync, forInit) {
|
|
5120
|
+
if (!this._funcFastPath) {
|
|
5121
|
+
return base.parseFunction.call(
|
|
5122
|
+
this,
|
|
5123
|
+
node,
|
|
5124
|
+
statement,
|
|
5125
|
+
allowExpressionBody,
|
|
5126
|
+
isAsync,
|
|
5127
|
+
forInit
|
|
5128
|
+
);
|
|
5129
|
+
}
|
|
5130
|
+
return this._parseFunctionAt(
|
|
5131
|
+
node.start,
|
|
5132
|
+
statement,
|
|
5133
|
+
allowExpressionBody === true,
|
|
5134
|
+
isAsync === true,
|
|
5135
|
+
forInit
|
|
5136
|
+
);
|
|
5137
|
+
}
|
|
5138
|
+
|
|
5139
|
+
/**
|
|
5140
|
+
* `parseFunction` without a started node (fast-path gate guarantees
|
|
5141
|
+
* `ecmaVersion >= 9`, folding acorn's version probes).
|
|
5142
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
5143
|
+
* @param {number} start function start offset
|
|
5144
|
+
* @param {number} statement FUNC_* statement bit flags
|
|
5145
|
+
* @param {boolean} allowExpressionBody whether an expression body is allowed
|
|
5146
|
+
* @param {boolean} isAsync whether the function is async
|
|
5147
|
+
* @param {boolean | string=} forInit for-init context flag
|
|
5148
|
+
* @returns {Expression} function declaration or expression
|
|
5149
|
+
* @this {ParserInternals}
|
|
5150
|
+
*/
|
|
5151
|
+
_parseFunctionAt(start, statement, allowExpressionBody, isAsync, forInit) {
|
|
5152
|
+
const node =
|
|
5153
|
+
/** @type {Node & { id: Identifier | null, generator: boolean, async: boolean }} */ (
|
|
5154
|
+
/** @type {unknown} */ (new FunctionNode(start))
|
|
5155
|
+
);
|
|
5156
|
+
if (this.type === tokTypes.star && statement & FUNC_HANGING_STATEMENT) {
|
|
5157
|
+
this.unexpected();
|
|
5158
|
+
}
|
|
5159
|
+
node.generator = this.eat(tokTypes.star);
|
|
5160
|
+
node.async = isAsync;
|
|
5161
|
+
if (statement & FUNC_STATEMENT) {
|
|
5162
|
+
node.id =
|
|
5163
|
+
statement & FUNC_NULLABLE_ID && this.type !== tokTypes.name
|
|
5164
|
+
? null
|
|
5165
|
+
: this.parseIdent();
|
|
5166
|
+
if (node.id && !(statement & FUNC_HANGING_STATEMENT)) {
|
|
5167
|
+
// Annex B: sloppy-mode function declarations bind like vars
|
|
5168
|
+
this.checkLValSimple(
|
|
5169
|
+
node.id,
|
|
5170
|
+
this.strict || node.generator || node.async
|
|
5171
|
+
? this.treatFunctionsAsVar
|
|
5172
|
+
? BIND_VAR
|
|
5173
|
+
: BIND_LEXICAL
|
|
5174
|
+
: /* BIND_FUNCTION */ 3
|
|
5175
|
+
);
|
|
5176
|
+
}
|
|
5177
|
+
}
|
|
5178
|
+
const oldYieldPos = this.yieldPos;
|
|
5179
|
+
const oldAwaitPos = this.awaitPos;
|
|
5180
|
+
const oldAwaitIdentPos = this.awaitIdentPos;
|
|
5181
|
+
this.yieldPos = 0;
|
|
5182
|
+
this.awaitPos = 0;
|
|
5183
|
+
this.awaitIdentPos = 0;
|
|
5184
|
+
this.enterScope(
|
|
5185
|
+
SCOPE_FUNCTION |
|
|
5186
|
+
(node.async ? SCOPE_ASYNC : 0) |
|
|
5187
|
+
(node.generator ? SCOPE_GENERATOR : 0)
|
|
5188
|
+
);
|
|
5189
|
+
if (!(statement & FUNC_STATEMENT)) {
|
|
5190
|
+
node.id = this.type === tokTypes.name ? this.parseIdent() : null;
|
|
5191
|
+
}
|
|
5192
|
+
this.parseFunctionParams(node);
|
|
5193
|
+
this.parseFunctionBody(node, allowExpressionBody, false, forInit);
|
|
5194
|
+
this.yieldPos = oldYieldPos;
|
|
5195
|
+
this.awaitPos = oldAwaitPos;
|
|
5196
|
+
this.awaitIdentPos = oldAwaitIdentPos;
|
|
5197
|
+
return /** @type {Expression} */ (
|
|
5198
|
+
/** @type {unknown} */ (
|
|
5199
|
+
this.finishNode(
|
|
5200
|
+
node,
|
|
5201
|
+
statement & FUNC_STATEMENT
|
|
5202
|
+
? "FunctionDeclaration"
|
|
5203
|
+
: "FunctionExpression"
|
|
5204
|
+
)
|
|
5205
|
+
)
|
|
5206
|
+
);
|
|
5207
|
+
}
|
|
5208
|
+
|
|
5209
|
+
/**
|
|
5210
|
+
* Owned `parseFunctionBody`, an exact-semantics copy of acorn 8's with
|
|
5211
|
+
* `isSimpleParamList` inlined and computed once (acorn walks the params
|
|
5212
|
+
* twice) — the fast-path gate pins it to acorn's own implementation.
|
|
5213
|
+
* Non-lazy mode and plugin overrides delegate.
|
|
5214
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
5215
|
+
* @param {Node} node function node being filled
|
|
5216
|
+
* @param {boolean} isArrowFunction whether this is an arrow function
|
|
5217
|
+
* @param {boolean} isMethod whether this is an object/class method
|
|
5218
|
+
* @param {boolean | string=} forInit for-init context flag
|
|
5219
|
+
* @returns {void}
|
|
5220
|
+
* @this {ParserInternals}
|
|
5221
|
+
*/
|
|
5222
|
+
parseFunctionBody(node, isArrowFunction, isMethod, forInit) {
|
|
5223
|
+
if (!this._funcFastPath) {
|
|
5224
|
+
return base.parseFunctionBody.call(
|
|
5225
|
+
this,
|
|
5226
|
+
node,
|
|
5227
|
+
isArrowFunction,
|
|
5228
|
+
isMethod,
|
|
5229
|
+
forInit
|
|
5230
|
+
);
|
|
5231
|
+
}
|
|
5232
|
+
const target =
|
|
5233
|
+
/** @type {Node & { id: Identifier | null, params: Node[], body: Node, expression: boolean }} */ (
|
|
5234
|
+
node
|
|
5235
|
+
);
|
|
5236
|
+
const isExpression = isArrowFunction && this.type !== tokTypes.braceL;
|
|
5237
|
+
const oldStrict = this.strict;
|
|
5238
|
+
let useStrict = false;
|
|
5239
|
+
if (isExpression) {
|
|
5240
|
+
target.body = this.parseMaybeAssign(forInit);
|
|
5241
|
+
target.expression = true;
|
|
5242
|
+
this.checkParams(node, false);
|
|
5243
|
+
} else {
|
|
5244
|
+
// acorn's isSimpleParamList, inlined and shared by both its call sites
|
|
5245
|
+
const params = target.params;
|
|
5246
|
+
let simpleParams = true;
|
|
5247
|
+
for (let i = 0; i < params.length; i++) {
|
|
5248
|
+
if (params[i].type !== "Identifier") {
|
|
5249
|
+
simpleParams = false;
|
|
5250
|
+
break;
|
|
5251
|
+
}
|
|
5252
|
+
}
|
|
5253
|
+
if (!oldStrict || !simpleParams) {
|
|
5254
|
+
useStrict = this.strictDirective(this.end);
|
|
5255
|
+
if (useStrict && !simpleParams) {
|
|
5256
|
+
this.raiseRecoverable(
|
|
5257
|
+
node.start,
|
|
5258
|
+
"Illegal 'use strict' directive in function with non-simple parameter list"
|
|
5259
|
+
);
|
|
5260
|
+
}
|
|
5261
|
+
}
|
|
5262
|
+
const oldLabels = this.labels;
|
|
5263
|
+
this.labels = [];
|
|
5264
|
+
if (useStrict) this.strict = true;
|
|
5265
|
+
this.checkParams(
|
|
5266
|
+
node,
|
|
5267
|
+
!oldStrict &&
|
|
5268
|
+
!useStrict &&
|
|
5269
|
+
!isArrowFunction &&
|
|
5270
|
+
!isMethod &&
|
|
5271
|
+
simpleParams
|
|
5272
|
+
);
|
|
5273
|
+
if (this.strict && target.id) {
|
|
5274
|
+
this.checkLValSimple(target.id, BIND_OUTSIDE);
|
|
5275
|
+
}
|
|
5276
|
+
target.body = this.parseBlock(false, undefined, useStrict && !oldStrict);
|
|
5277
|
+
target.expression = false;
|
|
5278
|
+
this.adaptDirectivePrologue(
|
|
5279
|
+
/** @type {Node & { body: Node[] }} */ (target.body).body
|
|
5280
|
+
);
|
|
5281
|
+
this.labels = oldLabels;
|
|
5282
|
+
}
|
|
5283
|
+
this.exitScope();
|
|
5284
|
+
}
|
|
5285
|
+
|
|
5286
|
+
/**
|
|
5287
|
+
* Owned `parseBindingAtom`: acorn's exact dispatch minus the per-call
|
|
5288
|
+
* normalized-options read. Non-lazy mode and pre-ES6 delegate.
|
|
5289
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/lval.js
|
|
5290
|
+
* @returns {Node} binding atom (identifier or pattern)
|
|
5291
|
+
* @this {ParserInternals}
|
|
5292
|
+
*/
|
|
5293
|
+
parseBindingAtom() {
|
|
5294
|
+
if (!this._lazy || this._ecmaVersion < 6) {
|
|
5295
|
+
return base.parseBindingAtom.call(this);
|
|
5296
|
+
}
|
|
5297
|
+
const type = this.type;
|
|
5298
|
+
if (type === tokTypes.bracketL) {
|
|
5299
|
+
const node = /** @type {Node & { elements?: Node[] }} */ (
|
|
5300
|
+
this.startNode()
|
|
5301
|
+
);
|
|
5302
|
+
this.next();
|
|
5303
|
+
node.elements = this.parseBindingList(tokTypes.bracketR, true, true);
|
|
5304
|
+
return this.finishNode(node, "ArrayPattern");
|
|
5305
|
+
}
|
|
5306
|
+
if (type === tokTypes.braceL) return this.parseObj(true);
|
|
5307
|
+
return this.parseIdent();
|
|
5308
|
+
}
|
|
5309
|
+
|
|
5310
|
+
/**
|
|
5311
|
+
* Owned `parseExprSubscripts`, an exact copy of acorn 8's with the arrow
|
|
5312
|
+
* probe served by `_lastArrow` identity. Delegates when the fast path is off.
|
|
5313
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
5314
|
+
* @param {DestructuringErrorsShim | null=} refDestructuringErrors destructuring errors to fill
|
|
5315
|
+
* @param {boolean | string=} forInit for-init context flag
|
|
5316
|
+
* @returns {Expression} expression node
|
|
5317
|
+
* @this {ParserInternals}
|
|
5318
|
+
*/
|
|
5319
|
+
parseExprSubscripts(refDestructuringErrors, forInit) {
|
|
5320
|
+
if (!this._arrowFastPath) {
|
|
5321
|
+
return base.parseExprSubscripts.call(
|
|
5322
|
+
this,
|
|
5323
|
+
refDestructuringErrors,
|
|
5324
|
+
forInit
|
|
5325
|
+
);
|
|
5326
|
+
}
|
|
5327
|
+
const startPos = this.start;
|
|
5328
|
+
const startLoc = this.startLoc;
|
|
5329
|
+
const expr = this.parseExprAtom(refDestructuringErrors, forInit);
|
|
5330
|
+
if (
|
|
5331
|
+
expr === this._lastArrow &&
|
|
5332
|
+
this.input.slice(this.lastTokStart, this.lastTokEnd) !== ")"
|
|
5333
|
+
) {
|
|
5334
|
+
return expr;
|
|
5335
|
+
}
|
|
5336
|
+
const result = this.parseSubscripts(
|
|
5337
|
+
expr,
|
|
5338
|
+
startPos,
|
|
5339
|
+
startLoc,
|
|
5340
|
+
false,
|
|
5341
|
+
forInit
|
|
5342
|
+
);
|
|
5343
|
+
if (refDestructuringErrors && result.type === "MemberExpression") {
|
|
5344
|
+
if (refDestructuringErrors.parenthesizedAssign >= result.start) {
|
|
5345
|
+
refDestructuringErrors.parenthesizedAssign = -1;
|
|
5346
|
+
}
|
|
5347
|
+
if (refDestructuringErrors.parenthesizedBind >= result.start) {
|
|
5348
|
+
refDestructuringErrors.parenthesizedBind = -1;
|
|
5349
|
+
}
|
|
5350
|
+
if (refDestructuringErrors.trailingComma >= result.start) {
|
|
5351
|
+
refDestructuringErrors.trailingComma = -1;
|
|
5352
|
+
}
|
|
5353
|
+
}
|
|
5354
|
+
return result;
|
|
5355
|
+
}
|
|
5356
|
+
|
|
5357
|
+
/**
|
|
5358
|
+
* Owned `parseExprList`, an exact-semantics copy of acorn 8's built in a
|
|
5359
|
+
* scratch array and materialized exactly sized. Non-lazy mode delegates.
|
|
5360
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
5361
|
+
* @param {TokenType} close closing token type
|
|
5362
|
+
* @param {boolean} allowTrailingComma whether a trailing comma is allowed
|
|
5363
|
+
* @param {boolean} allowEmpty whether holes are allowed
|
|
5364
|
+
* @param {DestructuringErrorsShim | null=} refDestructuringErrors destructuring errors to fill
|
|
5365
|
+
* @returns {Expression[]} parsed elements (`null` for holes)
|
|
5366
|
+
* @this {ParserInternals}
|
|
5367
|
+
*/
|
|
5368
|
+
parseExprList(close, allowTrailingComma, allowEmpty, refDestructuringErrors) {
|
|
5369
|
+
if (!this._lazy) {
|
|
5370
|
+
return base.parseExprList.call(
|
|
5371
|
+
this,
|
|
5372
|
+
close,
|
|
5373
|
+
allowTrailingComma,
|
|
5374
|
+
allowEmpty,
|
|
5375
|
+
refDestructuringErrors
|
|
5376
|
+
);
|
|
5377
|
+
}
|
|
5378
|
+
const scratch = this._acquireScratch();
|
|
5379
|
+
let count = 0;
|
|
5380
|
+
let first = true;
|
|
5381
|
+
while (!this.eat(close)) {
|
|
5382
|
+
if (!first) {
|
|
5383
|
+
this.expect(tokTypes.comma);
|
|
5384
|
+
if (allowTrailingComma && this.afterTrailingComma(close)) break;
|
|
5385
|
+
} else {
|
|
5386
|
+
first = false;
|
|
5387
|
+
}
|
|
5388
|
+
let elt;
|
|
5389
|
+
if (allowEmpty && this.type === tokTypes.comma) {
|
|
5390
|
+
elt = null;
|
|
5391
|
+
} else if (this.type === tokTypes.ellipsis) {
|
|
5392
|
+
elt = this.parseSpread(refDestructuringErrors);
|
|
5393
|
+
if (
|
|
5394
|
+
refDestructuringErrors &&
|
|
5395
|
+
this.type === tokTypes.comma &&
|
|
5396
|
+
refDestructuringErrors.trailingComma < 0
|
|
5397
|
+
) {
|
|
5398
|
+
refDestructuringErrors.trailingComma = this.start;
|
|
5399
|
+
}
|
|
5400
|
+
} else {
|
|
5401
|
+
elt = this.parseMaybeAssign(false, refDestructuringErrors);
|
|
5402
|
+
}
|
|
5403
|
+
scratch[count++] = elt;
|
|
5404
|
+
}
|
|
5405
|
+
return this._releaseScratch(scratch, count);
|
|
5406
|
+
}
|
|
5407
|
+
|
|
5408
|
+
/**
|
|
5409
|
+
* Owned `parseBindingList`, an exact-semantics copy of acorn 8's built in a
|
|
5410
|
+
* scratch array and materialized exactly sized. Non-lazy mode delegates.
|
|
5411
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/lval.js
|
|
5412
|
+
* @param {TokenType} close closing token type
|
|
5413
|
+
* @param {boolean} allowEmpty whether holes are allowed
|
|
5414
|
+
* @param {boolean} allowTrailingComma whether a trailing comma is allowed
|
|
5415
|
+
* @param {boolean=} allowModifiers passed through to `parseAssignableListItem`
|
|
5416
|
+
* @returns {Node[]} parsed bindings (`null` for holes)
|
|
5417
|
+
* @this {ParserInternals}
|
|
5418
|
+
*/
|
|
5419
|
+
parseBindingList(close, allowEmpty, allowTrailingComma, allowModifiers) {
|
|
5420
|
+
if (!this._lazy) {
|
|
5421
|
+
return base.parseBindingList.call(
|
|
5422
|
+
this,
|
|
5423
|
+
close,
|
|
5424
|
+
allowEmpty,
|
|
5425
|
+
allowTrailingComma,
|
|
5426
|
+
allowModifiers
|
|
5427
|
+
);
|
|
5428
|
+
}
|
|
5429
|
+
const scratch = this._acquireScratch();
|
|
5430
|
+
let count = 0;
|
|
5431
|
+
let first = true;
|
|
5432
|
+
while (!this.eat(close)) {
|
|
5433
|
+
if (first) first = false;
|
|
5434
|
+
else this.expect(tokTypes.comma);
|
|
5435
|
+
if (allowEmpty && this.type === tokTypes.comma) {
|
|
5436
|
+
scratch[count++] = null;
|
|
5437
|
+
} else if (allowTrailingComma && this.afterTrailingComma(close)) {
|
|
5438
|
+
break;
|
|
5439
|
+
} else if (this.type === tokTypes.ellipsis) {
|
|
5440
|
+
const rest = this.parseRestBinding();
|
|
5441
|
+
this.parseBindingListItem(rest);
|
|
5442
|
+
scratch[count++] = rest;
|
|
5443
|
+
if (this.type === tokTypes.comma) {
|
|
5444
|
+
this.raiseRecoverable(
|
|
5445
|
+
this.start,
|
|
5446
|
+
"Comma is not permitted after the rest element"
|
|
5447
|
+
);
|
|
5448
|
+
}
|
|
5449
|
+
this.expect(close);
|
|
5450
|
+
break;
|
|
5451
|
+
} else {
|
|
5452
|
+
scratch[count++] = this.parseAssignableListItem(allowModifiers);
|
|
5453
|
+
}
|
|
5454
|
+
}
|
|
5455
|
+
return this._releaseScratch(scratch, count);
|
|
5456
|
+
}
|
|
5457
|
+
|
|
5458
|
+
/**
|
|
5459
|
+
* Owned `parseParenAndDistinguishExpression`, an exact-semantics copy of
|
|
5460
|
+
* acorn 8's with the per-paren `DestructuringErrors` record pooled and the
|
|
5461
|
+
* expression list built in a scratch array. Non-lazy mode delegates (the
|
|
5462
|
+
* copy assumes ES6+, which `_lazy` guarantees via `ecmaVersion: "latest"`).
|
|
5463
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
5464
|
+
* @param {boolean} canBeArrow whether this may be an arrow head
|
|
5465
|
+
* @param {boolean | string} forInit for-init context flag
|
|
5466
|
+
* @returns {Expression} expression node
|
|
5467
|
+
* @this {ParserInternals}
|
|
5468
|
+
*/
|
|
5469
|
+
parseParenAndDistinguishExpression(canBeArrow, forInit) {
|
|
5470
|
+
if (!this._lazy || this._ecmaVersion < 6) {
|
|
5471
|
+
return base.parseParenAndDistinguishExpression.call(
|
|
5472
|
+
this,
|
|
5473
|
+
canBeArrow,
|
|
5474
|
+
forInit
|
|
5475
|
+
);
|
|
5476
|
+
}
|
|
5477
|
+
const startPos = this.start;
|
|
5478
|
+
const startLoc = this.startLoc;
|
|
5479
|
+
const allowTrailingComma = this._ecmaVersion >= 8;
|
|
5480
|
+
this.next();
|
|
5481
|
+
|
|
5482
|
+
const innerStartPos = this.start;
|
|
5483
|
+
const innerStartLoc = this.startLoc;
|
|
5484
|
+
const scratch = this._acquireScratch();
|
|
5485
|
+
let count = 0;
|
|
5486
|
+
let first = true;
|
|
5487
|
+
let lastIsComma = false;
|
|
5488
|
+
const refDestructuringErrors = this._acquireDestructuringErrors();
|
|
5489
|
+
const oldYieldPos = this.yieldPos;
|
|
5490
|
+
const oldAwaitPos = this.awaitPos;
|
|
5491
|
+
let spreadStart;
|
|
5492
|
+
this.yieldPos = 0;
|
|
5493
|
+
this.awaitPos = 0;
|
|
5494
|
+
// Do not save awaitIdentPos to allow checking awaits nested in parameters
|
|
5495
|
+
while (this.type !== tokTypes.parenR) {
|
|
5496
|
+
if (first) first = false;
|
|
5497
|
+
else this.expect(tokTypes.comma);
|
|
5498
|
+
if (
|
|
5499
|
+
allowTrailingComma &&
|
|
5500
|
+
this.afterTrailingComma(tokTypes.parenR, true)
|
|
5501
|
+
) {
|
|
5502
|
+
lastIsComma = true;
|
|
5503
|
+
break;
|
|
5504
|
+
} else if (this.type === tokTypes.ellipsis) {
|
|
5505
|
+
spreadStart = this.start;
|
|
5506
|
+
scratch[count++] = this.parseParenItem(this.parseRestBinding());
|
|
5507
|
+
if (this.type === tokTypes.comma) {
|
|
5508
|
+
this.raiseRecoverable(
|
|
5509
|
+
this.start,
|
|
5510
|
+
"Comma is not permitted after the rest element"
|
|
5511
|
+
);
|
|
5512
|
+
}
|
|
5513
|
+
break;
|
|
5514
|
+
} else {
|
|
5515
|
+
scratch[count++] = this.parseMaybeAssign(
|
|
5516
|
+
false,
|
|
5517
|
+
refDestructuringErrors,
|
|
5518
|
+
this.parseParenItem
|
|
5519
|
+
);
|
|
5520
|
+
}
|
|
5521
|
+
}
|
|
5522
|
+
const exprList = this._releaseScratch(scratch, count);
|
|
5523
|
+
const innerEndPos = this.lastTokEnd;
|
|
5524
|
+
this.expect(tokTypes.parenR);
|
|
5525
|
+
|
|
2908
5526
|
if (
|
|
2909
|
-
|
|
2910
|
-
this.
|
|
2911
|
-
|
|
5527
|
+
canBeArrow &&
|
|
5528
|
+
this.shouldParseArrow(exprList) &&
|
|
5529
|
+
this.eat(tokTypes.arrow)
|
|
2912
5530
|
) {
|
|
2913
|
-
|
|
5531
|
+
this.checkPatternErrors(refDestructuringErrors, false);
|
|
5532
|
+
this.checkYieldAwaitInDefaultParams();
|
|
5533
|
+
// last read of the pooled record was above, so the arrow body parse
|
|
5534
|
+
// below can already reuse its pool slot
|
|
5535
|
+
this._releaseDestructuringErrors();
|
|
5536
|
+
this.yieldPos = oldYieldPos;
|
|
5537
|
+
this.awaitPos = oldAwaitPos;
|
|
5538
|
+
return this.parseParenArrowList(startPos, startLoc, exprList, forInit);
|
|
2914
5539
|
}
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
this.
|
|
2920
|
-
this.
|
|
2921
|
-
|
|
5540
|
+
|
|
5541
|
+
if (exprList.length === 0 || lastIsComma) {
|
|
5542
|
+
this.unexpected(this.lastTokStart);
|
|
5543
|
+
}
|
|
5544
|
+
if (spreadStart) this.unexpected(spreadStart);
|
|
5545
|
+
this.checkExpressionErrors(refDestructuringErrors, true);
|
|
5546
|
+
this._releaseDestructuringErrors();
|
|
5547
|
+
this.yieldPos = oldYieldPos || this.yieldPos;
|
|
5548
|
+
this.awaitPos = oldAwaitPos || this.awaitPos;
|
|
5549
|
+
|
|
5550
|
+
/** @type {Expression} */
|
|
5551
|
+
let val;
|
|
5552
|
+
if (exprList.length > 1) {
|
|
5553
|
+
const seq = /** @type {Node & { expressions?: Expression[] }} */ (
|
|
5554
|
+
this.startNodeAt(innerStartPos, innerStartLoc)
|
|
5555
|
+
);
|
|
5556
|
+
seq.expressions = exprList;
|
|
5557
|
+
this.finishNodeAt(
|
|
5558
|
+
/** @type {Node} */ (seq),
|
|
5559
|
+
"SequenceExpression",
|
|
5560
|
+
innerEndPos,
|
|
5561
|
+
undefined
|
|
5562
|
+
);
|
|
5563
|
+
val = /** @type {Expression} */ (/** @type {unknown} */ (seq));
|
|
5564
|
+
} else {
|
|
5565
|
+
val = exprList[0];
|
|
5566
|
+
}
|
|
5567
|
+
|
|
5568
|
+
if (this.options.preserveParens) {
|
|
5569
|
+
const par = /** @type {Node & { expression?: Expression }} */ (
|
|
5570
|
+
this.startNodeAt(startPos, startLoc)
|
|
5571
|
+
);
|
|
5572
|
+
par.expression = val;
|
|
5573
|
+
return /** @type {Expression} */ (
|
|
5574
|
+
/** @type {unknown} */ (
|
|
5575
|
+
this.finishNode(/** @type {Node} */ (par), "ParenthesizedExpression")
|
|
5576
|
+
)
|
|
5577
|
+
);
|
|
5578
|
+
}
|
|
5579
|
+
return val;
|
|
2922
5580
|
}
|
|
2923
5581
|
|
|
2924
5582
|
/**
|
|
2925
|
-
* `
|
|
2926
|
-
*
|
|
2927
|
-
*
|
|
5583
|
+
* Owned `afterTrailingComma`, acorn's verbatim (mode-independent), so the
|
|
5584
|
+
* owned list parsers do not bounce through the dist for each element.
|
|
5585
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/parseutil.js
|
|
5586
|
+
* @param {TokenType} tokType closing token type
|
|
5587
|
+
* @param {boolean=} notNext whether to leave the closing token unconsumed
|
|
5588
|
+
* @returns {boolean} true when the list ended on a trailing comma
|
|
2928
5589
|
* @this {ParserInternals}
|
|
2929
5590
|
*/
|
|
2930
|
-
|
|
2931
|
-
if (
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
this.semicolon();
|
|
5591
|
+
afterTrailingComma(tokType, notNext) {
|
|
5592
|
+
if (this.type === tokType) {
|
|
5593
|
+
const onTrailingComma =
|
|
5594
|
+
/** @type {Options & { onTrailingComma?: (pos: number, loc?: Position) => void }} */
|
|
5595
|
+
(this.options).onTrailingComma;
|
|
5596
|
+
if (onTrailingComma) {
|
|
5597
|
+
onTrailingComma(this.lastTokStart, this.lastTokStartLoc);
|
|
5598
|
+
}
|
|
5599
|
+
if (!notNext) this.next();
|
|
5600
|
+
return true;
|
|
2941
5601
|
}
|
|
2942
|
-
return
|
|
2943
|
-
/** @type {unknown} */ (
|
|
2944
|
-
new ReturnStatementNode(start, this.lastTokEnd, argument)
|
|
2945
|
-
)
|
|
2946
|
-
);
|
|
5602
|
+
return false;
|
|
2947
5603
|
}
|
|
2948
5604
|
|
|
2949
5605
|
/**
|
|
2950
|
-
* Owned `
|
|
2951
|
-
*
|
|
2952
|
-
*
|
|
2953
|
-
* @
|
|
5606
|
+
* Owned `checkExpressionErrors`, acorn's verbatim (mode-independent): it
|
|
5607
|
+
* runs several times per expression from the owned spine.
|
|
5608
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/parseutil.js
|
|
5609
|
+
* @param {DestructuringErrorsShim | null=} refDestructuringErrors record to inspect
|
|
5610
|
+
* @param {boolean=} andThrow whether to throw on error
|
|
5611
|
+
* @returns {boolean} whether an error position was set
|
|
2954
5612
|
* @this {ParserInternals}
|
|
2955
5613
|
*/
|
|
2956
|
-
|
|
2957
|
-
if (!
|
|
2958
|
-
|
|
5614
|
+
checkExpressionErrors(refDestructuringErrors, andThrow) {
|
|
5615
|
+
if (!refDestructuringErrors) return false;
|
|
5616
|
+
const shorthandAssign = refDestructuringErrors.shorthandAssign;
|
|
5617
|
+
const doubleProto = refDestructuringErrors.doubleProto;
|
|
5618
|
+
if (!andThrow) return shorthandAssign >= 0 || doubleProto >= 0;
|
|
5619
|
+
if (shorthandAssign >= 0) {
|
|
5620
|
+
this.raise(
|
|
5621
|
+
shorthandAssign,
|
|
5622
|
+
"Shorthand property assignments are valid only in destructuring patterns"
|
|
5623
|
+
);
|
|
2959
5624
|
}
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
return
|
|
2964
|
-
/** @type {unknown} */ (
|
|
2965
|
-
new RestSpreadNode(start, this.lastTokEnd, "SpreadElement", argument)
|
|
2966
|
-
)
|
|
2967
|
-
);
|
|
5625
|
+
if (doubleProto >= 0) {
|
|
5626
|
+
this.raiseRecoverable(doubleProto, "Redefinition of __proto__ property");
|
|
5627
|
+
}
|
|
5628
|
+
return false;
|
|
2968
5629
|
}
|
|
2969
5630
|
|
|
2970
5631
|
/**
|
|
2971
|
-
* Owned `
|
|
2972
|
-
*
|
|
5632
|
+
* Owned `parseExpression`: acorn wraps every call in `catchStackOverflow`,
|
|
5633
|
+
* allocating a fresh closure per expression; inline the try/catch instead
|
|
5634
|
+
* (same overflow-message translation, no closure). Non-lazy mode delegates.
|
|
5635
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
2973
5636
|
* @param {boolean | string=} forInit for-init context flag
|
|
2974
5637
|
* @param {DestructuringErrorsShim | null=} refDestructuringErrors destructuring errors to fill
|
|
2975
5638
|
* @returns {Expression} expression node
|
|
2976
5639
|
* @this {ParserInternals}
|
|
2977
5640
|
*/
|
|
2978
|
-
|
|
5641
|
+
parseExpression(forInit, refDestructuringErrors) {
|
|
2979
5642
|
if (!this._lazy) {
|
|
2980
|
-
return base.
|
|
2981
|
-
this,
|
|
2982
|
-
forInit,
|
|
2983
|
-
refDestructuringErrors
|
|
2984
|
-
);
|
|
5643
|
+
return base.parseExpression.call(this, forInit, refDestructuringErrors);
|
|
2985
5644
|
}
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
5645
|
+
try {
|
|
5646
|
+
const startPos = this.start;
|
|
5647
|
+
const startLoc = this.startLoc;
|
|
5648
|
+
const expr = this.parseMaybeAssign(forInit, refDestructuringErrors);
|
|
5649
|
+
if (this.type === tokTypes.comma) {
|
|
5650
|
+
const node =
|
|
5651
|
+
/** @type {Node & { expressions?: Expression[] }} */
|
|
5652
|
+
(this.startNodeAt(startPos, startLoc));
|
|
5653
|
+
node.expressions = [expr];
|
|
5654
|
+
while (this.eat(tokTypes.comma)) {
|
|
5655
|
+
node.expressions.push(
|
|
5656
|
+
this.parseMaybeAssign(forInit, refDestructuringErrors)
|
|
5657
|
+
);
|
|
5658
|
+
}
|
|
5659
|
+
return /** @type {Expression} */ (
|
|
5660
|
+
/** @type {unknown} */ (this.finishNode(node, "SequenceExpression"))
|
|
5661
|
+
);
|
|
5662
|
+
}
|
|
5663
|
+
return expr;
|
|
5664
|
+
} catch (err) {
|
|
5665
|
+
// acorn's catchStackOverflow: translate an engine stack-overflow error
|
|
5666
|
+
if (
|
|
5667
|
+
err instanceof Error &&
|
|
5668
|
+
(/\bstack\b.*\b(exceeded|overflow)\b/i.test(err.message) ||
|
|
5669
|
+
/\btoo much recursion\b/i.test(err.message))
|
|
5670
|
+
) {
|
|
5671
|
+
this.raise(this.start, "Not enough stack space to parse input");
|
|
5672
|
+
}
|
|
5673
|
+
throw err;
|
|
3007
5674
|
}
|
|
3008
|
-
return expr;
|
|
3009
5675
|
}
|
|
3010
5676
|
|
|
3011
5677
|
/**
|
|
@@ -3013,6 +5679,7 @@ class WebpackParser extends BaseParser {
|
|
|
3013
5679
|
* lands on `NewExpressionNode`'s single shape (zero-argument calls share
|
|
3014
5680
|
* one empty array like acorn's `empty`); the rare `new.target` path keeps
|
|
3015
5681
|
* the generic node. Non-lazy mode delegates.
|
|
5682
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
3016
5683
|
* @returns {Expression} new expression or meta property
|
|
3017
5684
|
* @this {ParserInternals}
|
|
3018
5685
|
*/
|
|
@@ -3084,6 +5751,7 @@ class WebpackParser extends BaseParser {
|
|
|
3084
5751
|
* Owned `parseTemplateElement` landing on `TemplateElementNode`'s single
|
|
3085
5752
|
* shape; matches acorn's CRLF normalization and invalid-escape handling.
|
|
3086
5753
|
* Non-lazy mode delegates.
|
|
5754
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
3087
5755
|
* @param {{ isTagged: boolean }} opts whether the template is tagged
|
|
3088
5756
|
* @returns {Node} template element
|
|
3089
5757
|
* @this {ParserInternals}
|
|
@@ -3134,6 +5802,7 @@ class WebpackParser extends BaseParser {
|
|
|
3134
5802
|
/**
|
|
3135
5803
|
* Owned `parseTemplate` landing on `TemplateLiteralNode`'s single shape.
|
|
3136
5804
|
* Non-lazy mode delegates.
|
|
5805
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
3137
5806
|
* @param {{ isTagged?: boolean }=} opts whether the template is tagged
|
|
3138
5807
|
* @returns {Node} template literal
|
|
3139
5808
|
* @this {ParserInternals}
|
|
@@ -3148,27 +5817,31 @@ class WebpackParser extends BaseParser {
|
|
|
3148
5817
|
const isTagged = (opts !== undefined && opts.isTagged) === true;
|
|
3149
5818
|
const start = this.start;
|
|
3150
5819
|
this.next();
|
|
3151
|
-
|
|
3152
|
-
const
|
|
5820
|
+
const exprScratch = this._acquireScratch();
|
|
5821
|
+
const quasiScratch = this._acquireScratch();
|
|
5822
|
+
let exprCount = 0;
|
|
5823
|
+
let quasiCount = 0;
|
|
3153
5824
|
// one options object for all chunks (only `isTagged` is ever read)
|
|
3154
5825
|
const eltOpts = { isTagged };
|
|
3155
5826
|
let curElt = /** @type {Node & { tail?: boolean }} */ (
|
|
3156
5827
|
this.parseTemplateElement(eltOpts)
|
|
3157
5828
|
);
|
|
3158
|
-
|
|
5829
|
+
quasiScratch[quasiCount++] = curElt;
|
|
3159
5830
|
while (!curElt.tail) {
|
|
3160
5831
|
if (this.type === tokTypes.eof) {
|
|
3161
5832
|
this.raise(this.pos, "Unterminated template literal");
|
|
3162
5833
|
}
|
|
3163
5834
|
this.expect(tokTypes.dollarBraceL);
|
|
3164
|
-
|
|
5835
|
+
exprScratch[exprCount++] = this.parseExpression();
|
|
3165
5836
|
this.expect(tokTypes.braceR);
|
|
3166
5837
|
curElt = /** @type {Node & { tail?: boolean }} */ (
|
|
3167
5838
|
this.parseTemplateElement(eltOpts)
|
|
3168
5839
|
);
|
|
3169
|
-
|
|
5840
|
+
quasiScratch[quasiCount++] = curElt;
|
|
3170
5841
|
}
|
|
3171
5842
|
this.next();
|
|
5843
|
+
const quasis = this._releaseScratch(quasiScratch, quasiCount);
|
|
5844
|
+
const expressions = this._releaseScratch(exprScratch, exprCount);
|
|
3172
5845
|
return /** @type {Node} */ (
|
|
3173
5846
|
/** @type {unknown} */ (
|
|
3174
5847
|
new TemplateLiteralNode(start, this.lastTokEnd, expressions, quasis)
|
|
@@ -3180,6 +5853,7 @@ class WebpackParser extends BaseParser {
|
|
|
3180
5853
|
* Owned `parseMaybeUnary`, an exact-semantics copy of acorn 8's: prefix
|
|
3181
5854
|
* unary/update and postfix update nodes are built fully-formed on
|
|
3182
5855
|
* `UnaryNode`'s shared single shape. Non-lazy mode delegates to acorn.
|
|
5856
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
3183
5857
|
* @param {DestructuringErrorsShim | null} refDestructuringErrors destructuring errors to fill
|
|
3184
5858
|
* @param {boolean} sawUnary whether a unary operator was already consumed
|
|
3185
5859
|
* @param {boolean} incDec whether the caller was an update operator
|
|
@@ -3292,11 +5966,63 @@ class WebpackParser extends BaseParser {
|
|
|
3292
5966
|
return expr;
|
|
3293
5967
|
}
|
|
3294
5968
|
|
|
5969
|
+
/**
|
|
5970
|
+
* Collapses the commonest expression shape — a name/number/string/keyword
|
|
5971
|
+
* literal or `this` whose next source character can only begin a token that
|
|
5972
|
+
* cannot continue an expression — into the atom, skipping the seven-layer
|
|
5973
|
+
* `parseMaybeAssign` → `parseExprAtom` descent and its destructuring-error
|
|
5974
|
+
* bookkeeping (which is a net no-op for a bare atom).
|
|
5975
|
+
* @param {boolean | string=} forInit for-init context flag
|
|
5976
|
+
* @returns {Expression | null} the atom, or `null` when the shape does not apply
|
|
5977
|
+
* @this {ParserInternals}
|
|
5978
|
+
*/
|
|
5979
|
+
_parseTrivialAtom(forInit) {
|
|
5980
|
+
const code = this.input.charCodeAt(this.end);
|
|
5981
|
+
if (code >= 128 || EXPRESSION_END_CHAR[code] !== 1) return null;
|
|
5982
|
+
const type = this.type;
|
|
5983
|
+
if (type === tokTypes.name) {
|
|
5984
|
+
// both steer the chain themselves (`yield x`, `await x`)
|
|
5985
|
+
const name = /** @type {string} */ (this.value);
|
|
5986
|
+
if (name === "yield" || name === "await") return null;
|
|
5987
|
+
this.potentialArrowAt = this.start;
|
|
5988
|
+
this.potentialArrowInForAwait = forInit === "await";
|
|
5989
|
+
return /** @type {Expression} */ (
|
|
5990
|
+
/** @type {unknown} */ (this.parseIdent(false))
|
|
5991
|
+
);
|
|
5992
|
+
}
|
|
5993
|
+
if (type === tokTypes.num || type === tokTypes.string) {
|
|
5994
|
+
return /** @type {Expression} */ (
|
|
5995
|
+
/** @type {unknown} */ (this.parseLiteral(this.value))
|
|
5996
|
+
);
|
|
5997
|
+
}
|
|
5998
|
+
if (type === tokTypes._this) {
|
|
5999
|
+
const node = new ThisNode(this.start, this.end);
|
|
6000
|
+
this.next();
|
|
6001
|
+
return /** @type {Expression} */ (/** @type {unknown} */ (node));
|
|
6002
|
+
}
|
|
6003
|
+
if (
|
|
6004
|
+
type === tokTypes._null ||
|
|
6005
|
+
type === tokTypes._true ||
|
|
6006
|
+
type === tokTypes._false
|
|
6007
|
+
) {
|
|
6008
|
+
const node = new LiteralNode(
|
|
6009
|
+
this.start,
|
|
6010
|
+
this.end,
|
|
6011
|
+
type === tokTypes._null ? null : type === tokTypes._true,
|
|
6012
|
+
/** @type {string} */ (type.keyword)
|
|
6013
|
+
);
|
|
6014
|
+
this.next();
|
|
6015
|
+
return /** @type {Expression} */ (/** @type {unknown} */ (node));
|
|
6016
|
+
}
|
|
6017
|
+
return null;
|
|
6018
|
+
}
|
|
6019
|
+
|
|
3295
6020
|
/**
|
|
3296
6021
|
* Owned `parseMaybeAssign`, an exact-semantics copy of acorn 8's: the
|
|
3297
6022
|
* operator is captured before `next()` and the `AssignmentExpression` is
|
|
3298
6023
|
* built fully-formed on `AssignmentNode`'s single shape after the
|
|
3299
6024
|
* right-hand parse. Yield and non-lazy mode delegate to acorn.
|
|
6025
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
3300
6026
|
* @param {boolean | string=} forInit for-init context flag
|
|
3301
6027
|
* @param {DestructuringErrorsShim | null=} refDestructuringErrors destructuring errors to fill
|
|
3302
6028
|
* @param {((this: unknown, left: Expression, startPos: number, startLoc?: Position) => Expression)=} afterLeftParse hook applied to the parsed left side
|
|
@@ -3312,6 +6038,10 @@ class WebpackParser extends BaseParser {
|
|
|
3312
6038
|
afterLeftParse
|
|
3313
6039
|
);
|
|
3314
6040
|
}
|
|
6041
|
+
if (this._exprFastPath && afterLeftParse === undefined) {
|
|
6042
|
+
const atom = this._parseTrivialAtom(forInit);
|
|
6043
|
+
if (atom !== null) return atom;
|
|
6044
|
+
}
|
|
3315
6045
|
if (this.isContextual("yield")) {
|
|
3316
6046
|
if (this.inGenerator) return this.parseYield(forInit);
|
|
3317
6047
|
// the tokenizer assumed an expression follows `yield`, but this
|
|
@@ -3393,6 +6123,7 @@ class WebpackParser extends BaseParser {
|
|
|
3393
6123
|
* Owned `parseExprOps`, an exact copy of acorn 8's, so the hot expression
|
|
3394
6124
|
* spine (`parseMaybeAssign` → here → `parseMaybeUnary`) stays monomorphic
|
|
3395
6125
|
* on owned code. Non-lazy mode delegates.
|
|
6126
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
3396
6127
|
* @param {boolean | string=} forInit for-init context flag
|
|
3397
6128
|
* @param {DestructuringErrorsShim | null=} refDestructuringErrors destructuring errors to fill
|
|
3398
6129
|
* @returns {Expression} expression node
|
|
@@ -3411,7 +6142,10 @@ class WebpackParser extends BaseParser {
|
|
|
3411
6142
|
forInit
|
|
3412
6143
|
);
|
|
3413
6144
|
if (this.checkExpressionErrors(refDestructuringErrors)) return expr;
|
|
3414
|
-
|
|
6145
|
+
const isArrow = this._arrowFastPath
|
|
6146
|
+
? expr === this._lastArrow && expr.start === startPos
|
|
6147
|
+
: expr.start === startPos && expr.type === "ArrowFunctionExpression";
|
|
6148
|
+
return isArrow
|
|
3415
6149
|
? expr
|
|
3416
6150
|
: this.parseExprOp(expr, startPos, startLoc, -1, forInit);
|
|
3417
6151
|
}
|
|
@@ -3421,6 +6155,7 @@ class WebpackParser extends BaseParser {
|
|
|
3421
6155
|
* same-precedence continuation turned from tail recursion into a loop —
|
|
3422
6156
|
* `a + b + c + d` runs one frame instead of one per operator. Non-lazy mode
|
|
3423
6157
|
* delegates.
|
|
6158
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
3424
6159
|
* @param {Expression} left left operand
|
|
3425
6160
|
* @param {number} leftStartPos expression start offset
|
|
3426
6161
|
* @param {Position | undefined} leftStartLoc expression start position
|
|
@@ -3497,6 +6232,7 @@ class WebpackParser extends BaseParser {
|
|
|
3497
6232
|
* Owned `buildBinary` (acorn calls it only from `parseExprOp`): binary and
|
|
3498
6233
|
* logical nodes are built fully-formed on `BinaryNode`'s single shape.
|
|
3499
6234
|
* Non-lazy mode delegates to acorn.
|
|
6235
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
3500
6236
|
* @param {number} startPos expression start offset
|
|
3501
6237
|
* @param {Position | undefined} startLoc expression start position
|
|
3502
6238
|
* @param {Expression} left left operand
|
|
@@ -3544,6 +6280,7 @@ class WebpackParser extends BaseParser {
|
|
|
3544
6280
|
* async-function/async-arrow detection), number/string literals, keyword
|
|
3545
6281
|
* literals (`true`/`false`/`null` — on the same `LiteralNode` shape as the
|
|
3546
6282
|
* rest) and `this`. Everything else, and non-lazy mode, delegates to acorn.
|
|
6283
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
3547
6284
|
* @param {DestructuringErrorsShim | null=} refDestructuringErrors destructuring errors to fill
|
|
3548
6285
|
* @param {boolean | string=} forInit for-init context flag
|
|
3549
6286
|
* @param {boolean=} forNew whether parsed as a `new` callee
|
|
@@ -3670,6 +6407,7 @@ class WebpackParser extends BaseParser {
|
|
|
3670
6407
|
* Owned `parseObj`, an exact-semantics copy of acorn 8's landing on
|
|
3671
6408
|
* `ObjectNode`'s single shape (the ES5 trailing-comma gate is dropped —
|
|
3672
6409
|
* the fast path requires ES11+). Non-lazy mode delegates.
|
|
6410
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
3673
6411
|
* @param {boolean} isPattern whether parsing a binding pattern
|
|
3674
6412
|
* @param {DestructuringErrorsShim | null=} refDestructuringErrors destructuring errors to fill
|
|
3675
6413
|
* @returns {Node} object expression or pattern
|
|
@@ -3701,8 +6439,8 @@ class WebpackParser extends BaseParser {
|
|
|
3701
6439
|
} else {
|
|
3702
6440
|
propHash = {};
|
|
3703
6441
|
}
|
|
3704
|
-
|
|
3705
|
-
|
|
6442
|
+
const scratch = this._acquireScratch();
|
|
6443
|
+
let count = 0;
|
|
3706
6444
|
this.next();
|
|
3707
6445
|
while (!this.eat(tokTypes.braceR)) {
|
|
3708
6446
|
if (!first) {
|
|
@@ -3715,7 +6453,7 @@ class WebpackParser extends BaseParser {
|
|
|
3715
6453
|
if (!isPattern) {
|
|
3716
6454
|
this.checkPropClash(prop, propHash, refDestructuringErrors);
|
|
3717
6455
|
}
|
|
3718
|
-
|
|
6456
|
+
scratch[count++] = prop;
|
|
3719
6457
|
}
|
|
3720
6458
|
if (pooled) this._propHashDepth--;
|
|
3721
6459
|
return /** @type {Node} */ (
|
|
@@ -3724,7 +6462,7 @@ class WebpackParser extends BaseParser {
|
|
|
3724
6462
|
start,
|
|
3725
6463
|
this.lastTokEnd,
|
|
3726
6464
|
isPattern ? "ObjectPattern" : "ObjectExpression",
|
|
3727
|
-
|
|
6465
|
+
this._releaseScratch(scratch, count)
|
|
3728
6466
|
)
|
|
3729
6467
|
)
|
|
3730
6468
|
);
|
|
@@ -3736,6 +6474,7 @@ class WebpackParser extends BaseParser {
|
|
|
3736
6474
|
* `PropertyNode`, which acorn's shared `parsePropertyName`/
|
|
3737
6475
|
* `parsePropertyValue` then fill in place (ES9+ semantics assumed via the
|
|
3738
6476
|
* ES11 fast-path gate). Non-lazy mode delegates.
|
|
6477
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
3739
6478
|
* @param {boolean} isPattern whether parsing a binding pattern
|
|
3740
6479
|
* @param {DestructuringErrorsShim | null=} refDestructuringErrors destructuring errors to fill
|
|
3741
6480
|
* @returns {Node} property, spread element or rest element
|
|
@@ -3829,6 +6568,7 @@ class WebpackParser extends BaseParser {
|
|
|
3829
6568
|
/**
|
|
3830
6569
|
* Owned `parseLiteral`: builds the finished `LiteralNode` directly; the
|
|
3831
6570
|
* `bigint` branch matches acorn's. Non-lazy mode delegates to acorn.
|
|
6571
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
3832
6572
|
* @param {unknown} value literal value
|
|
3833
6573
|
* @returns {Node} literal node
|
|
3834
6574
|
* @this {ParserInternals}
|
|
@@ -3854,6 +6594,7 @@ class WebpackParser extends BaseParser {
|
|
|
3854
6594
|
* then builds the value with a second `new RegExp`. This override scans
|
|
3855
6595
|
* like acorn, keeps acorn's flag validation (for its exact messages) and
|
|
3856
6596
|
* lets one `new RegExp` be both the V8-backed validation and the value.
|
|
6597
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
|
|
3857
6598
|
* @this {ParserInternals & { regexpState: unknown }}
|
|
3858
6599
|
* @returns {void}
|
|
3859
6600
|
*/
|
|
@@ -3926,6 +6667,7 @@ class WebpackParser extends BaseParser {
|
|
|
3926
6667
|
* that validation costs several percent of parse time. Raise from V8's
|
|
3927
6668
|
* verdict instead — invalid patterns still fail the module build, only
|
|
3928
6669
|
* exotic engine-specific message texts may differ.
|
|
6670
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/regexp.js
|
|
3929
6671
|
* @param {{ start: number, source: string, flags: string }} state acorn regexp validation state
|
|
3930
6672
|
* @this {ParserInternals}
|
|
3931
6673
|
*/
|
|
@@ -3941,6 +6683,7 @@ class WebpackParser extends BaseParser {
|
|
|
3941
6683
|
// ----- scope tracking (Set-based, replaces acorn's array + indexOf) -----
|
|
3942
6684
|
|
|
3943
6685
|
/**
|
|
6686
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/scope.js
|
|
3944
6687
|
* @param {number} flags scope flags
|
|
3945
6688
|
* @this {ParserInternals}
|
|
3946
6689
|
*/
|
|
@@ -3950,6 +6693,7 @@ class WebpackParser extends BaseParser {
|
|
|
3950
6693
|
|
|
3951
6694
|
/**
|
|
3952
6695
|
* Set-backed replacement for acorn's `declareName` on Set-backed scopes.
|
|
6696
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/scope.js
|
|
3953
6697
|
* @param {string} name declared name
|
|
3954
6698
|
* @param {number} bindingType acorn BIND_* binding type
|
|
3955
6699
|
* @param {number} pos source offset for redeclaration errors
|
|
@@ -4020,6 +6764,7 @@ class WebpackParser extends BaseParser {
|
|
|
4020
6764
|
|
|
4021
6765
|
/**
|
|
4022
6766
|
* Set-backed replacement for acorn's `checkLocalExport` on Set-backed scopes.
|
|
6767
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/scope.js
|
|
4023
6768
|
* @param {Identifier} id exported identifier
|
|
4024
6769
|
* @this {ParserInternals}
|
|
4025
6770
|
*/
|
|
@@ -4095,6 +6840,7 @@ class WebpackParser extends BaseParser {
|
|
|
4095
6840
|
// ----- import phases (`import defer/source`, `import.defer/source()`) -----
|
|
4096
6841
|
|
|
4097
6842
|
/**
|
|
6843
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
4098
6844
|
* @param {Node & { phase?: ImportPhase }} node import declaration node
|
|
4099
6845
|
* @returns {Node} finished node
|
|
4100
6846
|
* @this {ParserInternals}
|
|
@@ -4110,6 +6856,7 @@ class WebpackParser extends BaseParser {
|
|
|
4110
6856
|
/**
|
|
4111
6857
|
* Owned `parseExport` only to flag module syntax for the auto-fallback guard;
|
|
4112
6858
|
* parsing itself delegates to acorn.
|
|
6859
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
4113
6860
|
* @param {Node} node started export node
|
|
4114
6861
|
* @param {unknown} exports export-name tracking object
|
|
4115
6862
|
* @returns {Node} export declaration
|
|
@@ -4123,6 +6870,7 @@ class WebpackParser extends BaseParser {
|
|
|
4123
6870
|
/**
|
|
4124
6871
|
* Owned `parseAwait` only to flag top-level await (module-only) for the
|
|
4125
6872
|
* auto-fallback guard; await inside a function is not module syntax.
|
|
6873
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
4126
6874
|
* @param {boolean | string=} forInit for-loop init context flag
|
|
4127
6875
|
* @returns {Expression} await expression
|
|
4128
6876
|
* @this {ParserInternals}
|
|
@@ -4135,6 +6883,7 @@ class WebpackParser extends BaseParser {
|
|
|
4135
6883
|
}
|
|
4136
6884
|
|
|
4137
6885
|
/**
|
|
6886
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
|
|
4138
6887
|
* @returns {AnyImportSpecifier[]} import specifiers
|
|
4139
6888
|
* @this {ParserInternals}
|
|
4140
6889
|
*/
|
|
@@ -4211,6 +6960,7 @@ class WebpackParser extends BaseParser {
|
|
|
4211
6960
|
}
|
|
4212
6961
|
|
|
4213
6962
|
/**
|
|
6963
|
+
* acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
|
|
4214
6964
|
* @param {boolean} forNew whether parsed as the operand of `new`
|
|
4215
6965
|
* @returns {Expression} expression node
|
|
4216
6966
|
* @this {ParserInternals}
|
|
@@ -4299,7 +7049,7 @@ class WebpackParser extends BaseParser {
|
|
|
4299
7049
|
}
|
|
4300
7050
|
}
|
|
4301
7051
|
|
|
4302
|
-
/** @
|
|
7052
|
+
/** @import { SourcePosition } from "../Dependency" */
|
|
4303
7053
|
|
|
4304
7054
|
/**
|
|
4305
7055
|
* Whether a raw string literal contains a legacy octal (`\47`, `\0` followed by
|
|
@@ -4333,13 +7083,13 @@ const hasOctalEscape = (raw) => {
|
|
|
4333
7083
|
// these two helpers.
|
|
4334
7084
|
|
|
4335
7085
|
/**
|
|
4336
|
-
*
|
|
4337
|
-
*
|
|
4338
|
-
*
|
|
7086
|
+
* Exact char-code scan matching acorn's `lineBreak` semantics (CRLF is one
|
|
7087
|
+
* break). Kept as the fallback for the terminators `buildLineStarts` cannot
|
|
7088
|
+
* find with a native search.
|
|
4339
7089
|
* @param {string} source source code
|
|
4340
7090
|
* @returns {number[]} line start offsets
|
|
4341
7091
|
*/
|
|
4342
|
-
const
|
|
7092
|
+
const scanLineStarts = (source) => {
|
|
4343
7093
|
const len = source.length;
|
|
4344
7094
|
const lineStarts = [0];
|
|
4345
7095
|
for (let i = 0; i < len; i++) {
|
|
@@ -4356,6 +7106,33 @@ const buildLineStarts = (source) => {
|
|
|
4356
7106
|
return lineStarts;
|
|
4357
7107
|
};
|
|
4358
7108
|
|
|
7109
|
+
/**
|
|
7110
|
+
* Offset of each line's first character. `indexOf` searches the source natively,
|
|
7111
|
+
* which beats a char-code loop by ~3x; CRLF needs no special case because it
|
|
7112
|
+
* starts the next line after its `\n` either way. A lone `\r` or a unicode
|
|
7113
|
+
* separator does break that equivalence, so those fall back to the char scan.
|
|
7114
|
+
* @param {string} source source code
|
|
7115
|
+
* @returns {number[]} line start offsets
|
|
7116
|
+
*/
|
|
7117
|
+
const buildLineStarts = (source) => {
|
|
7118
|
+
if (!source.includes("\u2028") && !source.includes("\u2029")) {
|
|
7119
|
+
let cr = source.indexOf("\r");
|
|
7120
|
+
while (cr !== -1 && source.charCodeAt(cr + 1) === 10) {
|
|
7121
|
+
cr = source.indexOf("\r", cr + 2);
|
|
7122
|
+
}
|
|
7123
|
+
if (cr === -1) {
|
|
7124
|
+
const lineStarts = [0];
|
|
7125
|
+
let i = source.indexOf("\n");
|
|
7126
|
+
while (i !== -1) {
|
|
7127
|
+
lineStarts.push(i + 1);
|
|
7128
|
+
i = source.indexOf("\n", i + 1);
|
|
7129
|
+
}
|
|
7130
|
+
return lineStarts;
|
|
7131
|
+
}
|
|
7132
|
+
}
|
|
7133
|
+
return scanLineStarts(source);
|
|
7134
|
+
};
|
|
7135
|
+
|
|
4359
7136
|
/**
|
|
4360
7137
|
* Binary search for the line containing the offset.
|
|
4361
7138
|
* @param {number[]} lineStarts line start offsets
|
|
@@ -4373,8 +7150,334 @@ const positionAt = (lineStarts, offset) => {
|
|
|
4373
7150
|
return { line: lo + 1, column: offset - lineStarts[lo] };
|
|
4374
7151
|
};
|
|
4375
7152
|
|
|
7153
|
+
const KEYWORDS_BEFORE_REGEXP = new Set([
|
|
7154
|
+
"await",
|
|
7155
|
+
"case",
|
|
7156
|
+
"delete",
|
|
7157
|
+
"do",
|
|
7158
|
+
"else",
|
|
7159
|
+
"in",
|
|
7160
|
+
"instanceof",
|
|
7161
|
+
"new",
|
|
7162
|
+
"of",
|
|
7163
|
+
"return",
|
|
7164
|
+
"throw",
|
|
7165
|
+
"typeof",
|
|
7166
|
+
"void",
|
|
7167
|
+
"yield"
|
|
7168
|
+
]);
|
|
7169
|
+
|
|
7170
|
+
/**
|
|
7171
|
+
* Whether a `/` at this point starts a regexp rather than division, decided by
|
|
7172
|
+
* what precedes it: after a value (name, number, `)`, `]`) it divides, after an
|
|
7173
|
+
* operator or a keyword it opens a regexp. `)` and `]` are always read as
|
|
7174
|
+
* division — telling `if (a) /re/` from `(a) / b` needs paren-context tracking
|
|
7175
|
+
* this single pass does not carry.
|
|
7176
|
+
* @param {string} source source code
|
|
7177
|
+
* @param {number} slash offset of the `/`
|
|
7178
|
+
* @returns {boolean} true when a regexp literal starts here
|
|
7179
|
+
*/
|
|
7180
|
+
const startsRegExp = (source, slash) => {
|
|
7181
|
+
let i = slash - 1;
|
|
7182
|
+
while (i >= 0) {
|
|
7183
|
+
const code = source.charCodeAt(i);
|
|
7184
|
+
if (code === 32 || code === 9 || code === 10 || code === 13) i--;
|
|
7185
|
+
else break;
|
|
7186
|
+
}
|
|
7187
|
+
if (i < 0) return true;
|
|
7188
|
+
const code = source.charCodeAt(i);
|
|
7189
|
+
if (code === 41 || code === 93) return false;
|
|
7190
|
+
if (!isIdentifierChar(code)) return true;
|
|
7191
|
+
// a keyword before `/` is an operator position (`return /re/`), a name is not
|
|
7192
|
+
let start = i;
|
|
7193
|
+
while (start >= 0 && isIdentifierChar(source.charCodeAt(start))) start--;
|
|
7194
|
+
return KEYWORDS_BEFORE_REGEXP.has(source.slice(start + 1, i + 1));
|
|
7195
|
+
};
|
|
7196
|
+
|
|
7197
|
+
/**
|
|
7198
|
+
* Skips whitespace and comments, returning the next code offset.
|
|
7199
|
+
* @param {string} source source code
|
|
7200
|
+
* @param {number} i offset to start at
|
|
7201
|
+
* @returns {number} offset of the next significant character
|
|
7202
|
+
*/
|
|
7203
|
+
const skipTrivia = (source, i) => {
|
|
7204
|
+
while (i < source.length) {
|
|
7205
|
+
const code = source.charCodeAt(i);
|
|
7206
|
+
if (code === 32 || code === 9 || code === 10 || code === 13) {
|
|
7207
|
+
i++;
|
|
7208
|
+
} else if (code === 47 && source.charCodeAt(i + 1) === 47) {
|
|
7209
|
+
const end = source.indexOf("\n", i + 2);
|
|
7210
|
+
i = end === -1 ? source.length : end + 1;
|
|
7211
|
+
} else if (code === 47 && source.charCodeAt(i + 1) === 42) {
|
|
7212
|
+
const end = source.indexOf("*/", i + 2);
|
|
7213
|
+
i = end === -1 ? source.length : end + 2;
|
|
7214
|
+
} else {
|
|
7215
|
+
break;
|
|
7216
|
+
}
|
|
7217
|
+
}
|
|
7218
|
+
return i;
|
|
7219
|
+
};
|
|
7220
|
+
|
|
7221
|
+
/** @type {Map<number, string>} */
|
|
7222
|
+
const SINGLE_CHARACTER_ESCAPES = new Map([
|
|
7223
|
+
[110, "\n"],
|
|
7224
|
+
[114, "\r"],
|
|
7225
|
+
[116, "\t"],
|
|
7226
|
+
[98, "\b"],
|
|
7227
|
+
[118, "\u000B"],
|
|
7228
|
+
[102, "\f"]
|
|
7229
|
+
]);
|
|
7230
|
+
|
|
7231
|
+
/**
|
|
7232
|
+
* Reads the hex digits of a `\x`/`\u` escape.
|
|
7233
|
+
* @param {string} source source code
|
|
7234
|
+
* @param {number} i offset of the first digit
|
|
7235
|
+
* @param {number} length how many digits to read
|
|
7236
|
+
* @returns {number} the code point, or `-1` when a digit is missing
|
|
7237
|
+
*/
|
|
7238
|
+
const readHexEscapeValue = (source, i, length) => {
|
|
7239
|
+
let value = 0;
|
|
7240
|
+
for (let j = i; j < i + length; j++) {
|
|
7241
|
+
const digit = Number.parseInt(source[j], 16);
|
|
7242
|
+
if (Number.isNaN(digit)) return -1;
|
|
7243
|
+
value = value * 16 + digit;
|
|
7244
|
+
}
|
|
7245
|
+
return value;
|
|
7246
|
+
};
|
|
7247
|
+
|
|
7248
|
+
/**
|
|
7249
|
+
* Cooks one escape sequence, sloppy-mode script semantics (legacy octal included).
|
|
7250
|
+
* @param {string} source source code
|
|
7251
|
+
* @param {number} i offset just past the backslash
|
|
7252
|
+
* @returns {{ value: string, end: number } | undefined} the cooked text, or `undefined` when malformed
|
|
7253
|
+
*/
|
|
7254
|
+
const readEscape = (source, i) => {
|
|
7255
|
+
if (i >= source.length) return;
|
|
7256
|
+
const code = source.charCodeAt(i);
|
|
7257
|
+
const single = SINGLE_CHARACTER_ESCAPES.get(code);
|
|
7258
|
+
if (single !== undefined) return { value: single, end: i + 1 };
|
|
7259
|
+
// a line continuation cooks to nothing; `\r\n` counts as one terminator
|
|
7260
|
+
if (code === 13) {
|
|
7261
|
+
return { value: "", end: source.charCodeAt(i + 1) === 10 ? i + 2 : i + 1 };
|
|
7262
|
+
}
|
|
7263
|
+
if (code === 10 || code === 0x2028 || code === 0x2029) {
|
|
7264
|
+
return { value: "", end: i + 1 };
|
|
7265
|
+
}
|
|
7266
|
+
if (code === 120) {
|
|
7267
|
+
const value = readHexEscapeValue(source, i + 1, 2);
|
|
7268
|
+
if (value === -1) return;
|
|
7269
|
+
return { value: String.fromCodePoint(value), end: i + 3 };
|
|
7270
|
+
}
|
|
7271
|
+
if (code === 117) {
|
|
7272
|
+
if (source.charCodeAt(i + 1) === 123) {
|
|
7273
|
+
const end = source.indexOf("}", i + 2);
|
|
7274
|
+
if (end === -1 || end === i + 2) return;
|
|
7275
|
+
const value = readHexEscapeValue(source, i + 2, end - i - 2);
|
|
7276
|
+
if (value === -1 || value > 0x10ffff) return;
|
|
7277
|
+
return { value: String.fromCodePoint(value), end: end + 1 };
|
|
7278
|
+
}
|
|
7279
|
+
const value = readHexEscapeValue(source, i + 1, 4);
|
|
7280
|
+
if (value === -1) return;
|
|
7281
|
+
return { value: String.fromCodePoint(value), end: i + 5 };
|
|
7282
|
+
}
|
|
7283
|
+
if (code >= 48 && code <= 55) {
|
|
7284
|
+
let digits = /** @type {RegExpMatchArray} */ (
|
|
7285
|
+
source.slice(i, i + 3).match(/^[0-7]+/)
|
|
7286
|
+
)[0];
|
|
7287
|
+
if (Number.parseInt(digits, 8) > 255) digits = digits.slice(0, -1);
|
|
7288
|
+
return {
|
|
7289
|
+
value: String.fromCharCode(Number.parseInt(digits, 8)),
|
|
7290
|
+
end: i + digits.length
|
|
7291
|
+
};
|
|
7292
|
+
}
|
|
7293
|
+
return { value: source[i], end: i + 1 };
|
|
7294
|
+
};
|
|
7295
|
+
|
|
7296
|
+
/**
|
|
7297
|
+
* Reads a `'`/`"` string starting at `i`, cooking its escapes the way the ast
|
|
7298
|
+
* this replaces did — a `Literal` node carries the cooked value, so a specifier
|
|
7299
|
+
* written `"\x2e/a"` is the same dependency as `"./a"`. Templates are not
|
|
7300
|
+
* specifiers here: the ast only matched `Literal` nodes.
|
|
7301
|
+
* @param {string} source source code
|
|
7302
|
+
* @param {number} i offset of the opening quote
|
|
7303
|
+
* @returns {{ value: string, end: number } | undefined} the literal
|
|
7304
|
+
*/
|
|
7305
|
+
const readStringLiteral = (source, i) => {
|
|
7306
|
+
const quote = source.charCodeAt(i);
|
|
7307
|
+
if (quote !== 34 && quote !== 39) return;
|
|
7308
|
+
for (let j = i + 1; j < source.length; j++) {
|
|
7309
|
+
const code = source.charCodeAt(j);
|
|
7310
|
+
if (code === 10 || code === 13) return;
|
|
7311
|
+
if (code === 92) return readEscapedStringLiteral(source, i, j);
|
|
7312
|
+
if (code === quote) return { value: source.slice(i + 1, j), end: j + 1 };
|
|
7313
|
+
}
|
|
7314
|
+
};
|
|
7315
|
+
|
|
7316
|
+
/**
|
|
7317
|
+
* Continues `readStringLiteral` from its first escape, so the unescaped case
|
|
7318
|
+
* stays a single slice.
|
|
7319
|
+
* @param {string} source source code
|
|
7320
|
+
* @param {number} i offset of the opening quote
|
|
7321
|
+
* @param {number} firstEscape offset of the first backslash
|
|
7322
|
+
* @returns {{ value: string, end: number } | undefined} the literal
|
|
7323
|
+
*/
|
|
7324
|
+
const readEscapedStringLiteral = (source, i, firstEscape) => {
|
|
7325
|
+
const quote = source.charCodeAt(i);
|
|
7326
|
+
let value = "";
|
|
7327
|
+
let segment = i + 1;
|
|
7328
|
+
for (let j = firstEscape; j < source.length; j++) {
|
|
7329
|
+
const code = source.charCodeAt(j);
|
|
7330
|
+
if (code === 10 || code === 13) return;
|
|
7331
|
+
if (code === quote) {
|
|
7332
|
+
return { value: value + source.slice(segment, j), end: j + 1 };
|
|
7333
|
+
}
|
|
7334
|
+
if (code !== 92) continue;
|
|
7335
|
+
const escape = readEscape(source, j + 1);
|
|
7336
|
+
if (escape === undefined) return;
|
|
7337
|
+
value += source.slice(segment, j) + escape.value;
|
|
7338
|
+
segment = escape.end;
|
|
7339
|
+
j = escape.end - 1;
|
|
7340
|
+
}
|
|
7341
|
+
};
|
|
7342
|
+
|
|
7343
|
+
/**
|
|
7344
|
+
* Scans a template body from `i` (just past a backtick or a `}` resuming one).
|
|
7345
|
+
* @param {string} source source code
|
|
7346
|
+
* @param {number} i offset inside the template
|
|
7347
|
+
* @returns {{ end: number, substitution: boolean }} where the body stops
|
|
7348
|
+
*/
|
|
7349
|
+
const skipTemplateBody = (source, i) => {
|
|
7350
|
+
for (; i < source.length; i++) {
|
|
7351
|
+
const code = source.charCodeAt(i);
|
|
7352
|
+
if (code === 92) {
|
|
7353
|
+
i++;
|
|
7354
|
+
} else if (code === 96) {
|
|
7355
|
+
return { end: i, substitution: false };
|
|
7356
|
+
} else if (code === 36 && source.charCodeAt(i + 1) === 123) {
|
|
7357
|
+
return { end: i + 1, substitution: true };
|
|
7358
|
+
}
|
|
7359
|
+
}
|
|
7360
|
+
return { end: source.length, substitution: false };
|
|
7361
|
+
};
|
|
7362
|
+
|
|
7363
|
+
/**
|
|
7364
|
+
* Collects the specifiers of static `require("…")` calls. A scan rather than a
|
|
7365
|
+
* parse: it only has to skip what could hide or fake a call — comments, strings,
|
|
7366
|
+
* templates and regexps — so it costs one pass and builds no ast. Template
|
|
7367
|
+
* substitutions are scanned as the code they are, which is why the brace depth
|
|
7368
|
+
* of each open `${` is tracked.
|
|
7369
|
+
* @param {string} source source code
|
|
7370
|
+
* @returns {Set<string>} required specifiers
|
|
7371
|
+
*/
|
|
7372
|
+
const collectCjsRequireSpecifiers = (source) => {
|
|
7373
|
+
/** @type {Set<string>} */
|
|
7374
|
+
const specifiers = new Set();
|
|
7375
|
+
/** @type {number[]} */
|
|
7376
|
+
const templateBraceDepths = [];
|
|
7377
|
+
let braceDepth = 0;
|
|
7378
|
+
for (let i = 0; i < source.length; i++) {
|
|
7379
|
+
const code = source.charCodeAt(i);
|
|
7380
|
+
if (code === 96) {
|
|
7381
|
+
const body = skipTemplateBody(source, i + 1);
|
|
7382
|
+
i = body.end;
|
|
7383
|
+
if (body.substitution) {
|
|
7384
|
+
templateBraceDepths.push(braceDepth);
|
|
7385
|
+
braceDepth++;
|
|
7386
|
+
}
|
|
7387
|
+
continue;
|
|
7388
|
+
}
|
|
7389
|
+
if (code === 123) {
|
|
7390
|
+
braceDepth++;
|
|
7391
|
+
continue;
|
|
7392
|
+
}
|
|
7393
|
+
if (code === 125) {
|
|
7394
|
+
braceDepth--;
|
|
7395
|
+
if (
|
|
7396
|
+
templateBraceDepths.length > 0 &&
|
|
7397
|
+
templateBraceDepths[templateBraceDepths.length - 1] === braceDepth
|
|
7398
|
+
) {
|
|
7399
|
+
templateBraceDepths.pop();
|
|
7400
|
+
const body = skipTemplateBody(source, i + 1);
|
|
7401
|
+
i = body.end;
|
|
7402
|
+
if (body.substitution) {
|
|
7403
|
+
templateBraceDepths.push(braceDepth);
|
|
7404
|
+
braceDepth++;
|
|
7405
|
+
}
|
|
7406
|
+
}
|
|
7407
|
+
continue;
|
|
7408
|
+
}
|
|
7409
|
+
if (code === 34 || code === 39) {
|
|
7410
|
+
for (i++; i < source.length; i++) {
|
|
7411
|
+
const inner = source.charCodeAt(i);
|
|
7412
|
+
if (inner === 92) i++;
|
|
7413
|
+
else if (inner === code) break;
|
|
7414
|
+
}
|
|
7415
|
+
continue;
|
|
7416
|
+
}
|
|
7417
|
+
if (code === 47) {
|
|
7418
|
+
const next = source.charCodeAt(i + 1);
|
|
7419
|
+
if (next === 47) {
|
|
7420
|
+
const end = source.indexOf("\n", i + 2);
|
|
7421
|
+
i = end === -1 ? source.length : end;
|
|
7422
|
+
continue;
|
|
7423
|
+
}
|
|
7424
|
+
if (next === 42) {
|
|
7425
|
+
const end = source.indexOf("*/", i + 2);
|
|
7426
|
+
i = end === -1 ? source.length : end + 1;
|
|
7427
|
+
continue;
|
|
7428
|
+
}
|
|
7429
|
+
if (!startsRegExp(source, i)) continue;
|
|
7430
|
+
let inClass = false;
|
|
7431
|
+
for (i++; i < source.length; i++) {
|
|
7432
|
+
const inner = source.charCodeAt(i);
|
|
7433
|
+
if (inner === 92) i++;
|
|
7434
|
+
else if (inner === 91) inClass = true;
|
|
7435
|
+
else if (inner === 93) inClass = false;
|
|
7436
|
+
else if (inner === 10) break;
|
|
7437
|
+
else if (inner === 47 && !inClass) break;
|
|
7438
|
+
}
|
|
7439
|
+
continue;
|
|
7440
|
+
}
|
|
7441
|
+
// `r` of `require`, as a whole word that is not a member access
|
|
7442
|
+
if (code !== 114 || !source.startsWith("require", i)) continue;
|
|
7443
|
+
if (isIdentifierChar(source.charCodeAt(i + 7))) continue;
|
|
7444
|
+
if (i > 0) {
|
|
7445
|
+
const before = source.charCodeAt(i - 1);
|
|
7446
|
+
if (isIdentifierChar(before) || before === 46) continue;
|
|
7447
|
+
}
|
|
7448
|
+
let j = skipTrivia(source, i + 7);
|
|
7449
|
+
if (source.charCodeAt(j) !== 40) continue;
|
|
7450
|
+
j = skipTrivia(source, j + 1);
|
|
7451
|
+
// a cast wraps the specifier in its own parens: `require(/** … */ ("x"))`
|
|
7452
|
+
let parens = 0;
|
|
7453
|
+
while (source.charCodeAt(j) === 40) {
|
|
7454
|
+
parens++;
|
|
7455
|
+
j = skipTrivia(source, j + 1);
|
|
7456
|
+
}
|
|
7457
|
+
const literal = readStringLiteral(source, j);
|
|
7458
|
+
if (literal === undefined) {
|
|
7459
|
+
i += 6;
|
|
7460
|
+
continue;
|
|
7461
|
+
}
|
|
7462
|
+
j = skipTrivia(source, literal.end);
|
|
7463
|
+
while (parens > 0 && source.charCodeAt(j) === 41) {
|
|
7464
|
+
parens--;
|
|
7465
|
+
j = skipTrivia(source, j + 1);
|
|
7466
|
+
}
|
|
7467
|
+
if (parens !== 0 || source.charCodeAt(j) !== 41) {
|
|
7468
|
+
i += 6;
|
|
7469
|
+
continue;
|
|
7470
|
+
}
|
|
7471
|
+
specifiers.add(literal.value);
|
|
7472
|
+
i = j;
|
|
7473
|
+
}
|
|
7474
|
+
return specifiers;
|
|
7475
|
+
};
|
|
7476
|
+
|
|
4376
7477
|
module.exports.LEGACY_ASSERT_ATTRIBUTES = LEGACY_ASSERT_ATTRIBUTES;
|
|
4377
7478
|
module.exports.WebpackParser = WebpackParser;
|
|
4378
7479
|
module.exports.buildLineStarts = buildLineStarts;
|
|
7480
|
+
module.exports.collectCjsRequireSpecifiers = collectCjsRequireSpecifiers;
|
|
4379
7481
|
module.exports.hasOctalEscape = hasOctalEscape;
|
|
7482
|
+
module.exports.isIdentifierChar = isIdentifierChar;
|
|
4380
7483
|
module.exports.positionAt = positionAt;
|