@depup/webpack 5.109.2-depup.0 → 5.110.3-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.
Files changed (647) hide show
  1. package/README.md +5 -5
  2. package/changes.json +7 -7
  3. package/lib/APIPlugin.js +123 -17
  4. package/lib/AsyncDependenciesBlock.js +10 -7
  5. package/lib/AutomaticPrefetchPlugin.js +1 -1
  6. package/lib/BannerPlugin.js +10 -6
  7. package/lib/CacheFacade.js +6 -6
  8. package/lib/Chunk.js +14 -11
  9. package/lib/ChunkGraph.js +46 -35
  10. package/lib/ChunkGroup.js +7 -7
  11. package/lib/ChunkTemplate.js +35 -44
  12. package/lib/CircularModulesPlugin.js +205 -28
  13. package/lib/CleanPlugin.js +4 -7
  14. package/lib/CodeGenerationResults.js +11 -8
  15. package/lib/CompatibilityPlugin.js +7 -7
  16. package/lib/Compilation.js +688 -409
  17. package/lib/Compiler.js +53 -38
  18. package/lib/ConcatenationScope.js +107 -8
  19. package/lib/ConditionalInitFragment.js +3 -3
  20. package/lib/ConstPlugin.js +13 -11
  21. package/lib/ContextExclusionPlugin.js +1 -1
  22. package/lib/ContextModule.js +146 -54
  23. package/lib/ContextModuleFactory.js +46 -14
  24. package/lib/ContextReplacementPlugin.js +12 -14
  25. package/lib/DefinePlugin.js +121 -37
  26. package/lib/DependenciesBlock.js +9 -6
  27. package/lib/Dependency.js +36 -16
  28. package/lib/DependencyTemplate.js +11 -12
  29. package/lib/DependencyTemplates.js +3 -3
  30. package/lib/DotenvPlugin.js +91 -26
  31. package/lib/DynamicEntryPlugin.js +8 -4
  32. package/lib/EntryOptionPlugin.js +8 -4
  33. package/lib/EntryPlugin.js +2 -2
  34. package/lib/Entrypoint.js +6 -2
  35. package/lib/EnvironmentPlugin.js +2 -2
  36. package/lib/EvalDevToolModulePlugin.js +8 -4
  37. package/lib/EvalSourceMapDevToolPlugin.js +15 -8
  38. package/lib/ExportsInfo.js +111 -14
  39. package/lib/ExportsInfoApiPlugin.js +2 -4
  40. package/lib/ExternalModule.js +232 -77
  41. package/lib/ExternalModuleFactoryPlugin.js +97 -38
  42. package/lib/ExternalsPlugin.js +10 -6
  43. package/lib/FileSystemInfo.js +44 -70
  44. package/lib/FlagAllModulesAsUsedPlugin.js +2 -3
  45. package/lib/FlagDependencyExportsPlugin.js +76 -19
  46. package/lib/FlagDependencyUsagePlugin.js +40 -49
  47. package/lib/FlagEntryExportAsUsedPlugin.js +1 -1
  48. package/lib/Generator.js +36 -15
  49. package/lib/HotModuleReplacementPlugin.js +16 -44
  50. package/lib/IgnorePlugin.js +8 -4
  51. package/lib/IgnoreWarningsPlugin.js +2 -2
  52. package/lib/InitFragment.js +8 -4
  53. package/lib/JavascriptMetaInfoPlugin.js +35 -4
  54. package/lib/LazyBarrel.js +3 -4
  55. package/lib/LibraryTemplatePlugin.js +10 -6
  56. package/lib/LoaderOptionsPlugin.js +7 -3
  57. package/lib/LoaderTargetPlugin.js +1 -1
  58. package/lib/MainTemplate.js +49 -42
  59. package/lib/ManifestPlugin.js +12 -11
  60. package/lib/Module.js +62 -33
  61. package/lib/ModuleFactory.js +3 -3
  62. package/lib/ModuleFilenameHelpers.js +9 -4
  63. package/lib/ModuleGraph.js +195 -21
  64. package/lib/ModuleGraphConnection.js +6 -13
  65. package/lib/ModuleInfoHeaderPlugin.js +8 -10
  66. package/lib/ModuleTemplate.js +62 -63
  67. package/lib/MultiCompiler.js +130 -64
  68. package/lib/MultiStats.js +40 -9
  69. package/lib/MultiWatching.js +3 -3
  70. package/lib/NoEmitOnErrorsPlugin.js +1 -1
  71. package/lib/NodeStuffPlugin.js +29 -19
  72. package/lib/NormalModule.js +152 -103
  73. package/lib/NormalModuleFactory.js +555 -110
  74. package/lib/NormalModuleReplacementPlugin.js +5 -8
  75. package/lib/NullFactory.js +6 -2
  76. package/lib/OptionsApply.js +7 -3
  77. package/lib/Parser.js +7 -3
  78. package/lib/PlatformPlugin.js +2 -2
  79. package/lib/PrefetchPlugin.js +1 -1
  80. package/lib/ProgressPlugin.js +16 -13
  81. package/lib/ProvidePlugin.js +3 -5
  82. package/lib/RawModule.js +25 -17
  83. package/lib/RecordIdsPlugin.js +3 -3
  84. package/lib/RequestShortener.js +1 -1
  85. package/lib/ResolverFactory.js +2 -2
  86. package/lib/RuntimeGlobals.js +22 -10
  87. package/lib/RuntimeModule.js +29 -19
  88. package/lib/RuntimePlugin.js +335 -169
  89. package/lib/RuntimeTemplate.js +2761 -316
  90. package/lib/SelfModuleFactory.js +7 -3
  91. package/lib/SourceMapDevToolModuleOptionsPlugin.js +6 -2
  92. package/lib/SourceMapDevToolPlugin.js +30 -20
  93. package/lib/Stats.js +3 -4
  94. package/lib/Template.js +32 -22
  95. package/lib/TemplatedPathPlugin.js +96 -14
  96. package/lib/UseStrictPlugin.js +4 -6
  97. package/lib/WarnCaseSensitiveModulesPlugin.js +4 -4
  98. package/lib/WarnDeprecatedOptionPlugin.js +1 -1
  99. package/lib/WarnNoModeSetPlugin.js +1 -1
  100. package/lib/WatchIgnorePlugin.js +8 -6
  101. package/lib/Watching.js +8 -8
  102. package/lib/WebpackIsIncludedPlugin.js +2 -4
  103. package/lib/WebpackOptionsApply.js +308 -18
  104. package/lib/WebpackOptionsDefaulter.js +6 -2
  105. package/lib/asset/AssetBytesGenerator.js +12 -10
  106. package/lib/asset/AssetBytesParser.js +2 -4
  107. package/lib/asset/AssetGenerator.js +188 -95
  108. package/lib/asset/AssetModule.js +7 -3
  109. package/lib/asset/AssetModulesPlugin.js +110 -38
  110. package/lib/asset/AssetParser.js +9 -7
  111. package/lib/asset/AssetSourceGenerator.js +60 -13
  112. package/lib/asset/AssetSourceParser.js +2 -4
  113. package/lib/asset/RawDataUrlModule.js +24 -16
  114. package/lib/asset/WebManifestGenerator.js +8 -10
  115. package/lib/asset/WebManifestParser.js +24 -10
  116. package/lib/async-modules/AsyncModuleHelpers.js +12 -6
  117. package/lib/async-modules/AwaitDependenciesInitFragment.js +2 -2
  118. package/lib/async-modules/InferAsyncModulesPlugin.js +2 -2
  119. package/lib/async-modules/isGeneratorLowered.js +4 -4
  120. package/lib/buildChunkGraph.js +36 -27
  121. package/lib/bun/BunTargetPlugin.js +1 -1
  122. package/lib/cache/AddBuildDependenciesPlugin.js +1 -1
  123. package/lib/cache/AddManagedPathsPlugin.js +1 -1
  124. package/lib/cache/IdleFileCachePlugin.js +2 -2
  125. package/lib/cache/MemoryCachePlugin.js +18 -10
  126. package/lib/cache/MemoryWithGcCachePlugin.js +34 -22
  127. package/lib/cache/PackFileCacheStrategy.js +30 -23
  128. package/lib/cache/ResolverCachePlugin.js +38 -18
  129. package/lib/cache/getLazyHashedEtag.js +1 -2
  130. package/lib/cache/mergeEtags.js +1 -1
  131. package/lib/cli.js +1 -3
  132. package/lib/config/browserslistTargetHandler.js +41 -5
  133. package/lib/config/defaults.js +270 -78
  134. package/lib/config/defineConfig.js +10 -2
  135. package/lib/config/getClaimedAssetTypes.js +65 -0
  136. package/lib/config/normalization.js +46 -16
  137. package/lib/config/target.js +46 -3
  138. package/lib/container/ContainerEntryDependency.js +1 -1
  139. package/lib/container/ContainerEntryModule.js +24 -15
  140. package/lib/container/ContainerEntryModuleFactory.js +7 -3
  141. package/lib/container/ContainerPlugin.js +9 -10
  142. package/lib/container/ContainerReferencePlugin.js +6 -2
  143. package/lib/container/FallbackDependency.js +1 -1
  144. package/lib/container/FallbackModule.js +24 -17
  145. package/lib/container/FallbackModuleFactory.js +7 -3
  146. package/lib/container/HoistContainerReferencesPlugin.js +6 -11
  147. package/lib/container/ModuleFederationPlugin.js +7 -24
  148. package/lib/container/RemoteModule.js +27 -19
  149. package/lib/container/RemoteRuntimeModule.js +10 -8
  150. package/lib/container/moduleFederationHooks.js +32 -0
  151. package/lib/css/CssGenerator.js +171 -43
  152. package/lib/css/CssInjectStyleRuntimeModule.js +7 -5
  153. package/lib/css/CssLoadingRuntimeModule.js +84 -32
  154. package/lib/css/CssModule.js +10 -7
  155. package/lib/css/CssModulesPlugin.js +172 -100
  156. package/lib/css/CssParser.js +1113 -568
  157. package/lib/css/CssServerStylesRuntimeModule.js +54 -0
  158. package/lib/css/cssMinify.js +168 -0
  159. package/lib/css/data.js +5334 -0
  160. package/lib/css/syntax.js +9647 -232
  161. package/lib/debug/ProfilingPlugin.js +14 -9
  162. package/lib/deno/DenoTargetPlugin.js +1 -1
  163. package/lib/dependencies/AMDDefineDependency.js +112 -87
  164. package/lib/dependencies/AMDDefineDependencyParserPlugin.js +30 -17
  165. package/lib/dependencies/AMDPlugin.js +9 -7
  166. package/lib/dependencies/AMDRequireArrayDependency.js +5 -5
  167. package/lib/dependencies/AMDRequireContextDependency.js +2 -2
  168. package/lib/dependencies/AMDRequireDependenciesBlock.js +1 -1
  169. package/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js +25 -14
  170. package/lib/dependencies/AMDRequireDependency.js +8 -7
  171. package/lib/dependencies/AMDRequireItemDependency.js +1 -1
  172. package/lib/dependencies/AMDRuntimeModules.js +21 -1
  173. package/lib/dependencies/BuildTimeConstDependency.js +102 -0
  174. package/lib/dependencies/CachedConstDependency.js +11 -8
  175. package/lib/dependencies/CommonJsDependencyHelpers.js +67 -46
  176. package/lib/dependencies/CommonJsExportRequireDependency.js +121 -45
  177. package/lib/dependencies/CommonJsExportsDependency.js +53 -49
  178. package/lib/dependencies/CommonJsExportsParserPlugin.js +207 -25
  179. package/lib/dependencies/CommonJsFullRequireDependency.js +119 -34
  180. package/lib/dependencies/CommonJsImportsParserPlugin.js +100 -50
  181. package/lib/dependencies/CommonJsObjectExportDependency.js +188 -0
  182. package/lib/dependencies/CommonJsPlugin.js +35 -6
  183. package/lib/dependencies/CommonJsRequireContextDependency.js +5 -6
  184. package/lib/dependencies/CommonJsRequireDependency.js +170 -27
  185. package/lib/dependencies/CommonJsSelfReferenceDependency.js +63 -38
  186. package/lib/dependencies/ConstDependency.js +8 -9
  187. package/lib/dependencies/ContextDependency.js +12 -8
  188. package/lib/dependencies/ContextDependencyHelpers.js +14 -9
  189. package/lib/dependencies/ContextDependencyTemplateAsId.js +4 -4
  190. package/lib/dependencies/ContextDependencyTemplateAsRequireCall.js +24 -11
  191. package/lib/dependencies/ContextElementDependency.js +31 -12
  192. package/lib/dependencies/CreateRequireParserPlugin.js +12 -7
  193. package/lib/dependencies/CreateScriptUrlDependency.js +4 -4
  194. package/lib/dependencies/CssIcssExportDependency.js +56 -28
  195. package/lib/dependencies/CssIcssImportDependency.js +17 -13
  196. package/lib/dependencies/CssIcssSymbolDependency.js +9 -10
  197. package/lib/dependencies/CssImportDependency.js +18 -9
  198. package/lib/dependencies/CssUrlDependency.js +17 -13
  199. package/lib/dependencies/DllEntryDependency.js +1 -1
  200. package/lib/dependencies/DynamicExports.js +2 -2
  201. package/lib/dependencies/ExportBindingInitFragment.js +36 -9
  202. package/lib/dependencies/ExportsInfoDependency.js +7 -8
  203. package/lib/dependencies/ExternalModuleDependency.js +9 -5
  204. package/lib/dependencies/ExternalModuleInitFragment.js +2 -2
  205. package/lib/dependencies/ExternalModuleInitFragmentDependency.js +8 -5
  206. package/lib/dependencies/HarmonyAcceptDependency.js +5 -5
  207. package/lib/dependencies/HarmonyCompatibilityDependency.js +52 -17
  208. package/lib/dependencies/HarmonyDetectionParserPlugin.js +11 -7
  209. package/lib/dependencies/HarmonyEvaluatedImportSpecifierDependency.js +23 -14
  210. package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +80 -12
  211. package/lib/dependencies/HarmonyExportExpressionDependency.js +23 -18
  212. package/lib/dependencies/HarmonyExportHeaderDependency.js +7 -7
  213. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +286 -80
  214. package/lib/dependencies/HarmonyExportInitFragment.js +18 -6
  215. package/lib/dependencies/HarmonyExportSpecifierDependency.js +51 -14
  216. package/lib/dependencies/HarmonyExports.js +7 -4
  217. package/lib/dependencies/HarmonyImportDependency.js +121 -60
  218. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +124 -38
  219. package/lib/dependencies/HarmonyImportGuard.js +20 -30
  220. package/lib/dependencies/HarmonyImportSideEffectDependency.js +152 -9
  221. package/lib/dependencies/HarmonyImportSpecifierDependency.js +97 -49
  222. package/lib/dependencies/HarmonyModulesPlugin.js +7 -3
  223. package/lib/dependencies/HarmonyTopLevelThisParserPlugin.js +1 -3
  224. package/lib/dependencies/HtmlEntryDependency.js +49 -31
  225. package/lib/dependencies/HtmlInlineHtmlDependency.js +7 -8
  226. package/lib/dependencies/HtmlInlineScriptDependency.js +11 -8
  227. package/lib/dependencies/HtmlInlineStyleDependency.js +7 -10
  228. package/lib/dependencies/HtmlSourceDependency.js +22 -14
  229. package/lib/dependencies/ImportContextDependency.js +45 -5
  230. package/lib/dependencies/ImportDependency.js +33 -50
  231. package/lib/dependencies/ImportEagerDependency.js +6 -9
  232. package/lib/dependencies/ImportMetaContextDependency.js +2 -2
  233. package/lib/dependencies/ImportMetaContextDependencyParserPlugin.js +14 -13
  234. package/lib/dependencies/ImportMetaContextPlugin.js +7 -3
  235. package/lib/dependencies/ImportMetaGlobDependency.js +2 -2
  236. package/lib/dependencies/ImportMetaGlobDependencyParserPlugin.js +2 -3
  237. package/lib/dependencies/ImportMetaGlobHelpers.js +19 -22
  238. package/lib/dependencies/ImportMetaHotAcceptDependency.js +1 -1
  239. package/lib/dependencies/ImportMetaHotDeclineDependency.js +1 -1
  240. package/lib/dependencies/ImportMetaPlugin.js +154 -71
  241. package/lib/dependencies/ImportMetaResolveDependency.js +3 -4
  242. package/lib/dependencies/ImportParserPlugin.js +73 -49
  243. package/lib/dependencies/ImportPhase.js +12 -5
  244. package/lib/dependencies/ImportPlugin.js +7 -3
  245. package/lib/dependencies/ImportWeakDependency.js +6 -9
  246. package/lib/dependencies/JsonExportsDependency.js +11 -7
  247. package/lib/dependencies/LoaderDependency.js +2 -2
  248. package/lib/dependencies/LoaderImportDependency.js +2 -2
  249. package/lib/dependencies/LoaderPlugin.js +11 -7
  250. package/lib/dependencies/LocalModuleDependency.js +5 -5
  251. package/lib/dependencies/LocalModulesHelpers.js +1 -1
  252. package/lib/dependencies/ModuleDecoratorDependency.js +6 -7
  253. package/lib/dependencies/ModuleDependency.js +9 -6
  254. package/lib/dependencies/ModuleDependencyTemplateAsId.js +4 -4
  255. package/lib/dependencies/ModuleDependencyTemplateAsRequireId.js +3 -3
  256. package/lib/dependencies/ModuleHotAcceptDependency.js +1 -1
  257. package/lib/dependencies/ModuleHotDeclineDependency.js +1 -1
  258. package/lib/dependencies/ModuleInitFragmentDependency.js +24 -10
  259. package/lib/dependencies/NullDependency.js +3 -3
  260. package/lib/dependencies/ProvidedDependency.js +14 -10
  261. package/lib/dependencies/PureExpressionDependency.js +9 -10
  262. package/lib/dependencies/RequireContextDependency.js +2 -2
  263. package/lib/dependencies/RequireContextDependencyParserPlugin.js +2 -4
  264. package/lib/dependencies/RequireContextPlugin.js +8 -4
  265. package/lib/dependencies/RequireEnsureDependenciesBlock.js +2 -2
  266. package/lib/dependencies/RequireEnsureDependenciesBlockParserPlugin.js +5 -8
  267. package/lib/dependencies/RequireEnsureDependency.js +8 -7
  268. package/lib/dependencies/RequireEnsurePlugin.js +7 -3
  269. package/lib/dependencies/RequireHeaderDependency.js +50 -12
  270. package/lib/dependencies/RequireIncludeDependency.js +6 -6
  271. package/lib/dependencies/RequireIncludeDependencyParserPlugin.js +2 -3
  272. package/lib/dependencies/RequireIncludePlugin.js +7 -3
  273. package/lib/dependencies/RequireJsStuffPlugin.js +7 -3
  274. package/lib/dependencies/RequireResolveContextDependency.js +2 -2
  275. package/lib/dependencies/RequireResolveDependency.js +4 -4
  276. package/lib/dependencies/RequireResolveHeaderDependency.js +4 -4
  277. package/lib/dependencies/RuntimeRequirementsDependency.js +5 -6
  278. package/lib/dependencies/StaticExportsDependency.js +2 -2
  279. package/lib/dependencies/SystemPlugin.js +10 -6
  280. package/lib/dependencies/SystemRuntimeModule.js +10 -0
  281. package/lib/dependencies/TopLevelAwaitDependency.js +11 -7
  282. package/lib/dependencies/URLContextDependency.js +2 -2
  283. package/lib/dependencies/URLDependency.js +110 -64
  284. package/lib/dependencies/URLPlugin.js +7 -3
  285. package/lib/dependencies/UnsupportedDependency.js +4 -4
  286. package/lib/dependencies/WebAssemblyExportImportedDependency.js +3 -4
  287. package/lib/dependencies/WebAssemblyImportDependency.js +5 -5
  288. package/lib/dependencies/WebpackIsIncludedDependency.js +6 -6
  289. package/lib/dependencies/WorkerAndWorkletPlugin.js +47 -28
  290. package/lib/dependencies/WorkerDependency.js +22 -22
  291. package/lib/dependencies/WorkletDependency.js +18 -21
  292. package/lib/dependencies/getFunctionExpression.js +8 -4
  293. package/lib/dependencies/importOptionsCheck.js +47 -0
  294. package/lib/dependencies/processExportInfo.js +5 -5
  295. package/lib/dll/DelegatedModule.js +34 -22
  296. package/lib/dll/DelegatedModuleFactoryPlugin.js +15 -7
  297. package/lib/dll/DelegatedPlugin.js +2 -2
  298. package/lib/dll/DllEntryPlugin.js +2 -2
  299. package/lib/dll/DllModule.js +22 -15
  300. package/lib/dll/DllModuleFactory.js +7 -3
  301. package/lib/dll/DllPlugin.js +7 -5
  302. package/lib/dll/DllReferencePlugin.js +10 -7
  303. package/lib/dll/LibManifestPlugin.js +5 -5
  304. package/lib/electron/ElectronTargetPlugin.js +53 -49
  305. package/lib/errors/AsyncChunkWaterfallWarning.js +36 -0
  306. package/lib/errors/AsyncDependencyToInitialChunkError.js +2 -2
  307. package/lib/errors/BroadContextsWarning.js +43 -0
  308. package/lib/errors/BuildCycleError.js +1 -1
  309. package/lib/errors/CacheEffectivenessWarning.js +55 -0
  310. package/lib/errors/ChunkRenderError.js +1 -1
  311. package/lib/errors/CircularDependenciesWarning.js +38 -0
  312. package/lib/errors/CodeGenerationError.js +1 -1
  313. package/lib/errors/CommentCompilationWarning.js +1 -1
  314. package/lib/errors/ConflictingResourceHintsWarning.js +35 -0
  315. package/lib/errors/DotenvFileError.js +29 -0
  316. package/lib/errors/DuplicateModulesWarning.js +45 -0
  317. package/lib/errors/DynamicExportsWarning.js +30 -0
  318. package/lib/errors/EmbeddedSourceMapsWarning.js +25 -0
  319. package/lib/errors/EntrypointOverlapWarning.js +45 -0
  320. package/lib/errors/EnvironmentNotSupportAsyncWarning.js +2 -2
  321. package/lib/errors/EvalUsageWarning.js +28 -0
  322. package/lib/errors/HookWebpackError.js +5 -5
  323. package/lib/errors/HotspotsWarning.js +57 -0
  324. package/lib/errors/IgnoreErrorModuleFactory.js +7 -3
  325. package/lib/errors/ImportedBindingAssignmentError.js +30 -0
  326. package/lib/errors/InlinedAssetsWarning.js +36 -0
  327. package/lib/errors/InvalidDependenciesModuleWarning.js +1 -1
  328. package/lib/errors/LargeModulesWarning.js +45 -0
  329. package/lib/errors/LegacyJavascriptWarning.js +48 -0
  330. package/lib/errors/MissingSideEffectsWarning.js +36 -0
  331. package/lib/errors/MixedExportsWarning.js +41 -0
  332. package/lib/errors/ModuleDependencyError.js +13 -16
  333. package/lib/errors/ModuleDependencyWarning.js +5 -15
  334. package/lib/errors/ModuleHashingError.js +1 -1
  335. package/lib/errors/ModuleNotFoundError.js +2 -2
  336. package/lib/errors/ModuleParseError.js +1 -2
  337. package/lib/errors/ModuleRestoreError.js +1 -1
  338. package/lib/errors/ModuleStoreError.js +1 -1
  339. package/lib/errors/NodeStuffInWebError.js +1 -1
  340. package/lib/errors/OsDependentRuleWarning.js +31 -0
  341. package/lib/errors/PureAnnotationsWarning.js +36 -0
  342. package/lib/errors/RedundantDynamicImportWarning.js +31 -0
  343. package/lib/errors/ScopeHoistingBailoutsWarning.js +41 -0
  344. package/lib/errors/SplitChunksCappedWarning.js +41 -0
  345. package/lib/errors/TinyChunksWarning.js +40 -0
  346. package/lib/errors/TopLevelThisWarning.js +34 -0
  347. package/lib/errors/UnsplitVendorsWarning.js +42 -0
  348. package/lib/errors/UnsupportedFeatureWarning.js +1 -1
  349. package/lib/errors/UnusedAliasesWarning.js +29 -0
  350. package/lib/errors/UnusedDefinesWarning.js +29 -0
  351. package/lib/errors/UnusedExternalsWarning.js +29 -0
  352. package/lib/errors/UnusedReexportsWarning.js +42 -0
  353. package/lib/errors/UnusedRuleWarning.js +29 -0
  354. package/lib/errors/WebpackError.js +9 -5
  355. package/lib/errors/deriveStackFromNestedError.js +90 -0
  356. package/lib/esm/ExportWebpackRequireRuntimeModule.js +2 -0
  357. package/lib/esm/ModuleChunkFormatPlugin.js +37 -19
  358. package/lib/esm/ModuleChunkLoadingPlugin.js +86 -51
  359. package/lib/esm/ModuleChunkLoadingRuntimeModule.js +161 -62
  360. package/lib/hmr/HotModuleReplacement.runtime.js +24 -5
  361. package/lib/hmr/HotModuleReplacementRuntimeModule.js +1 -1
  362. package/lib/hmr/LazyCompilationPlugin.js +45 -24
  363. package/lib/hmr/lazyCompilationBackend.js +9 -6
  364. package/lib/hmr/parserHooks.js +56 -0
  365. package/lib/html/HtmlGenerator.js +277 -77
  366. package/lib/html/HtmlModule.js +7 -3
  367. package/lib/html/HtmlModulesPlugin.js +366 -200
  368. package/lib/html/HtmlParser.js +31 -86
  369. package/lib/html/data.js +1928 -0
  370. package/lib/html/htmlMinify.js +288 -0
  371. package/lib/html/syntax.js +6034 -1384
  372. package/lib/ids/ChunkModuleIdRangePlugin.js +3 -3
  373. package/lib/ids/DeterministicChunkIdsPlugin.js +1 -1
  374. package/lib/ids/DeterministicModuleIdsPlugin.js +2 -2
  375. package/lib/ids/HashedModuleIdsPlugin.js +6 -2
  376. package/lib/ids/IdHelpers.js +7 -8
  377. package/lib/ids/NamedChunkIdsPlugin.js +1 -1
  378. package/lib/ids/NamedModuleIdsPlugin.js +1 -1
  379. package/lib/ids/NaturalChunkIdsPlugin.js +2 -2
  380. package/lib/ids/NaturalModuleIdsPlugin.js +1 -1
  381. package/lib/ids/OccurrenceChunkIdsPlugin.js +7 -3
  382. package/lib/ids/OccurrenceModuleIdsPlugin.js +7 -3
  383. package/lib/ids/SyncModuleIdsPlugin.js +4 -4
  384. package/lib/index.js +10 -0
  385. package/lib/javascript/ArrayPushCallbackChunkFormatPlugin.js +3 -3
  386. package/lib/javascript/BasicEvaluatedExpression.js +18 -14
  387. package/lib/javascript/ChunkFormatHelpers.js +6 -6
  388. package/lib/javascript/ChunkHelpers.js +1 -1
  389. package/lib/javascript/CommonJsChunkFormatPlugin.js +11 -5
  390. package/lib/javascript/EnableChunkLoadingPlugin.js +2 -2
  391. package/lib/javascript/JavascriptGenerator.js +65 -165
  392. package/lib/javascript/JavascriptModule.js +9 -3
  393. package/lib/javascript/JavascriptModulesPlugin.js +103 -123
  394. package/lib/javascript/JavascriptParser.js +242 -99
  395. package/lib/javascript/JavascriptParserHelpers.js +10 -7
  396. package/lib/javascript/ScopeAnalyzer.js +1094 -0
  397. package/lib/javascript/StartupHelpers.js +55 -9
  398. package/lib/javascript/syntax.js +2678 -232
  399. package/lib/json/JsonData.js +8 -4
  400. package/lib/json/JsonGenerator.js +38 -16
  401. package/lib/json/JsonModule.js +7 -3
  402. package/lib/json/JsonModulesPlugin.js +1 -1
  403. package/lib/json/JsonParser.js +5 -6
  404. package/lib/library/AbstractLibraryPlugin.js +20 -14
  405. package/lib/library/AmdLibraryPlugin.js +11 -7
  406. package/lib/library/AssignLibraryPlugin.js +19 -13
  407. package/lib/library/EnableLibraryPlugin.js +2 -2
  408. package/lib/library/ExportPropertyLibraryPlugin.js +15 -8
  409. package/lib/library/JsonpLibraryPlugin.js +11 -7
  410. package/lib/library/ModuleLibraryPlugin.js +256 -64
  411. package/lib/library/SystemLibraryPlugin.js +12 -8
  412. package/lib/library/UmdLibraryPlugin.js +62 -25
  413. package/lib/loaders/LoaderRunner.js +47 -6
  414. package/lib/loaders/loadLoader.js +8 -4
  415. package/lib/logging/createConsoleLogger.js +7 -4
  416. package/lib/node/CommonJsChunkLoadingPlugin.js +36 -22
  417. package/lib/node/NodeEnvironmentPlugin.js +17 -3
  418. package/lib/node/NodeSourcePlugin.js +1 -1
  419. package/lib/node/NodeTargetPlugin.js +4 -3
  420. package/lib/node/NodeTemplatePlugin.js +1 -1
  421. package/lib/node/NodeWatchFileSystem.js +70 -9
  422. package/lib/node/ReadFileChunkLoadingRuntimeModule.js +35 -38
  423. package/lib/node/ReadFileCompileAsyncWasmPlugin.js +65 -19
  424. package/lib/node/ReadFileCompileWasmPlugin.js +28 -16
  425. package/lib/node/RequireChunkLoadingRuntimeModule.js +35 -38
  426. package/lib/node/nodeConsole.js +7 -3
  427. package/lib/optimize/AggressiveMergingPlugin.js +2 -2
  428. package/lib/optimize/AggressiveSplittingPlugin.js +9 -6
  429. package/lib/optimize/ConcatenatedModule.js +1030 -476
  430. package/lib/optimize/ConstExportsPlugin.js +16 -7
  431. package/lib/optimize/EnsureChunkConditionsPlugin.js +3 -3
  432. package/lib/optimize/FlagIncludedChunksPlugin.js +3 -4
  433. package/lib/optimize/InlineExports.js +130 -5
  434. package/lib/optimize/InnerGraph.js +28 -12
  435. package/lib/optimize/InnerGraphPlugin.js +23 -18
  436. package/lib/optimize/LimitChunkCountPlugin.js +7 -3
  437. package/lib/optimize/MangleExportsPlugin.js +7 -8
  438. package/lib/optimize/MergeDuplicateChunksPlugin.js +7 -3
  439. package/lib/optimize/MinChunkSizePlugin.js +7 -3
  440. package/lib/optimize/ModuleConcatenationPlugin.js +51 -35
  441. package/lib/optimize/RealContentHashPlugin.js +121 -41
  442. package/lib/optimize/RemoveEmptyChunksPlugin.js +2 -2
  443. package/lib/optimize/RemoveParentModulesPlugin.js +4 -4
  444. package/lib/optimize/RuntimeChunkPlugin.js +2 -2
  445. package/lib/optimize/SideEffectsFlagPlugin.js +262 -39
  446. package/lib/optimize/SplitChunksPlugin.js +86 -24
  447. package/lib/performance/AssetsOverSizeLimitWarning.js +10 -2
  448. package/lib/performance/AsyncChunkWaterfallsPlugin.js +136 -0
  449. package/lib/performance/BroadContextsPlugin.js +142 -0
  450. package/lib/performance/CacheEffectivenessPlugin.js +125 -0
  451. package/lib/performance/ConflictingResourceHintsPlugin.js +99 -0
  452. package/lib/performance/DuplicateModulesPlugin.js +93 -0
  453. package/lib/performance/DuplicatePackagesPlugin.js +119 -0
  454. package/lib/performance/DuplicatePackagesWarning.js +84 -0
  455. package/lib/performance/DynamicExportsPlugin.js +120 -0
  456. package/lib/performance/EmbeddedSourceMapsPlugin.js +71 -0
  457. package/lib/performance/EntrypointOverlapPlugin.js +122 -0
  458. package/lib/performance/EntrypointsOverSizeLimitWarning.js +1 -1
  459. package/lib/performance/EvalUsagePlugin.js +115 -0
  460. package/lib/performance/HotspotsPlugin.js +296 -0
  461. package/lib/performance/InlinedAssetsPlugin.js +99 -0
  462. package/lib/performance/LargeModulesPlugin.js +126 -0
  463. package/lib/performance/LegacyJavascriptPlugin.js +139 -0
  464. package/lib/performance/MissingSideEffectsPlugin.js +138 -0
  465. package/lib/performance/MixedExportsPlugin.js +136 -0
  466. package/lib/performance/OsDependentRuleWarningPlugin.js +178 -0
  467. package/lib/performance/PureAnnotationsPlugin.js +219 -0
  468. package/lib/performance/RedundantDynamicImportsPlugin.js +225 -0
  469. package/lib/performance/RuntimeInLargeChunkWarning.js +27 -0
  470. package/lib/performance/ScopeHoistingBailoutsPlugin.js +164 -0
  471. package/lib/performance/SizeLimitsPlugin.js +139 -7
  472. package/lib/performance/SplitChunksCappedPlugin.js +99 -0
  473. package/lib/performance/TinyChunksPlugin.js +128 -0
  474. package/lib/performance/TopLevelThisPlugin.js +208 -0
  475. package/lib/performance/UnsplitVendorsPlugin.js +112 -0
  476. package/lib/performance/UnusedAliasesPlugin.js +253 -0
  477. package/lib/performance/UnusedDefinesPlugin.js +87 -0
  478. package/lib/performance/UnusedExternalsPlugin.js +110 -0
  479. package/lib/performance/UnusedReexportsPlugin.js +159 -0
  480. package/lib/performance/UnusedRuleWarningPlugin.js +105 -0
  481. package/lib/performance/getModuleSize.js +22 -0
  482. package/lib/performance/getSourceModules.js +22 -0
  483. package/lib/performance/hasOnlyUnusedExports.js +40 -0
  484. package/lib/prefetch/ChunkPrefetchFunctionRuntimeModule.js +24 -10
  485. package/lib/prefetch/ChunkPrefetchPreloadPlugin.js +63 -46
  486. package/lib/prefetch/ChunkPrefetchStartupRuntimeModule.js +2 -3
  487. package/lib/prefetch/ChunkPrefetchTriggerRuntimeModule.js +2 -2
  488. package/lib/prefetch/ChunkPreloadTriggerRuntimeModule.js +2 -2
  489. package/lib/prefetch/ResourceHintPlugin.js +295 -79
  490. package/lib/prefetch/ResourceHintRuntimeModule.js +1 -21
  491. package/lib/prefetch/StartupAssetHintRuntimeModule.js +10 -133
  492. package/lib/prefetch/parseResourceHintOptions.js +31 -4
  493. package/lib/rules/BasicEffectRulePlugin.js +2 -2
  494. package/lib/rules/BasicMatcherRulePlugin.js +8 -4
  495. package/lib/rules/GlobMatcherRulePlugin.js +68 -0
  496. package/lib/rules/ObjectMatcherRulePlugin.js +12 -5
  497. package/lib/rules/RuleSetCompiler.js +146 -12
  498. package/lib/rules/UseEffectRulePlugin.js +18 -11
  499. package/lib/runtime/AsyncModuleGeneratorRuntimeModule.js +11 -1
  500. package/lib/runtime/AsyncModuleRuntimeModule.js +6 -2
  501. package/lib/runtime/AutoPublicPathRuntimeModule.js +15 -20
  502. package/lib/runtime/BaseUriRuntimeModule.js +33 -7
  503. package/lib/runtime/ChunkNameRuntimeModule.js +10 -0
  504. package/lib/runtime/CompatGetDefaultExportRuntimeModule.js +11 -1
  505. package/lib/runtime/CompatRuntimeModule.js +5 -3
  506. package/lib/runtime/ConcatenationWrapRuntimeModule.js +90 -0
  507. package/lib/runtime/ConstructRequireRuntimeModule.js +52 -0
  508. package/lib/runtime/CreateFakeNamespaceObjectRuntimeModule.js +8 -6
  509. package/lib/runtime/CreateScriptRuntimeModule.js +11 -1
  510. package/lib/runtime/CreateScriptUrlRuntimeModule.js +11 -1
  511. package/lib/runtime/DefinePropertyGettersRuntimeModule.js +56 -38
  512. package/lib/runtime/EnsureChunkRuntimeModule.js +18 -2
  513. package/lib/runtime/GetChunkFilenameRuntimeModule.js +62 -37
  514. package/lib/runtime/GetFullHashRuntimeModule.js +12 -2
  515. package/lib/runtime/GetMainFilenameRuntimeModule.js +12 -2
  516. package/lib/runtime/GetTrustedTypesPolicyRuntimeModule.js +2 -2
  517. package/lib/runtime/GetWorkletBootstrapRuntimeModule.js +16 -3
  518. package/lib/runtime/GlobalRuntimeModule.js +18 -0
  519. package/lib/runtime/HasOwnPropertyRuntimeModule.js +12 -2
  520. package/lib/runtime/LoadScriptRuntimeModule.js +2 -2
  521. package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +34 -7
  522. package/lib/runtime/MakeNamespaceObjectRuntimeModule.js +22 -6
  523. package/lib/runtime/NonceRuntimeModule.js +10 -0
  524. package/lib/runtime/OnChunksLoadedRuntimeModule.js +5 -3
  525. package/lib/runtime/PublicPathRuntimeModule.js +12 -2
  526. package/lib/runtime/RelativeUrlRuntimeModule.js +11 -1
  527. package/lib/runtime/RuntimeIdRuntimeModule.js +12 -2
  528. package/lib/runtime/SetAnonymousDefaultNameRuntimeModule.js +11 -1
  529. package/lib/runtime/StartupChunkDependenciesPlugin.js +18 -9
  530. package/lib/runtime/StartupChunkDependenciesRuntimeModule.js +3 -3
  531. package/lib/runtime/StartupEntrypointRuntimeModule.js +21 -4
  532. package/lib/runtime/SystemContextRuntimeModule.js +10 -0
  533. package/lib/runtime/ToBinaryRuntimeModule.js +1 -1
  534. package/lib/runtime/WorkerRuntimeModule.js +11 -1
  535. package/lib/runtime/baseUri.js +63 -0
  536. package/lib/schemes/DataUriPlugin.js +1 -1
  537. package/lib/schemes/FileUriPlugin.js +1 -1
  538. package/lib/schemes/HttpUriPlugin.js +46 -20
  539. package/lib/schemes/VirtualUrlPlugin.js +13 -7
  540. package/lib/serialization/AggregateErrorSerializer.js +1 -1
  541. package/lib/serialization/BinaryMiddleware.js +4 -4
  542. package/lib/serialization/ErrorObjectSerializer.js +1 -1
  543. package/lib/serialization/FileMiddleware.js +22 -9
  544. package/lib/serialization/ObjectMiddleware.js +139 -114
  545. package/lib/serialization/PlainObjectSerializer.js +19 -16
  546. package/lib/sharing/ConsumeSharedModule.js +30 -21
  547. package/lib/sharing/ConsumeSharedPlugin.js +18 -10
  548. package/lib/sharing/ConsumeSharedRuntimeModule.js +6 -9
  549. package/lib/sharing/ProvideSharedModule.js +25 -16
  550. package/lib/sharing/ProvideSharedModuleFactory.js +7 -3
  551. package/lib/sharing/ProvideSharedPlugin.js +8 -4
  552. package/lib/sharing/SharePlugin.js +17 -5
  553. package/lib/sharing/ShareRuntimeModule.js +4 -4
  554. package/lib/sharing/resolveMatchedConfigs.js +9 -6
  555. package/lib/sharing/utils.js +1 -3
  556. package/lib/stats/DefaultStatsFactoryPlugin.js +50 -29
  557. package/lib/stats/DefaultStatsPresetPlugin.js +17 -8
  558. package/lib/stats/DefaultStatsPrinterPlugin.js +36 -26
  559. package/lib/stats/StatsFactory.js +25 -26
  560. package/lib/stats/StatsPrinter.js +16 -12
  561. package/lib/typescript/TypeScriptPlugin.js +20 -24
  562. package/lib/url/URLParserPlugin.js +26 -13
  563. package/lib/util/ArrayQueue.js +3 -3
  564. package/lib/util/AsyncQueue.js +4 -3
  565. package/lib/util/Hash.js +5 -1
  566. package/lib/util/LazySet.js +35 -22
  567. package/lib/util/LocConverter.js +36 -13
  568. package/lib/util/SourceProcessor.js +1066 -24
  569. package/lib/util/StringXor.js +1 -1
  570. package/lib/util/URLAbsoluteSpecifier.js +3 -1
  571. package/lib/util/chainedImports.js +9 -5
  572. package/lib/util/cleverMerge.js +1 -1
  573. package/lib/util/comparators.js +45 -14
  574. package/lib/util/concatenate.js +203 -77
  575. package/lib/util/conventions.js +10 -2
  576. package/lib/util/createHash.js +2 -2
  577. package/lib/util/createHooksRegistry.js +8 -10
  578. package/lib/util/createMappings.js +25 -3
  579. package/lib/util/dataURL.js +225 -1
  580. package/lib/util/extractSourceMap.js +4 -3
  581. package/lib/util/findCaseMismatch.js +139 -0
  582. package/lib/util/formatLocation.js +1 -2
  583. package/lib/util/fs.js +22 -5
  584. package/lib/util/globUtils.js +298 -24
  585. package/lib/util/hash/BatchedHash.js +5 -1
  586. package/lib/util/hash/BulkUpdateHash.js +5 -1
  587. package/lib/util/hash/DebugHash.js +5 -1
  588. package/lib/util/hash/hash-digest.js +6 -2
  589. package/lib/util/identifier.js +4 -0
  590. package/lib/util/implicitTypeLoaderFallback.js +1 -1
  591. package/lib/util/internalSerializables.js +8 -0
  592. package/lib/util/lazyModule.js +56 -0
  593. package/lib/util/makeSerializable.js +7 -3
  594. package/lib/util/matchAlias.js +25 -0
  595. package/lib/util/mimeTypes.js +11 -5
  596. package/lib/util/nonNumericOnlyHash.js +4 -3
  597. package/lib/util/parseJson.js +5 -3
  598. package/lib/util/preloadModuleType.js +32 -0
  599. package/lib/util/registerExternalSerializer.js +7 -5
  600. package/lib/util/removeBOM.js +82 -1
  601. package/lib/util/runtime.js +2 -2
  602. package/lib/util/semver.js +1 -1
  603. package/lib/util/serialization.js +28 -28
  604. package/lib/util/source.js +2 -2
  605. package/lib/util/traverseDestructuringAssignmentProperties.js +6 -2
  606. package/lib/wasm/EnableWasmLoadingPlugin.js +10 -8
  607. package/lib/wasm/wasmModuleFilename.js +54 -0
  608. package/lib/wasm-async/AsyncWasmCompileRuntimeModule.js +43 -21
  609. package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +45 -21
  610. package/lib/wasm-async/AsyncWasmModule.js +3 -3
  611. package/lib/wasm-async/AsyncWebAssemblyGenerator.js +4 -5
  612. package/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js +57 -17
  613. package/lib/wasm-async/AsyncWebAssemblyModulesPlugin.js +34 -18
  614. package/lib/wasm-async/AsyncWebAssemblyParser.js +9 -8
  615. package/lib/wasm-async/UniversalCompileAsyncWasmPlugin.js +29 -8
  616. package/lib/wasm-sync/SyncWasmModule.js +2 -2
  617. package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +18 -13
  618. package/lib/wasm-sync/WasmFinalizeExportsPlugin.js +4 -5
  619. package/lib/wasm-sync/WebAssemblyGenerator.js +18 -17
  620. package/lib/wasm-sync/WebAssemblyInInitialChunkError.js +4 -4
  621. package/lib/wasm-sync/WebAssemblyJavascriptGenerator.js +7 -7
  622. package/lib/wasm-sync/WebAssemblyModulesPlugin.js +24 -11
  623. package/lib/wasm-sync/WebAssemblyParser.js +4 -6
  624. package/lib/wasm-sync/WebAssemblyUtils.js +2 -2
  625. package/lib/web/FetchCompileAsyncWasmPlugin.js +105 -19
  626. package/lib/web/FetchCompileWasmPlugin.js +48 -16
  627. package/lib/web/JsonpChunkLoadingPlugin.js +47 -23
  628. package/lib/web/JsonpChunkLoadingRuntimeModule.js +50 -20
  629. package/lib/web/JsonpTemplatePlugin.js +2 -2
  630. package/lib/webpack.js +22 -11
  631. package/lib/webworker/ImportScriptsChunkLoadingPlugin.js +60 -26
  632. package/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js +30 -32
  633. package/lib/webworker/WebWorkerTemplatePlugin.js +1 -1
  634. package/module.d.ts +1 -0
  635. package/package.json +32 -25
  636. package/schemas/WebpackOptions.check.js +1 -1
  637. package/schemas/WebpackOptions.json +667 -34
  638. package/schemas/plugins/HtmlParserOptions.check.js +1 -1
  639. package/schemas/plugins/container/ContainerPlugin.check.js +1 -1
  640. package/schemas/plugins/container/ContainerPlugin.json +10 -0
  641. package/schemas/plugins/container/ModuleFederationPlugin.check.js +1 -1
  642. package/schemas/plugins/container/ModuleFederationPlugin.json +10 -0
  643. package/schemas/plugins/css/CssAutoOrModuleParserOptions.check.js +1 -1
  644. package/schemas/plugins/css/CssModuleParserOptions.check.js +1 -1
  645. package/schemas/plugins/css/CssParserOptions.check.js +1 -1
  646. package/types.d.ts +3223 -465
  647. package/lib/runtime/CommonJsWrapRuntimeModule.js +0 -37
@@ -75,24 +75,30 @@ const stringToNumber = (str, isLegacyOctal) =>
75
75
  */
76
76
  const stringToBigInt = (str) => BigInt(str.replace(/_/g, ""));
77
77
 
78
- /** @typedef {import("acorn").Options} Options */
79
- /** @typedef {import("acorn").Position} Position */
80
- /** @typedef {import("acorn").Node} Node */
81
- /** @typedef {import("acorn").Identifier} Identifier */
82
- /** @typedef {import("acorn").ImportAttribute} ImportAttribute */
83
- /** @typedef {import("acorn").ImportDefaultSpecifier} ImportDefaultSpecifier */
84
- /** @typedef {import("acorn").ImportExpression} ImportExpression */
85
- /** @typedef {import("acorn").Expression} Expression */
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
+ */
86
91
  /** @typedef {import("acorn").ImportSpecifier | import("acorn").ImportDefaultSpecifier | import("acorn").ImportNamespaceSpecifier} AnyImportSpecifier */
87
- /** @typedef {import("acorn").TokenType} TokenType */
88
- /** @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 */
89
- /** @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 */
90
93
  /** @typedef {[number, number]} Range */
91
94
  /** @typedef {"defer" | "source"} ImportPhase */
92
95
  /** @typedef {import("estree").Comment & { start: number, end: number }} CollectedComment comment as JavascriptParser exposes it */
93
96
 
94
97
  // Symbol-keyed so they stay out of for-in, Object.keys and JSON.stringify
95
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");
96
102
  const kSource = Symbol("source");
97
103
  const kRange = Symbol("range");
98
104
  const kText = Symbol("text");
@@ -102,12 +108,23 @@ const kTextStart = Symbol("text start");
102
108
  const LEGACY_ASSERT_ATTRIBUTES = Symbol("assert");
103
109
 
104
110
  // acorn's binding types and scope flags, stable across acorn 8
111
+ const BIND_NONE = 0;
105
112
  const BIND_VAR = 1;
106
113
  const BIND_LEXICAL = 2;
114
+ const BIND_OUTSIDE = 5;
107
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;
108
120
  const SCOPE_SIMPLE_CATCH = 32;
109
121
  // SCOPE_TOP | SCOPE_FUNCTION | SCOPE_CLASS_STATIC_BLOCK
122
+ const SCOPE_SWITCH = 1024;
110
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;
111
128
 
112
129
  // ASCII identifier-continuation chars ($ 0-9 A-Z _ a-z); css/html-style
113
130
  // Uint8Array table so the tokenizer fast path is one load per char
@@ -142,6 +159,18 @@ SIMPLE_PUNCT[123] = tokTypes.braceL;
142
159
  SIMPLE_PUNCT[125] = tokTypes.braceR;
143
160
  SIMPLE_PUNCT[58] = tokTypes.colon;
144
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
+
145
174
  // Char classification for the owned `nextToken` (yuku's ws_class): one table
146
175
  // load steers both the whitespace skip loop and the token dispatch. Token
147
176
  // classes sort below CLS_SPACE so the skip loop exits on a single compare.
@@ -631,6 +660,235 @@ class PropertyNode {
631
660
  }
632
661
  }
633
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
+
634
892
  /**
635
893
  * Single-shape `SpreadElement`/`RestElement` — identical field sets, so both
636
894
  * node types share one hidden class.
@@ -650,6 +908,10 @@ class RestSpreadNode {
650
908
  }
651
909
  }
652
910
 
911
+ // Mirrors of acorn's module-level `loopLabel`/`switchLabel`.
912
+ const LOOP_LABEL = { kind: "loop" };
913
+ const SWITCH_LABEL = { kind: "switch" };
914
+
653
915
  // Shared zero-length arguments array for `new X` without parens, mirroring
654
916
  // acorn's module-level `empty`.
655
917
  /** @type {Expression[]} */
@@ -715,7 +977,18 @@ for (const NodeClass of [
715
977
  TemplateElementNode,
716
978
  ObjectNode,
717
979
  PropertyNode,
718
- 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
719
992
  ]) {
720
993
  for (const key of ["range"]) {
721
994
  Object.defineProperty(
@@ -729,8 +1002,9 @@ for (const NodeClass of [
729
1002
 
730
1003
  /**
731
1004
  * Comment collected without slicing its text out of the source: only magic
732
- * comments and pure annotations ever get their text read, so the slice is
733
- * deferred to the first `value` access and memoized like `loc`.
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`.
734
1008
  */
735
1009
  class LazyComment {
736
1010
  /**
@@ -745,12 +1019,30 @@ class LazyComment {
745
1019
  this.type = block ? "Block" : "Line";
746
1020
  this.start = start;
747
1021
  this.end = end;
748
- /** @type {Range} */
749
- this.range = [start, end];
750
1022
  this[kSource] = source;
751
1023
  this[kTextStart] = textStart;
752
1024
  }
753
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
+
754
1046
  /**
755
1047
  * @returns {string} comment text without the delimiters
756
1048
  */
@@ -825,9 +1117,10 @@ class Scope {
825
1117
  * parseLiteral: (value: unknown) => Node,
826
1118
  * awaitIdentPos: number,
827
1119
  * lastTokStart: number,
1120
+ * lastTokStartLoc?: Position,
828
1121
  * yieldPos: number,
829
1122
  * awaitPos: number,
830
- * parseExpression: () => Expression,
1123
+ * parseExpression: (forInit?: boolean | string, refDestructuringErrors?: DestructuringErrorsShim | null) => Expression,
831
1124
  * parseSpread: (refDestructuringErrors?: DestructuringErrorsShim | null) => Node,
832
1125
  * braceIsBlock: (prevType: TokenType) => boolean,
833
1126
  * _gapHasNewline: () => boolean,
@@ -839,10 +1132,11 @@ class Scope {
839
1132
  * checkPatternErrors: (refDestructuringErrors: DestructuringErrorsShim, isAssign: boolean) => void,
840
1133
  * checkYieldAwaitInDefaultParams: () => void,
841
1134
  * checkExpressionErrors: (refDestructuringErrors?: DestructuringErrorsShim | null, andThrow?: boolean) => boolean,
842
- * parseSubscript: (base: Expression, startPos: number, startLoc: Position | undefined, noCalls: boolean | undefined, maybeAsyncArrow: boolean, optionalChained: boolean, forInit: boolean | string) => Expression,
1135
+ * parseSubscript: (base: Expression, startPos: number, startLoc: Position | undefined, noCalls: boolean | undefined, maybeAsyncArrow: boolean, optionalChained: boolean, forInit?: boolean | string) => Expression,
843
1136
  * parseExprAtom: (refDestructuringErrors?: DestructuringErrorsShim | null, forInit?: boolean | string, forNew?: boolean) => Expression,
844
1137
  * buildBinary: (startPos: number, startLoc: Position | undefined, left: Expression, right: Expression, op: string, logical: boolean) => Expression,
845
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,
846
1140
  * parseMaybeConditional: (forInit?: boolean | string, refDestructuringErrors?: DestructuringErrorsShim | null) => Expression,
847
1141
  * parseMaybeUnary: (refDestructuringErrors: DestructuringErrorsShim | null, sawUnary: boolean, incDec: boolean, forInit?: boolean | string) => Expression,
848
1142
  * parseExprSubscripts: (refDestructuringErrors?: DestructuringErrorsShim | null, forInit?: boolean | string) => Expression,
@@ -874,6 +1168,18 @@ class Scope {
874
1168
  * _propHashDepth: number,
875
1169
  * _acquireDestructuringErrors: () => DestructuringErrorsShim,
876
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,
877
1183
  * parseSubscripts: (base: Expression, startPos: number, startLoc: Position | undefined, noCalls?: boolean, forInit?: boolean | string) => Expression,
878
1184
  * parseNew: () => Expression,
879
1185
  * parseTemplateElement: (opts: { isTagged: boolean }) => Node,
@@ -890,7 +1196,9 @@ class Scope {
890
1196
  * parseFunction: (node: Node, statement: number, allowExpressionBody?: boolean, isAsync?: boolean, forInit?: boolean | string) => Expression,
891
1197
  * parseArrowExpression: (node: Node, params: Node[], isAsync: boolean, forInit?: boolean | string) => Expression,
892
1198
  * _subscriptFastPath: boolean,
893
- * 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,
894
1202
  * startNode: () => Node,
895
1203
  * startNodeAt: (pos: number, loc?: Position) => Node,
896
1204
  * finishNode: (node: Node, type: string) => Node,
@@ -916,6 +1224,7 @@ class Scope {
916
1224
  * _readNumberCold: (startsWithDot: boolean) => void,
917
1225
  * _readRadixNumber: (radix: number) => void,
918
1226
  * _readWord1Cold: () => string,
1227
+ * _finishWordSlow: (word: string) => void,
919
1228
  * _skipSpaceCold: () => void,
920
1229
  * _getUnknownOrPrivate: (code: number) => void,
921
1230
  * finishToken: (type: TokenType, value?: unknown) => void,
@@ -953,6 +1262,20 @@ class Scope {
953
1262
  * parseExprImport: (forNew: boolean) => Expression,
954
1263
  * parseImportMeta: (node: Node) => Expression,
955
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,
956
1279
  * _lazy: boolean,
957
1280
  * _importPhase: ImportPhase | null,
958
1281
  * _importPhasesEnabled: boolean,
@@ -960,13 +1283,53 @@ class Scope {
960
1283
  * _newlineBefore: 0 | 1 | 2,
961
1284
  * _fullTokenFastPath: boolean,
962
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,
963
1302
  * isLet: (context?: string | null) => boolean,
964
1303
  * parseLabeledStatement: (node: Node, maybeName: string, expr: Identifier, context: string | null) => Node,
965
- * _parseVarInto: (declarations: Node[], isFor: boolean, kind: string, allowMissingInitializer?: boolean) => void,
1304
+ * _parseVarInto: (declarations: Node[], isFor: boolean, kind: string, allowMissingInitializer?: boolean) => number,
966
1305
  * _parseVarStatementAt: (start: number, kind: string, allowMissingInitializer?: boolean) => Node,
967
1306
  * _parseIfStatementAt: (start: number) => Node,
968
1307
  * _parseReturnStatementAt: (start: number) => Node,
969
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,
970
1333
  * _moduleFallback: boolean,
971
1334
  * _moduleSyntaxSeen: boolean,
972
1335
  * _tryModuleFallback: () => boolean,
@@ -1044,6 +1407,10 @@ const createDestructuringErrors = () => {
1044
1407
  * @property {Map<string, ReservedKind>} reservedKinds identifier name → reserved kind
1045
1408
  * @property {number} reservedMaxLen longest key in `reservedKinds`
1046
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
1047
1414
  */
1048
1415
 
1049
1416
  // One entry per distinct keyword/reserved-word set; webpack parses with a
@@ -1052,20 +1419,6 @@ const createDestructuringErrors = () => {
1052
1419
  /** @type {Map<string, WordLookups>} */
1053
1420
  const wordLookupsCache = new Map();
1054
1421
 
1055
- /**
1056
- * @param {string} word interned candidate
1057
- * @param {string} input source code
1058
- * @param {number} start word start offset
1059
- * @param {number} len word length (already known equal to `word.length`)
1060
- * @returns {boolean} whether the source span spells `word`
1061
- */
1062
- const sameWord = (word, input, start, len) => {
1063
- for (let i = 0; i < len; i++) {
1064
- if (word.charCodeAt(i) !== input.charCodeAt(start + i)) return false;
1065
- }
1066
- return true;
1067
- };
1068
-
1069
1422
  // Direct-mapped identifier cache for `readWord1`: one slot per hash, verified
1070
1423
  // by char compare, overwritten on collision. Shared across parses — hits are
1071
1424
  // content-checked, so a stale entry is merely a miss. Only words short enough
@@ -1075,6 +1428,34 @@ const WORD_CACHE_MASK = 0x1fff;
1075
1428
  const WORD_CACHE = Array.from({ length: WORD_CACHE_MASK + 1 }, () => null);
1076
1429
  const WORD_CACHE_MAX_LEN = 12;
1077
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
+
1078
1459
  // Multi-char operator strings for `finishOp` (`=>`, `===`, `&&=`, …), keyed by
1079
1460
  // their char codes packed 7 bits apart — collision-free for ASCII operators up
1080
1461
  // to acorn's maximum of 4 chars (`>>>=`), so the set stays ~40 entries.
@@ -1093,9 +1474,9 @@ const VALID_REGEXP_FLAGS = new Map();
1093
1474
  const getValidRegexpFlags = (ecmaVersion) => {
1094
1475
  let flags = VALID_REGEXP_FLAGS.get(ecmaVersion);
1095
1476
  if (flags === undefined) {
1096
- flags = `gim${ecmaVersion >= 6 ? "uy" : ""}${
1097
- ecmaVersion >= 9 ? "s" : ""
1098
- }${ecmaVersion >= 13 ? "d" : ""}${ecmaVersion >= 15 ? "v" : ""}`;
1477
+ flags = `gim${ecmaVersion >= 6 ? "uy" : ""}${ecmaVersion >= 9 ? "s" : ""}${
1478
+ ecmaVersion >= 13 ? "d" : ""
1479
+ }${ecmaVersion >= 15 ? "v" : ""}`;
1099
1480
  VALID_REGEXP_FLAGS.set(ecmaVersion, flags);
1100
1481
  }
1101
1482
  return flags;
@@ -1172,6 +1553,14 @@ const getWordLookups = (parser) => {
1172
1553
  // keyword classification wins, matching acorn's keyword-first check
1173
1554
  for (const name of keywords.keys()) reservedKinds.set(name, 1);
1174
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
+ }
1175
1564
  let reservedMaxLen = 0;
1176
1565
  for (const name of reservedKinds.keys()) {
1177
1566
  if (name.length > reservedMaxLen) reservedMaxLen = name.length;
@@ -1181,7 +1570,11 @@ const getWordLookups = (parser) => {
1181
1570
  keywords,
1182
1571
  reservedKinds,
1183
1572
  reservedMaxLen,
1184
- reservedBindTest: { test: (name) => reservedBind.has(name) }
1573
+ reservedBindTest: { test: (name) => reservedBind.has(name) },
1574
+ reservedBindSet: reservedBind,
1575
+ reservedBindMinLen,
1576
+ reservedBindMaxLen,
1577
+ id: nextWordLookupsId++
1185
1578
  };
1186
1579
  wordLookupsCache.set(key, lookups);
1187
1580
  lastWordLookups = lookups;
@@ -1260,9 +1653,50 @@ class WebpackParser extends BaseParser {
1260
1653
  // the owned parseSubscript assumes optional chaining exists (it bakes
1261
1654
  // `optional` into the node shape), so gate it on the normalized version
1262
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);
1263
1678
  // the owned getTokenFromCode bakes in every ES2021 operator (?., ??=,
1264
- // &&=, ...), so it needs at least that version
1265
- this._fullTokenFastPath = lazy && this._ecmaVersion >= 12;
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;
1266
1700
  // whether the gap before the current token holds a line terminator:
1267
1701
  // 0 no, 1 yes, 2 unknown (canInsertSemicolon then scans the gap)
1268
1702
  /** @type {0 | 1 | 2} */
@@ -1281,11 +1715,16 @@ class WebpackParser extends BaseParser {
1281
1715
  /** @type {{ proto: boolean }[]} */
1282
1716
  this._propHashStack = [];
1283
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;
1284
1724
  // `readRegexp`'s flag whitelist depends only on the ecmaVersion
1285
1725
  this._validRegexpFlags = getValidRegexpFlags(this._ecmaVersion);
1286
1726
  // the owned parseStatement inlines these methods, so a parser plugin
1287
1727
  // overriding any of them turns the statement fast path off
1288
- const proto = WebpackParser.prototype;
1289
1728
  this._stmtFastPath =
1290
1729
  lazy &&
1291
1730
  this.parseVarStatement === proto.parseVarStatement &&
@@ -1293,6 +1732,62 @@ class WebpackParser extends BaseParser {
1293
1732
  this.parseIfStatement === proto.parseIfStatement &&
1294
1733
  this.parseReturnStatement === proto.parseReturnStatement &&
1295
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;
1296
1791
  }
1297
1792
 
1298
1793
  /**
@@ -1327,15 +1822,42 @@ class WebpackParser extends BaseParser {
1327
1822
  this._deDepth--;
1328
1823
  }
1329
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
+
1330
1851
  // ----- tokenizer fast paths -----
1331
1852
 
1332
1853
  /**
1333
1854
  * Owned per-token loop: acorn's `nextToken` chains `skipSpace` →
1334
1855
  * `fullCharCodeAtPos` → `readToken` → `isIdentifierStart` with a dead
1335
- * `locations` check at each step. For the common lazy, non-template context
1856
+ * `locations` check at each step. For the common non-template context of
1857
+ * `_tokenFastPath` mode (lazy, or locations-off with no tokenizer overrides)
1336
1858
  * this folds whitespace and comment skipping and the ASCII token dispatch
1337
1859
  * into one function so nothing re-enters acorn's per-step option checks.
1338
- * Template/`preserveSpace` contexts and non-lazy mode use acorn's tokenizer.
1860
+ * Template/`preserveSpace` contexts and other modes use acorn's tokenizer.
1339
1861
  * acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
1340
1862
  * @returns {void}
1341
1863
  * @this {ParserInternals}
@@ -1343,12 +1865,19 @@ class WebpackParser extends BaseParser {
1343
1865
  nextToken() {
1344
1866
  const context = this.context;
1345
1867
  const curContext = context[context.length - 1];
1346
- if (
1347
- !this._lazy ||
1348
- !curContext ||
1349
- curContext.preserveSpace ||
1350
- curContext.override
1351
- ) {
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) {
1352
1881
  this._newlineBefore = 2;
1353
1882
  return base.nextToken.call(this);
1354
1883
  }
@@ -1412,9 +1941,71 @@ class WebpackParser extends BaseParser {
1412
1941
  switch (cls) {
1413
1942
  case CLS_IDENT:
1414
1943
  return this.readWord();
1415
- case CLS_PUNCT:
1944
+ case CLS_PUNCT: {
1945
+ const type = /** @type {TokenType} */ (SIMPLE_PUNCT[code]);
1416
1946
  this.pos = pos + 1;
1417
- return this.finishToken(/** @type {TokenType} */ (SIMPLE_PUNCT[code]));
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
+ }
1418
2009
  case CLS_DOT: {
1419
2010
  // `.` not starting `.5` or `...`: skip readToken_dot's re-dispatch
1420
2011
  const next = input.charCodeAt(pos + 1);
@@ -1441,10 +2032,10 @@ class WebpackParser extends BaseParser {
1441
2032
  }
1442
2033
 
1443
2034
  /**
1444
- * Lazy-mode `finishToken`: acorn probes `options.locations` for a dead
1445
- * `endLoc` write on every token and reaches `updateContext` through an extra
1446
- * method call. Skip the probe and inline acorn's `updateContext` body — this
1447
- * 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.
1448
2039
  * acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
1449
2040
  * @param {TokenType} type token type
1450
2041
  * @param {unknown=} value token value
@@ -1452,7 +2043,7 @@ class WebpackParser extends BaseParser {
1452
2043
  * @this {ParserInternals}
1453
2044
  */
1454
2045
  finishToken(type, value) {
1455
- if (!this._lazy) {
2046
+ if (!this._tokenFastPath) {
1456
2047
  return base.finishToken.call(this, type, value);
1457
2048
  }
1458
2049
  this.end = this.pos;
@@ -1471,41 +2062,53 @@ class WebpackParser extends BaseParser {
1471
2062
  (value === "yield" && this.inGeneratorContext())) &&
1472
2063
  prevType !== tokTypes.dot &&
1473
2064
  this._ecmaVersion >= 6;
1474
- } else if (type.keyword && prevType === tokTypes.dot) {
1475
- this.exprAllowed = false;
1476
- } else if (type === tokTypes.parenR || type === tokTypes.braceR) {
1477
- // parenR/braceR.updateContext, inlined
1478
- const context = this.context;
1479
- if (context.length === 1) {
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
+ );
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);
1480
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;
1481
2109
  } else {
1482
- let out = /** @type {TokContextShim} */ (context.pop());
1483
- if (
1484
- out === CTX_B_STAT &&
1485
- /** @type {TokContextShim} */ (context[context.length - 1]).token ===
1486
- "function"
1487
- ) {
1488
- out = /** @type {TokContextShim} */ (context.pop());
1489
- }
1490
- this.exprAllowed = !out.isExpr;
1491
- }
1492
- } else if (type === tokTypes.braceL) {
1493
- // braceL.updateContext, inlined
1494
- this.context.push(this.braceIsBlock(prevType) ? CTX_B_STAT : CTX_B_EXPR);
1495
- this.exprAllowed = true;
1496
- } else if (type === tokTypes.parenL) {
1497
- // parenL.updateContext, inlined
1498
- const statementParens =
1499
- prevType === tokTypes._if ||
1500
- prevType === tokTypes._for ||
1501
- prevType === tokTypes._with ||
1502
- prevType === tokTypes._while;
1503
- this.context.push(statementParens ? CTX_P_STAT : CTX_P_EXPR);
1504
- this.exprAllowed = true;
1505
- } else if (internal.updateContext) {
1506
- internal.updateContext.call(this, prevType);
1507
- } else {
1508
- this.exprAllowed = internal.beforeExpr;
2110
+ update.call(this, prevType);
2111
+ }
1509
2112
  }
1510
2113
  }
1511
2114
 
@@ -1585,19 +2188,21 @@ class WebpackParser extends BaseParser {
1585
2188
  /**
1586
2189
  * Owned per-token advance: acorn's `next` writes `lastTokEndLoc`/
1587
2190
  * `lastTokStartLoc` and probes `options.onToken` on every token, both dead in
1588
- * lazy mode (locations off, no token stream), leaving only the two offset
1589
- * 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.
1590
2193
  * acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
1591
2194
  * @param {boolean=} ignoreEscapeSequenceInKeyword whether an escape in a keyword is allowed here
1592
2195
  * @returns {void}
1593
2196
  * @this {ParserInternals}
1594
2197
  */
1595
2198
  next(ignoreEscapeSequenceInKeyword) {
1596
- if (!this._lazy) {
2199
+ if (!this._tokenFastPath) {
1597
2200
  return base.next.call(this, ignoreEscapeSequenceInKeyword);
1598
2201
  }
1599
2202
  const type = this.type;
1600
- if (!ignoreEscapeSequenceInKeyword && type.keyword && this.containsEsc) {
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) {
1601
2206
  this.raiseRecoverable(
1602
2207
  this.start,
1603
2208
  `Escape sequence in keyword ${type.keyword}`
@@ -1986,12 +2591,15 @@ class WebpackParser extends BaseParser {
1986
2591
  if (
1987
2592
  cached !== null &&
1988
2593
  cached.length === wordLen &&
1989
- sameWord(cached, input, start, wordLen)
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)
1990
2597
  ) {
1991
2598
  return cached;
1992
2599
  }
1993
2600
  const word = input.slice(start, pos);
1994
2601
  WORD_CACHE[slot] = word;
2602
+ WORD_TYPE_OWNERS[slot] = 0;
1995
2603
  return word;
1996
2604
  }
1997
2605
  return input.slice(start, pos);
@@ -2758,36 +3366,113 @@ class WebpackParser extends BaseParser {
2758
3366
  // ----- word classification (Map/Set lookups, replaces acorn's regexps) -----
2759
3367
 
2760
3368
  /**
2761
- * Replaces acorn's `readWord`, whose `this.keywords.test(word)` runs an
2762
- * anchored alternation regexp for every identifier and keyword token; a
2763
- * Map lookup on the same keyword set is cheaper.
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.
2764
3373
  * acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/tokenize.js
2765
3374
  * @this {ParserInternals}
2766
3375
  * @returns {void}
2767
3376
  */
2768
3377
  readWord() {
2769
- const word = this.readWord1();
2770
- let type = tokTypes.name;
2771
- const len = word.length;
2772
- // every acorn keyword is 2-10 lowercase ASCII chars (`do`…`instanceof`),
2773
- // so most identifiers skip the Map probe entirely (yuku gates its keyword
2774
- // switch the same way)
2775
- if (len >= 2 && len <= 10) {
2776
- const first = word.charCodeAt(0);
2777
- if (first >= 97 && first <= 122) {
2778
- type = this._wordLookups.keywords.get(word) || tokTypes.name;
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());
2779
3395
  }
2780
3396
  }
2781
- this.finishToken(type, word);
2782
- }
2783
-
2784
- /**
2785
- * Mirror of acorn's `checkUnreserved` with its two per-identifier regexp
2786
- * tests (`keywords` and `reservedWords`/`reservedWordsStrict`) folded into a
2787
- * single `reservedKinds` lookup — one hash probe instead of two, and the
2788
- * common plain identifier misses it and returns. Branches and error
2789
- * messages match acorn exactly.
2790
- * acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
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
+ }
3468
+
3469
+ /**
3470
+ * Mirror of acorn's `checkUnreserved` with its two per-identifier regexp
3471
+ * tests (`keywords` and `reservedWords`/`reservedWordsStrict`) folded into a
3472
+ * single `reservedKinds` lookup — one hash probe instead of two, and the
3473
+ * common plain identifier misses it and returns. Branches and error
3474
+ * messages match acorn exactly.
3475
+ * acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
2791
3476
  * @param {Identifier} ref identifier node
2792
3477
  * @this {ParserInternals}
2793
3478
  */
@@ -2850,6 +3535,162 @@ class WebpackParser extends BaseParser {
2850
3535
  }
2851
3536
  }
2852
3537
 
3538
+ /**
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}
3548
+ * @this {ParserInternals}
3549
+ */
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;
3593
+ }
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`);
3620
+ }
3621
+
3622
+ /**
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
3629
+ * @returns {void}
3630
+ * @this {ParserInternals}
3631
+ */
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
+
2853
3694
  /**
2854
3695
  * Replaces acorn's `canInsertSemicolon`, whose line-break check slices the
2855
3696
  * inter-token gap and runs a regexp on it for every ASI decision (hundreds
@@ -3016,6 +3857,79 @@ class WebpackParser extends BaseParser {
3016
3857
  return node;
3017
3858
  }
3018
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
+
3019
3933
  /**
3020
3934
  * Owned `parseSubscript`, an exact-semantics copy of acorn 8's with the
3021
3935
  * node construction replaced: member and call nodes are built fully-formed
@@ -3201,17 +4115,65 @@ class WebpackParser extends BaseParser {
3201
4115
  case tokTypes.braceL:
3202
4116
  // the owned parseBlock never reads the started node
3203
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
+ }
3204
4140
  case tokTypes._break:
3205
4141
  case tokTypes._continue:
3206
- case tokTypes._debugger:
3207
- case tokTypes._do:
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
+ );
3208
4149
  case tokTypes._for:
3209
- case tokTypes._function:
3210
- case tokTypes._class:
4150
+ if (!this._stmt2FastPath) {
4151
+ return base.parseStatement.call(this, context, topLevel, exports);
4152
+ }
4153
+ return this._parseForStatementAt(this.start);
3211
4154
  case tokTypes._switch:
4155
+ if (!this._stmt2FastPath) {
4156
+ return base.parseStatement.call(this, context, topLevel, exports);
4157
+ }
4158
+ return this._parseSwitchStatementAt(this.start);
3212
4159
  case tokTypes._throw:
4160
+ if (!this._stmt2FastPath) {
4161
+ return base.parseStatement.call(this, context, topLevel, exports);
4162
+ }
4163
+ return this._parseThrowStatementAt(this.start);
3213
4164
  case tokTypes._try:
4165
+ if (!this._stmt2FastPath) {
4166
+ return base.parseStatement.call(this, context, topLevel, exports);
4167
+ }
4168
+ return this._parseTryStatementAt(this.start);
3214
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:
3215
4177
  case tokTypes._with:
3216
4178
  case tokTypes.semi:
3217
4179
  case tokTypes._export:
@@ -3294,9 +4256,14 @@ class WebpackParser extends BaseParser {
3294
4256
  */
3295
4257
  _parseVarStatementAt(start, kind, allowMissingInitializer) {
3296
4258
  this.next();
3297
- /** @type {Node[]} */
3298
- const declarations = [];
3299
- this._parseVarInto(declarations, false, kind, allowMissingInitializer);
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);
3300
4267
  this.semicolon();
3301
4268
  return /** @type {Node} */ (
3302
4269
  /** @type {unknown} */ (
@@ -3328,13 +4295,23 @@ class WebpackParser extends BaseParser {
3328
4295
  allowMissingInitializer
3329
4296
  );
3330
4297
  }
3331
- /** @type {Node[]} */
3332
- const declarations = [];
3333
4298
  const target =
3334
- /** @type {Node & { declarations: Node[], kind: string }} */ (node);
3335
- target.declarations = declarations;
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;
3336
4306
  target.kind = kind;
3337
- this._parseVarInto(declarations, isFor, kind, allowMissingInitializer);
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);
3338
4315
  return node;
3339
4316
  }
3340
4317
 
@@ -3342,16 +4319,17 @@ class WebpackParser extends BaseParser {
3342
4319
  * The declarator loop of the owned `parseVar`, shared with the owned
3343
4320
  * `parseStatement`'s node-free statement path.
3344
4321
  * acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
3345
- * @param {Node[]} declarations output array for the declarators
4322
+ * @param {Node[]} declarations scratch array for the declarators
3346
4323
  * @param {boolean} isFor whether parsing a `for` head
3347
4324
  * @param {string} kind declaration kind
3348
4325
  * @param {boolean=} allowMissingInitializer whether `const x;` is allowed
3349
- * @returns {void}
4326
+ * @returns {number} number of declarators written
3350
4327
  * @this {ParserInternals}
3351
4328
  */
3352
4329
  _parseVarInto(declarations, isFor, kind, allowMissingInitializer) {
3353
4330
  const ecmaVersion = this._ecmaVersion;
3354
4331
  const usingKind = kind === "using" || kind === "await using";
4332
+ let count = 0;
3355
4333
  for (;;) {
3356
4334
  const declStart = this.start;
3357
4335
  const id = usingKind ? this.parseIdent() : this.parseBindingAtom();
@@ -3394,15 +4372,14 @@ class WebpackParser extends BaseParser {
3394
4372
  "Complex binding patterns require an initialization value"
3395
4373
  );
3396
4374
  }
3397
- declarations.push(
3398
- /** @type {Node} */ (
3399
- /** @type {unknown} */ (
3400
- new VariableDeclaratorNode(declStart, this.lastTokEnd, id, init)
3401
- )
4375
+ declarations[count++] = /** @type {Node} */ (
4376
+ /** @type {unknown} */ (
4377
+ new VariableDeclaratorNode(declStart, this.lastTokEnd, id, init)
3402
4378
  )
3403
4379
  );
3404
4380
  if (!this.eat(tokTypes.comma)) break;
3405
4381
  }
4382
+ return count;
3406
4383
  }
3407
4384
 
3408
4385
  /**
@@ -3460,19 +4437,23 @@ class WebpackParser extends BaseParser {
3460
4437
  }
3461
4438
  if (createNewLexicalScope === undefined) createNewLexicalScope = true;
3462
4439
  const start = this.start;
3463
- /** @type {Node[]} */
3464
- const body = [];
4440
+ const scratch = this._acquireScratch();
4441
+ let count = 0;
3465
4442
  this.expect(tokTypes.braceL);
3466
4443
  if (createNewLexicalScope) this.enterScope(0);
3467
4444
  while (this.type !== tokTypes.braceR) {
3468
- body.push(this.parseStatement(null));
4445
+ scratch[count++] = this.parseStatement(null);
3469
4446
  }
3470
4447
  if (exitStrict) this.strict = false;
3471
4448
  this.next();
3472
4449
  if (createNewLexicalScope) this.exitScope();
3473
4450
  return /** @type {Node} */ (
3474
4451
  /** @type {unknown} */ (
3475
- new BlockStatementNode(start, this.lastTokEnd, body)
4452
+ new BlockStatementNode(
4453
+ start,
4454
+ this.lastTokEnd,
4455
+ this._releaseScratch(scratch, count)
4456
+ )
3476
4457
  )
3477
4458
  );
3478
4459
  }
@@ -3538,109 +4519,1159 @@ class WebpackParser extends BaseParser {
3538
4519
  */
3539
4520
  _tryModuleFallback() {
3540
4521
  if (
3541
- !this._moduleFallback ||
3542
- this._moduleSyntaxSeen ||
3543
- !(this.currentVarScope().flags & SCOPE_TOP)
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
+
5526
+ if (
5527
+ canBeArrow &&
5528
+ this.shouldParseArrow(exprList) &&
5529
+ this.eat(tokTypes.arrow)
3544
5530
  ) {
3545
- return false;
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);
3546
5539
  }
3547
- this.options.allowReturnOutsideFunction = true;
3548
- // acorn stamps Program.sourceType from this at parseTopLevel's end
3549
- this.options.sourceType = "script";
3550
- this.strict = false;
3551
- this.inModule = false;
3552
- this._moduleFallback = false;
3553
- return true;
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;
3554
5580
  }
3555
5581
 
3556
5582
  /**
3557
- * `parseReturnStatement` without a started node.
3558
- * acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/statement.js
3559
- * @param {number} start statement start offset
3560
- * @returns {Node} return statement
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
3561
5589
  * @this {ParserInternals}
3562
5590
  */
3563
- _parseReturnStatementAt(start) {
3564
- if (!this.allowReturn && !this._tryModuleFallback()) {
3565
- this.raise(this.start, "'return' outside of function");
3566
- }
3567
- this.next();
3568
- /** @type {Expression | null} */
3569
- let argument = null;
3570
- // `return` takes an optional argument, so eagerly look for a semicolon
3571
- if (!(this.eat(tokTypes.semi) || this.insertSemicolon())) {
3572
- argument = this.parseExpression();
3573
- 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;
3574
5601
  }
3575
- return /** @type {Node} */ (
3576
- /** @type {unknown} */ (
3577
- new ReturnStatementNode(start, this.lastTokEnd, argument)
3578
- )
3579
- );
5602
+ return false;
3580
5603
  }
3581
5604
 
3582
5605
  /**
3583
- * Owned `parseSpread` landing on `RestSpreadNode`'s single shape.
3584
- * Non-lazy mode delegates.
3585
- * acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/lval.js
3586
- * @param {DestructuringErrorsShim | null=} refDestructuringErrors destructuring errors to fill
3587
- * @returns {Node} spread element
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
3588
5612
  * @this {ParserInternals}
3589
5613
  */
3590
- parseSpread(refDestructuringErrors) {
3591
- if (!this._lazy) {
3592
- return base.parseSpread.call(this, refDestructuringErrors);
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
+ );
3593
5624
  }
3594
- const start = this.start;
3595
- this.next();
3596
- const argument = this.parseMaybeAssign(false, refDestructuringErrors);
3597
- return /** @type {Node} */ (
3598
- /** @type {unknown} */ (
3599
- new RestSpreadNode(start, this.lastTokEnd, "SpreadElement", argument)
3600
- )
3601
- );
5625
+ if (doubleProto >= 0) {
5626
+ this.raiseRecoverable(doubleProto, "Redefinition of __proto__ property");
5627
+ }
5628
+ return false;
3602
5629
  }
3603
5630
 
3604
5631
  /**
3605
- * Owned `parseMaybeConditional` landing on
3606
- * `ConditionalExpressionNode`'s single shape. Non-lazy mode delegates.
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.
3607
5635
  * acorn source: https://github.com/acornjs/acorn/blob/8.17.0/acorn/src/expression.js
3608
5636
  * @param {boolean | string=} forInit for-init context flag
3609
5637
  * @param {DestructuringErrorsShim | null=} refDestructuringErrors destructuring errors to fill
3610
5638
  * @returns {Expression} expression node
3611
5639
  * @this {ParserInternals}
3612
5640
  */
3613
- parseMaybeConditional(forInit, refDestructuringErrors) {
5641
+ parseExpression(forInit, refDestructuringErrors) {
3614
5642
  if (!this._lazy) {
3615
- return base.parseMaybeConditional.call(
3616
- this,
3617
- forInit,
3618
- refDestructuringErrors
3619
- );
5643
+ return base.parseExpression.call(this, forInit, refDestructuringErrors);
3620
5644
  }
3621
- const startPos = this.start;
3622
- const expr = this.parseExprOps(forInit, refDestructuringErrors);
3623
- if (this.checkExpressionErrors(refDestructuringErrors)) return expr;
3624
- if (
3625
- !(expr.type === "ArrowFunctionExpression" && expr.start === startPos) &&
3626
- this.eat(tokTypes.question)
3627
- ) {
3628
- const consequent = this.parseMaybeAssign();
3629
- this.expect(tokTypes.colon);
3630
- const alternate = this.parseMaybeAssign(forInit);
3631
- return /** @type {Expression} */ (
3632
- /** @type {unknown} */ (
3633
- new ConditionalExpressionNode(
3634
- startPos,
3635
- this.lastTokEnd,
3636
- expr,
3637
- consequent,
3638
- alternate
3639
- )
3640
- )
3641
- );
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;
3642
5674
  }
3643
- return expr;
3644
5675
  }
3645
5676
 
3646
5677
  /**
@@ -3786,27 +5817,31 @@ class WebpackParser extends BaseParser {
3786
5817
  const isTagged = (opts !== undefined && opts.isTagged) === true;
3787
5818
  const start = this.start;
3788
5819
  this.next();
3789
- /** @type {Expression[]} */
3790
- const expressions = [];
5820
+ const exprScratch = this._acquireScratch();
5821
+ const quasiScratch = this._acquireScratch();
5822
+ let exprCount = 0;
5823
+ let quasiCount = 0;
3791
5824
  // one options object for all chunks (only `isTagged` is ever read)
3792
5825
  const eltOpts = { isTagged };
3793
5826
  let curElt = /** @type {Node & { tail?: boolean }} */ (
3794
5827
  this.parseTemplateElement(eltOpts)
3795
5828
  );
3796
- const quasis = [/** @type {Node} */ (curElt)];
5829
+ quasiScratch[quasiCount++] = curElt;
3797
5830
  while (!curElt.tail) {
3798
5831
  if (this.type === tokTypes.eof) {
3799
5832
  this.raise(this.pos, "Unterminated template literal");
3800
5833
  }
3801
5834
  this.expect(tokTypes.dollarBraceL);
3802
- expressions.push(this.parseExpression());
5835
+ exprScratch[exprCount++] = this.parseExpression();
3803
5836
  this.expect(tokTypes.braceR);
3804
5837
  curElt = /** @type {Node & { tail?: boolean }} */ (
3805
5838
  this.parseTemplateElement(eltOpts)
3806
5839
  );
3807
- quasis.push(/** @type {Node} */ (curElt));
5840
+ quasiScratch[quasiCount++] = curElt;
3808
5841
  }
3809
5842
  this.next();
5843
+ const quasis = this._releaseScratch(quasiScratch, quasiCount);
5844
+ const expressions = this._releaseScratch(exprScratch, exprCount);
3810
5845
  return /** @type {Node} */ (
3811
5846
  /** @type {unknown} */ (
3812
5847
  new TemplateLiteralNode(start, this.lastTokEnd, expressions, quasis)
@@ -3931,6 +5966,57 @@ class WebpackParser extends BaseParser {
3931
5966
  return expr;
3932
5967
  }
3933
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
+
3934
6020
  /**
3935
6021
  * Owned `parseMaybeAssign`, an exact-semantics copy of acorn 8's: the
3936
6022
  * operator is captured before `next()` and the `AssignmentExpression` is
@@ -3952,6 +6038,10 @@ class WebpackParser extends BaseParser {
3952
6038
  afterLeftParse
3953
6039
  );
3954
6040
  }
6041
+ if (this._exprFastPath && afterLeftParse === undefined) {
6042
+ const atom = this._parseTrivialAtom(forInit);
6043
+ if (atom !== null) return atom;
6044
+ }
3955
6045
  if (this.isContextual("yield")) {
3956
6046
  if (this.inGenerator) return this.parseYield(forInit);
3957
6047
  // the tokenizer assumed an expression follows `yield`, but this
@@ -4052,7 +6142,10 @@ class WebpackParser extends BaseParser {
4052
6142
  forInit
4053
6143
  );
4054
6144
  if (this.checkExpressionErrors(refDestructuringErrors)) return expr;
4055
- return expr.start === startPos && expr.type === "ArrowFunctionExpression"
6145
+ const isArrow = this._arrowFastPath
6146
+ ? expr === this._lastArrow && expr.start === startPos
6147
+ : expr.start === startPos && expr.type === "ArrowFunctionExpression";
6148
+ return isArrow
4056
6149
  ? expr
4057
6150
  : this.parseExprOp(expr, startPos, startLoc, -1, forInit);
4058
6151
  }
@@ -4346,8 +6439,8 @@ class WebpackParser extends BaseParser {
4346
6439
  } else {
4347
6440
  propHash = {};
4348
6441
  }
4349
- /** @type {Node[]} */
4350
- const properties = [];
6442
+ const scratch = this._acquireScratch();
6443
+ let count = 0;
4351
6444
  this.next();
4352
6445
  while (!this.eat(tokTypes.braceR)) {
4353
6446
  if (!first) {
@@ -4360,7 +6453,7 @@ class WebpackParser extends BaseParser {
4360
6453
  if (!isPattern) {
4361
6454
  this.checkPropClash(prop, propHash, refDestructuringErrors);
4362
6455
  }
4363
- properties.push(prop);
6456
+ scratch[count++] = prop;
4364
6457
  }
4365
6458
  if (pooled) this._propHashDepth--;
4366
6459
  return /** @type {Node} */ (
@@ -4369,7 +6462,7 @@ class WebpackParser extends BaseParser {
4369
6462
  start,
4370
6463
  this.lastTokEnd,
4371
6464
  isPattern ? "ObjectPattern" : "ObjectExpression",
4372
- properties
6465
+ this._releaseScratch(scratch, count)
4373
6466
  )
4374
6467
  )
4375
6468
  );
@@ -4956,7 +7049,7 @@ class WebpackParser extends BaseParser {
4956
7049
  }
4957
7050
  }
4958
7051
 
4959
- /** @typedef {import("../Dependency").SourcePosition} SourcePosition */
7052
+ /** @import { SourcePosition } from "../Dependency" */
4960
7053
 
4961
7054
  /**
4962
7055
  * Whether a raw string literal contains a legacy octal (`\47`, `\0` followed by
@@ -4990,13 +7083,13 @@ const hasOctalEscape = (raw) => {
4990
7083
  // these two helpers.
4991
7084
 
4992
7085
  /**
4993
- * Offset of each line's first character. Char-code scan matching acorn's
4994
- * `lineBreak` semantics (CRLF is one break): a regex `exec` loop here
4995
- * allocates a match array per line.
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.
4996
7089
  * @param {string} source source code
4997
7090
  * @returns {number[]} line start offsets
4998
7091
  */
4999
- const buildLineStarts = (source) => {
7092
+ const scanLineStarts = (source) => {
5000
7093
  const len = source.length;
5001
7094
  const lineStarts = [0];
5002
7095
  for (let i = 0; i < len; i++) {
@@ -5013,6 +7106,33 @@ const buildLineStarts = (source) => {
5013
7106
  return lineStarts;
5014
7107
  };
5015
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
+
5016
7136
  /**
5017
7137
  * Binary search for the line containing the offset.
5018
7138
  * @param {number[]} lineStarts line start offsets
@@ -5030,8 +7150,334 @@ const positionAt = (lineStarts, offset) => {
5030
7150
  return { line: lo + 1, column: offset - lineStarts[lo] };
5031
7151
  };
5032
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
+
5033
7477
  module.exports.LEGACY_ASSERT_ATTRIBUTES = LEGACY_ASSERT_ATTRIBUTES;
5034
7478
  module.exports.WebpackParser = WebpackParser;
5035
7479
  module.exports.buildLineStarts = buildLineStarts;
7480
+ module.exports.collectCjsRequireSpecifiers = collectCjsRequireSpecifiers;
5036
7481
  module.exports.hasOctalEscape = hasOctalEscape;
7482
+ module.exports.isIdentifierChar = isIdentifierChar;
5037
7483
  module.exports.positionAt = positionAt;