webpack 5.97.1 → 5.104.1

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 (610) hide show
  1. package/README.md +368 -434
  2. package/bin/webpack.js +15 -9
  3. package/hot/dev-server.js +18 -3
  4. package/hot/emitter-event-target.js +7 -0
  5. package/hot/lazy-compilation-node.js +45 -29
  6. package/hot/lazy-compilation-universal.js +18 -0
  7. package/hot/lazy-compilation-web.js +15 -5
  8. package/hot/load-http.js +7 -0
  9. package/hot/log.js +15 -15
  10. package/hot/only-dev-server.js +19 -4
  11. package/hot/poll.js +1 -0
  12. package/lib/APIPlugin.js +48 -50
  13. package/lib/AbstractMethodError.js +1 -0
  14. package/lib/AsyncDependenciesBlock.js +4 -5
  15. package/lib/AutomaticPrefetchPlugin.js +22 -22
  16. package/lib/BannerPlugin.js +35 -40
  17. package/lib/Cache.js +12 -9
  18. package/lib/CacheFacade.js +13 -13
  19. package/lib/CaseSensitiveModulesWarning.js +6 -6
  20. package/lib/Chunk.js +68 -47
  21. package/lib/ChunkGraph.js +174 -95
  22. package/lib/ChunkGroup.js +32 -24
  23. package/lib/ChunkTemplate.js +8 -8
  24. package/lib/CleanPlugin.js +90 -42
  25. package/lib/CodeGenerationResults.js +12 -9
  26. package/lib/CompatibilityPlugin.js +70 -21
  27. package/lib/Compilation.js +827 -550
  28. package/lib/Compiler.js +137 -109
  29. package/lib/ConcatenationScope.js +45 -8
  30. package/lib/ConditionalInitFragment.js +1 -1
  31. package/lib/ConstPlugin.js +89 -59
  32. package/lib/ContextExclusionPlugin.js +5 -4
  33. package/lib/ContextModule.js +66 -51
  34. package/lib/ContextModuleFactory.js +51 -30
  35. package/lib/ContextReplacementPlugin.js +89 -34
  36. package/lib/CssModule.js +8 -4
  37. package/lib/DefinePlugin.js +209 -57
  38. package/lib/DelegatedModule.js +34 -23
  39. package/lib/DelegatedModuleFactoryPlugin.js +27 -24
  40. package/lib/DelegatedPlugin.js +4 -2
  41. package/lib/DependenciesBlock.js +0 -2
  42. package/lib/Dependency.js +37 -19
  43. package/lib/DependencyTemplate.js +2 -0
  44. package/lib/DependencyTemplates.js +5 -6
  45. package/lib/DllEntryPlugin.js +8 -4
  46. package/lib/DllModule.js +11 -12
  47. package/lib/DllModuleFactory.js +2 -2
  48. package/lib/DllPlugin.js +9 -6
  49. package/lib/DllReferencePlugin.js +60 -65
  50. package/lib/DotenvPlugin.js +462 -0
  51. package/lib/DynamicEntryPlugin.js +8 -8
  52. package/lib/EntryOptionPlugin.js +8 -6
  53. package/lib/EntryPlugin.js +5 -3
  54. package/lib/Entrypoint.js +19 -0
  55. package/lib/EnvironmentNotSupportAsyncWarning.js +0 -3
  56. package/lib/EnvironmentPlugin.js +26 -19
  57. package/lib/ErrorHelpers.js +6 -6
  58. package/lib/EvalDevToolModulePlugin.js +17 -14
  59. package/lib/EvalSourceMapDevToolPlugin.js +156 -142
  60. package/lib/ExportsInfo.js +180 -115
  61. package/lib/ExportsInfoApiPlugin.js +2 -2
  62. package/lib/ExternalModule.js +256 -102
  63. package/lib/ExternalModuleFactoryPlugin.js +66 -29
  64. package/lib/ExternalsPlugin.js +57 -2
  65. package/lib/FileSystemInfo.js +313 -247
  66. package/lib/FlagAllModulesAsUsedPlugin.js +2 -2
  67. package/lib/FlagDependencyExportsPlugin.js +29 -19
  68. package/lib/FlagDependencyUsagePlugin.js +9 -10
  69. package/lib/FlagEntryExportAsUsedPlugin.js +1 -1
  70. package/lib/Generator.js +43 -10
  71. package/lib/GraphHelpers.js +11 -3
  72. package/lib/HookWebpackError.js +35 -7
  73. package/lib/HotModuleReplacementPlugin.js +149 -108
  74. package/lib/HotUpdateChunk.js +0 -3
  75. package/lib/IgnoreErrorModuleFactory.js +2 -2
  76. package/lib/IgnorePlugin.js +16 -13
  77. package/lib/IgnoreWarningsPlugin.js +6 -4
  78. package/lib/InitFragment.js +41 -23
  79. package/lib/InvalidDependenciesModuleWarning.js +2 -3
  80. package/lib/JavascriptMetaInfoPlugin.js +2 -4
  81. package/lib/LibManifestPlugin.js +12 -13
  82. package/lib/LoaderOptionsPlugin.js +12 -14
  83. package/lib/LoaderTargetPlugin.js +5 -3
  84. package/lib/MainTemplate.js +18 -29
  85. package/lib/ManifestPlugin.js +235 -0
  86. package/lib/Module.js +138 -60
  87. package/lib/ModuleBuildError.js +4 -2
  88. package/lib/ModuleDependencyError.js +4 -3
  89. package/lib/ModuleDependencyWarning.js +4 -3
  90. package/lib/ModuleError.js +1 -1
  91. package/lib/ModuleFactory.js +10 -3
  92. package/lib/ModuleFilenameHelpers.js +63 -60
  93. package/lib/ModuleGraph.js +195 -70
  94. package/lib/ModuleGraphConnection.js +14 -20
  95. package/lib/ModuleInfoHeaderPlugin.js +15 -16
  96. package/lib/ModuleNotFoundError.js +1 -1
  97. package/lib/ModuleParseError.js +8 -4
  98. package/lib/ModuleSourceTypeConstants.js +189 -0
  99. package/lib/ModuleTemplate.js +7 -8
  100. package/lib/ModuleTypeConstants.js +37 -15
  101. package/lib/ModuleWarning.js +1 -1
  102. package/lib/MultiCompiler.js +64 -49
  103. package/lib/MultiStats.js +19 -14
  104. package/lib/MultiWatching.js +7 -11
  105. package/lib/NoEmitOnErrorsPlugin.js +5 -3
  106. package/lib/NodeStuffPlugin.js +438 -126
  107. package/lib/NormalModule.js +322 -201
  108. package/lib/NormalModuleFactory.js +230 -117
  109. package/lib/NormalModuleReplacementPlugin.js +37 -39
  110. package/lib/NullFactory.js +3 -2
  111. package/lib/OptimizationStages.js +1 -1
  112. package/lib/OptionsApply.js +1 -1
  113. package/lib/Parser.js +5 -3
  114. package/lib/PlatformPlugin.js +3 -1
  115. package/lib/PrefetchPlugin.js +6 -4
  116. package/lib/ProgressPlugin.js +48 -49
  117. package/lib/ProvidePlugin.js +7 -5
  118. package/lib/RawModule.js +26 -12
  119. package/lib/RecordIdsPlugin.js +88 -110
  120. package/lib/RequestShortener.js +3 -1
  121. package/lib/ResolverFactory.js +15 -14
  122. package/lib/RuntimeGlobals.js +216 -153
  123. package/lib/RuntimeModule.js +7 -6
  124. package/lib/RuntimePlugin.js +115 -62
  125. package/lib/RuntimeTemplate.js +248 -76
  126. package/lib/SelfModuleFactory.js +2 -2
  127. package/lib/SizeFormatHelpers.js +2 -2
  128. package/lib/SourceMapDevToolModuleOptionsPlugin.js +17 -27
  129. package/lib/SourceMapDevToolPlugin.js +72 -59
  130. package/lib/Stats.js +2 -3
  131. package/lib/Template.js +31 -24
  132. package/lib/TemplatedPathPlugin.js +24 -21
  133. package/lib/UseStrictPlugin.js +1 -1
  134. package/lib/WarnCaseSensitiveModulesPlugin.js +36 -37
  135. package/lib/WarnDeprecatedOptionPlugin.js +7 -8
  136. package/lib/WarnNoModeSetPlugin.js +3 -1
  137. package/lib/WatchIgnorePlugin.js +11 -9
  138. package/lib/Watching.js +27 -29
  139. package/lib/WebpackError.js +10 -3
  140. package/lib/WebpackIsIncludedPlugin.js +4 -5
  141. package/lib/WebpackOptionsApply.js +263 -135
  142. package/lib/asset/AssetBytesGenerator.js +171 -0
  143. package/lib/asset/AssetBytesParser.js +37 -0
  144. package/lib/asset/AssetGenerator.js +285 -223
  145. package/lib/asset/AssetModulesPlugin.js +103 -41
  146. package/lib/asset/AssetParser.js +7 -3
  147. package/lib/asset/AssetSourceGenerator.js +41 -17
  148. package/lib/asset/RawDataUrlModule.js +17 -9
  149. package/lib/async-modules/AsyncModuleHelpers.js +52 -0
  150. package/lib/async-modules/AwaitDependenciesInitFragment.js +39 -24
  151. package/lib/async-modules/InferAsyncModulesPlugin.js +25 -26
  152. package/lib/buildChunkGraph.js +36 -17
  153. package/lib/cache/AddBuildDependenciesPlugin.js +5 -6
  154. package/lib/cache/IdleFileCachePlugin.js +22 -20
  155. package/lib/cache/MemoryCachePlugin.js +3 -3
  156. package/lib/cache/MemoryWithGcCachePlugin.js +17 -11
  157. package/lib/cache/PackFileCacheStrategy.js +198 -170
  158. package/lib/cache/ResolverCachePlugin.js +58 -48
  159. package/lib/cache/getLazyHashedEtag.js +5 -4
  160. package/lib/cli.js +197 -39
  161. package/lib/config/browserslistTargetHandler.js +110 -85
  162. package/lib/config/defaults.js +514 -113
  163. package/lib/config/normalization.js +91 -64
  164. package/lib/config/target.js +30 -18
  165. package/lib/container/ContainerEntryDependency.js +0 -1
  166. package/lib/container/ContainerEntryModule.js +16 -15
  167. package/lib/container/ContainerEntryModuleFactory.js +2 -2
  168. package/lib/container/ContainerPlugin.js +5 -6
  169. package/lib/container/ContainerReferencePlugin.js +27 -30
  170. package/lib/container/FallbackDependency.js +2 -1
  171. package/lib/container/FallbackModule.js +19 -14
  172. package/lib/container/FallbackModuleFactory.js +2 -2
  173. package/lib/container/HoistContainerReferencesPlugin.js +7 -7
  174. package/lib/container/ModuleFederationPlugin.js +4 -4
  175. package/lib/container/RemoteModule.js +14 -14
  176. package/lib/container/RemoteRuntimeModule.js +2 -2
  177. package/lib/container/options.js +9 -9
  178. package/lib/css/CssGenerator.js +366 -74
  179. package/lib/css/CssLoadingRuntimeModule.js +26 -16
  180. package/lib/css/CssMergeStyleSheetsRuntimeModule.js +56 -0
  181. package/lib/css/CssModulesPlugin.js +191 -142
  182. package/lib/css/CssParser.js +1756 -740
  183. package/lib/css/walkCssTokens.js +180 -67
  184. package/lib/debug/ProfilingPlugin.js +135 -51
  185. package/lib/dependencies/AMDDefineDependencyParserPlugin.js +29 -28
  186. package/lib/dependencies/AMDPlugin.js +18 -11
  187. package/lib/dependencies/AMDRequireArrayDependency.js +5 -4
  188. package/lib/dependencies/AMDRequireContextDependency.js +2 -1
  189. package/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js +35 -26
  190. package/lib/dependencies/AMDRuntimeModules.js +3 -1
  191. package/lib/dependencies/CachedConstDependency.js +24 -18
  192. package/lib/dependencies/CommonJsExportRequireDependency.js +31 -24
  193. package/lib/dependencies/CommonJsExportsDependency.js +2 -1
  194. package/lib/dependencies/CommonJsExportsParserPlugin.js +50 -36
  195. package/lib/dependencies/CommonJsFullRequireDependency.js +7 -13
  196. package/lib/dependencies/CommonJsImportsParserPlugin.js +146 -127
  197. package/lib/dependencies/CommonJsPlugin.js +29 -18
  198. package/lib/dependencies/CommonJsRequireContextDependency.js +4 -3
  199. package/lib/dependencies/CommonJsSelfReferenceDependency.js +4 -4
  200. package/lib/dependencies/ConstDependency.js +2 -2
  201. package/lib/dependencies/ContextDependency.js +10 -5
  202. package/lib/dependencies/ContextDependencyHelpers.js +21 -13
  203. package/lib/dependencies/ContextDependencyTemplateAsId.js +10 -9
  204. package/lib/dependencies/ContextDependencyTemplateAsRequireCall.js +13 -10
  205. package/lib/dependencies/ContextElementDependency.js +23 -12
  206. package/lib/dependencies/CssIcssExportDependency.js +402 -22
  207. package/lib/dependencies/CssIcssImportDependency.js +116 -51
  208. package/lib/dependencies/CssIcssSymbolDependency.js +33 -35
  209. package/lib/dependencies/CssImportDependency.js +17 -14
  210. package/lib/dependencies/CssUrlDependency.js +8 -13
  211. package/lib/dependencies/DynamicExports.js +19 -19
  212. package/lib/dependencies/ExportsInfoDependency.js +13 -10
  213. package/lib/dependencies/ExternalModuleDependency.js +7 -7
  214. package/lib/dependencies/ExternalModuleInitFragment.js +3 -2
  215. package/lib/dependencies/ExternalModuleInitFragmentDependency.js +96 -0
  216. package/lib/dependencies/HarmonyAcceptDependency.js +96 -5
  217. package/lib/dependencies/HarmonyAcceptImportDependency.js +2 -5
  218. package/lib/dependencies/HarmonyCompatibilityDependency.js +0 -1
  219. package/lib/dependencies/HarmonyDetectionParserPlugin.js +10 -30
  220. package/lib/dependencies/HarmonyEvaluatedImportSpecifierDependency.js +19 -8
  221. package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +136 -99
  222. package/lib/dependencies/HarmonyExportExpressionDependency.js +1 -1
  223. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +152 -61
  224. package/lib/dependencies/HarmonyExportInitFragment.js +2 -2
  225. package/lib/dependencies/HarmonyExportSpecifierDependency.js +2 -2
  226. package/lib/dependencies/HarmonyExports.js +5 -5
  227. package/lib/dependencies/HarmonyImportDependency.js +92 -45
  228. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +201 -163
  229. package/lib/dependencies/HarmonyImportSideEffectDependency.js +5 -6
  230. package/lib/dependencies/HarmonyImportSpecifierDependency.js +69 -42
  231. package/lib/dependencies/HarmonyModulesPlugin.js +16 -11
  232. package/lib/dependencies/HarmonyTopLevelThisParserPlugin.js +15 -15
  233. package/lib/dependencies/ImportContextDependency.js +15 -1
  234. package/lib/dependencies/ImportDependency.js +25 -7
  235. package/lib/dependencies/ImportEagerDependency.js +7 -5
  236. package/lib/dependencies/ImportMetaContextDependencyParserPlugin.js +23 -13
  237. package/lib/dependencies/ImportMetaContextPlugin.js +2 -2
  238. package/lib/dependencies/ImportMetaPlugin.js +172 -20
  239. package/lib/dependencies/ImportParserPlugin.js +327 -49
  240. package/lib/dependencies/ImportPhase.js +121 -0
  241. package/lib/dependencies/ImportPlugin.js +3 -1
  242. package/lib/dependencies/ImportWeakDependency.js +7 -5
  243. package/lib/dependencies/JsonExportsDependency.js +54 -28
  244. package/lib/dependencies/LoaderDependency.js +0 -3
  245. package/lib/dependencies/LoaderImportDependency.js +0 -3
  246. package/lib/dependencies/LoaderPlugin.js +24 -25
  247. package/lib/dependencies/LocalModulesHelpers.js +4 -4
  248. package/lib/dependencies/ModuleDecoratorDependency.js +2 -4
  249. package/lib/dependencies/ModuleDependency.js +14 -13
  250. package/lib/dependencies/ModuleDependencyTemplateAsRequireId.js +1 -0
  251. package/lib/dependencies/ModuleHotAcceptDependency.js +1 -1
  252. package/lib/dependencies/NullDependency.js +2 -0
  253. package/lib/dependencies/ProvidedDependency.js +8 -10
  254. package/lib/dependencies/PureExpressionDependency.js +1 -2
  255. package/lib/dependencies/RequireContextDependency.js +2 -1
  256. package/lib/dependencies/RequireContextDependencyParserPlugin.js +47 -44
  257. package/lib/dependencies/RequireContextPlugin.js +5 -2
  258. package/lib/dependencies/RequireEnsureDependenciesBlock.js +3 -3
  259. package/lib/dependencies/RequireEnsureDependenciesBlockParserPlugin.js +101 -99
  260. package/lib/dependencies/RequireEnsurePlugin.js +6 -6
  261. package/lib/dependencies/RequireIncludeDependency.js +2 -2
  262. package/lib/dependencies/RequireIncludeDependencyParserPlugin.js +33 -34
  263. package/lib/dependencies/RequireIncludePlugin.js +1 -0
  264. package/lib/dependencies/RequireResolveContextDependency.js +1 -1
  265. package/lib/dependencies/RequireResolveDependency.js +3 -3
  266. package/lib/dependencies/RuntimeRequirementsDependency.js +3 -4
  267. package/lib/dependencies/StaticExportsDependency.js +3 -5
  268. package/lib/dependencies/SystemPlugin.js +4 -4
  269. package/lib/dependencies/URLContextDependency.js +65 -0
  270. package/lib/dependencies/URLDependency.js +3 -8
  271. package/lib/dependencies/URLPlugin.js +18 -159
  272. package/lib/dependencies/WebAssemblyExportImportedDependency.js +3 -3
  273. package/lib/dependencies/WebAssemblyImportDependency.js +2 -2
  274. package/lib/dependencies/WebpackIsIncludedDependency.js +2 -3
  275. package/lib/dependencies/WorkerDependency.js +8 -6
  276. package/lib/dependencies/WorkerPlugin.js +131 -67
  277. package/lib/dependencies/getFunctionExpression.js +2 -2
  278. package/lib/dependencies/processExportInfo.js +4 -4
  279. package/lib/esm/ExportWebpackRequireRuntimeModule.js +1 -1
  280. package/lib/esm/ModuleChunkFormatPlugin.js +232 -179
  281. package/lib/esm/ModuleChunkLoadingPlugin.js +112 -57
  282. package/lib/esm/ModuleChunkLoadingRuntimeModule.js +102 -28
  283. package/lib/formatLocation.js +2 -2
  284. package/lib/hmr/HotModuleReplacement.runtime.js +41 -29
  285. package/lib/hmr/HotModuleReplacementRuntimeModule.js +1 -1
  286. package/lib/hmr/JavascriptHotModuleReplacement.runtime.js +43 -33
  287. package/lib/hmr/JavascriptHotModuleReplacementHelper.js +37 -0
  288. package/lib/hmr/LazyCompilationPlugin.js +67 -54
  289. package/lib/hmr/lazyCompilationBackend.js +23 -18
  290. package/lib/ids/ChunkModuleIdRangePlugin.js +14 -11
  291. package/lib/ids/DeterministicChunkIdsPlugin.js +32 -37
  292. package/lib/ids/DeterministicModuleIdsPlugin.js +52 -52
  293. package/lib/ids/HashedModuleIdsPlugin.js +15 -13
  294. package/lib/ids/IdHelpers.js +66 -49
  295. package/lib/ids/NamedChunkIdsPlugin.js +14 -17
  296. package/lib/ids/NamedModuleIdsPlugin.js +12 -14
  297. package/lib/ids/NaturalChunkIdsPlugin.js +6 -4
  298. package/lib/ids/NaturalModuleIdsPlugin.js +4 -3
  299. package/lib/ids/OccurrenceChunkIdsPlugin.js +7 -5
  300. package/lib/ids/OccurrenceModuleIdsPlugin.js +8 -7
  301. package/lib/ids/SyncModuleIdsPlugin.js +18 -13
  302. package/lib/index.js +54 -14
  303. package/lib/javascript/ArrayPushCallbackChunkFormatPlugin.js +116 -119
  304. package/lib/javascript/BasicEvaluatedExpression.js +26 -18
  305. package/lib/javascript/ChunkFormatHelpers.js +70 -0
  306. package/lib/javascript/ChunkHelpers.js +17 -5
  307. package/lib/javascript/CommonJsChunkFormatPlugin.js +114 -141
  308. package/lib/javascript/EnableChunkLoadingPlugin.js +7 -4
  309. package/lib/javascript/JavascriptGenerator.js +122 -100
  310. package/lib/javascript/JavascriptModulesPlugin.js +332 -152
  311. package/lib/javascript/JavascriptParser.js +1488 -1052
  312. package/lib/javascript/JavascriptParserHelpers.js +48 -47
  313. package/lib/javascript/StartupHelpers.js +23 -22
  314. package/lib/json/JsonData.js +4 -4
  315. package/lib/json/JsonGenerator.js +66 -32
  316. package/lib/json/JsonModulesPlugin.js +16 -6
  317. package/lib/json/JsonParser.js +23 -8
  318. package/lib/library/AbstractLibraryPlugin.js +45 -10
  319. package/lib/library/AmdLibraryPlugin.js +7 -5
  320. package/lib/library/AssignLibraryPlugin.js +71 -17
  321. package/lib/library/EnableLibraryPlugin.js +51 -25
  322. package/lib/library/ExportPropertyLibraryPlugin.js +12 -18
  323. package/lib/library/JsonpLibraryPlugin.js +5 -2
  324. package/lib/library/ModuleLibraryPlugin.js +230 -18
  325. package/lib/library/SystemLibraryPlugin.js +29 -11
  326. package/lib/library/UmdLibraryPlugin.js +35 -32
  327. package/lib/logging/Logger.js +18 -15
  328. package/lib/logging/createConsoleLogger.js +27 -27
  329. package/lib/logging/runtime.js +11 -11
  330. package/lib/logging/truncateArgs.js +5 -5
  331. package/lib/node/CommonJsChunkLoadingPlugin.js +72 -75
  332. package/lib/node/NodeEnvironmentPlugin.js +9 -3
  333. package/lib/node/NodeTargetPlugin.js +9 -1
  334. package/lib/node/NodeTemplatePlugin.js +2 -2
  335. package/lib/node/NodeWatchFileSystem.js +4 -4
  336. package/lib/node/ReadFileChunkLoadingRuntimeModule.js +22 -38
  337. package/lib/node/ReadFileCompileAsyncWasmPlugin.js +10 -11
  338. package/lib/node/ReadFileCompileWasmPlugin.js +11 -14
  339. package/lib/node/RequireChunkLoadingRuntimeModule.js +22 -30
  340. package/lib/node/nodeConsole.js +12 -7
  341. package/lib/optimize/AggressiveMergingPlugin.js +46 -47
  342. package/lib/optimize/AggressiveSplittingPlugin.js +233 -238
  343. package/lib/optimize/ConcatenatedModule.js +620 -251
  344. package/lib/optimize/EnsureChunkConditionsPlugin.js +58 -58
  345. package/lib/optimize/FlagIncludedChunksPlugin.js +93 -96
  346. package/lib/optimize/InnerGraph.js +139 -124
  347. package/lib/optimize/InnerGraphPlugin.js +29 -24
  348. package/lib/optimize/LimitChunkCountPlugin.js +32 -8
  349. package/lib/optimize/MangleExportsPlugin.js +22 -22
  350. package/lib/optimize/MergeDuplicateChunksPlugin.js +80 -81
  351. package/lib/optimize/MinChunkSizePlugin.js +12 -7
  352. package/lib/optimize/ModuleConcatenationPlugin.js +92 -71
  353. package/lib/optimize/RealContentHashPlugin.js +58 -44
  354. package/lib/optimize/RemoveEmptyChunksPlugin.js +8 -5
  355. package/lib/optimize/RemoveParentModulesPlugin.js +7 -4
  356. package/lib/optimize/RuntimeChunkPlugin.js +22 -25
  357. package/lib/optimize/SideEffectsFlagPlugin.js +44 -26
  358. package/lib/optimize/SplitChunksPlugin.js +209 -158
  359. package/lib/performance/AssetsOverSizeLimitWarning.js +1 -1
  360. package/lib/performance/EntrypointsOverSizeLimitWarning.js +2 -2
  361. package/lib/performance/SizeLimitsPlugin.js +8 -5
  362. package/lib/prefetch/ChunkPrefetchFunctionRuntimeModule.js +5 -7
  363. package/lib/prefetch/ChunkPrefetchPreloadPlugin.js +61 -64
  364. package/lib/prefetch/ChunkPrefetchStartupRuntimeModule.js +3 -4
  365. package/lib/prefetch/ChunkPrefetchTriggerRuntimeModule.js +2 -2
  366. package/lib/prefetch/ChunkPreloadTriggerRuntimeModule.js +2 -2
  367. package/lib/rules/BasicEffectRulePlugin.js +14 -5
  368. package/lib/rules/BasicMatcherRulePlugin.js +18 -7
  369. package/lib/rules/ObjectMatcherRulePlugin.js +17 -6
  370. package/lib/rules/RuleSetCompiler.js +73 -32
  371. package/lib/rules/UseEffectRulePlugin.js +61 -25
  372. package/lib/runtime/AsyncModuleRuntimeModule.js +74 -9
  373. package/lib/runtime/AutoPublicPathRuntimeModule.js +9 -4
  374. package/lib/runtime/BaseUriRuntimeModule.js +2 -2
  375. package/lib/runtime/CompatRuntimeModule.js +0 -1
  376. package/lib/runtime/CreateFakeNamespaceObjectRuntimeModule.js +1 -1
  377. package/lib/runtime/GetChunkFilenameRuntimeModule.js +34 -35
  378. package/lib/runtime/GetMainFilenameRuntimeModule.js +1 -1
  379. package/lib/runtime/GetTrustedTypesPolicyRuntimeModule.js +1 -1
  380. package/lib/runtime/LoadScriptRuntimeModule.js +0 -2
  381. package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +248 -0
  382. package/lib/runtime/PublicPathRuntimeModule.js +2 -2
  383. package/lib/runtime/RuntimeIdRuntimeModule.js +2 -1
  384. package/lib/runtime/StartupChunkDependenciesPlugin.js +39 -42
  385. package/lib/runtime/StartupChunkDependenciesRuntimeModule.js +10 -9
  386. package/lib/runtime/StartupEntrypointRuntimeModule.js +0 -1
  387. package/lib/runtime/SystemContextRuntimeModule.js +0 -2
  388. package/lib/runtime/ToBinaryRuntimeModule.js +64 -0
  389. package/lib/schemes/DataUriPlugin.js +9 -31
  390. package/lib/schemes/FileUriPlugin.js +11 -6
  391. package/lib/schemes/HttpUriPlugin.js +381 -261
  392. package/lib/schemes/VirtualUrlPlugin.js +222 -0
  393. package/lib/serialization/AggregateErrorSerializer.js +41 -0
  394. package/lib/serialization/BinaryMiddleware.js +51 -33
  395. package/lib/serialization/ErrorObjectSerializer.js +7 -2
  396. package/lib/serialization/FileMiddleware.js +101 -71
  397. package/lib/serialization/NullPrototypeObjectSerializer.js +5 -3
  398. package/lib/serialization/ObjectMiddleware.js +130 -54
  399. package/lib/serialization/PlainObjectSerializer.js +1 -1
  400. package/lib/serialization/Serializer.js +38 -20
  401. package/lib/serialization/SerializerMiddleware.js +121 -49
  402. package/lib/serialization/SingleItemMiddleware.js +9 -7
  403. package/lib/serialization/types.js +1 -1
  404. package/lib/sharing/ConsumeSharedModule.js +9 -9
  405. package/lib/sharing/ConsumeSharedPlugin.js +14 -14
  406. package/lib/sharing/ConsumeSharedRuntimeModule.js +11 -8
  407. package/lib/sharing/ProvideSharedModule.js +9 -11
  408. package/lib/sharing/ProvideSharedModuleFactory.js +5 -3
  409. package/lib/sharing/ProvideSharedPlugin.js +15 -10
  410. package/lib/sharing/SharePlugin.js +3 -4
  411. package/lib/sharing/ShareRuntimeModule.js +7 -6
  412. package/lib/sharing/resolveMatchedConfigs.js +27 -13
  413. package/lib/sharing/utils.js +37 -43
  414. package/lib/stats/DefaultStatsFactoryPlugin.js +455 -286
  415. package/lib/stats/DefaultStatsPresetPlugin.js +77 -46
  416. package/lib/stats/DefaultStatsPrinterPlugin.js +583 -419
  417. package/lib/stats/StatsFactory.js +75 -32
  418. package/lib/stats/StatsPrinter.js +71 -51
  419. package/lib/url/URLParserPlugin.js +264 -0
  420. package/lib/util/ArrayHelpers.js +6 -8
  421. package/lib/util/ArrayQueue.js +1 -1
  422. package/lib/util/AsyncQueue.js +11 -10
  423. package/lib/util/Hash.js +37 -5
  424. package/lib/util/IterableHelpers.js +4 -4
  425. package/lib/util/LazyBucketSortedSet.js +46 -27
  426. package/lib/util/LazySet.js +16 -10
  427. package/lib/util/MapHelpers.js +1 -1
  428. package/lib/util/ParallelismFactorCalculator.js +2 -2
  429. package/lib/util/Semaphore.js +3 -3
  430. package/lib/util/SetHelpers.js +6 -6
  431. package/lib/util/SortableSet.js +11 -9
  432. package/lib/util/StackedCacheMap.js +2 -2
  433. package/lib/util/StackedMap.js +3 -3
  434. package/lib/util/StringXor.js +2 -1
  435. package/lib/util/TupleQueue.js +11 -8
  436. package/lib/util/TupleSet.js +44 -19
  437. package/lib/util/URLAbsoluteSpecifier.js +3 -4
  438. package/lib/util/WeakTupleMap.js +56 -42
  439. package/lib/util/binarySearchBounds.js +4 -3
  440. package/lib/util/chainedImports.js +3 -1
  441. package/lib/util/cleverMerge.js +171 -107
  442. package/lib/util/comparators.js +265 -162
  443. package/lib/util/compileBooleanMatcher.js +120 -41
  444. package/lib/util/concatenate.js +20 -16
  445. package/lib/util/conventions.js +73 -74
  446. package/lib/util/create-schema-validation.js +8 -8
  447. package/lib/util/createHash.js +32 -135
  448. package/lib/util/dataURL.js +39 -0
  449. package/lib/util/deprecation.js +119 -116
  450. package/lib/util/deterministicGrouping.js +56 -47
  451. package/lib/util/extractSourceMap.js +319 -0
  452. package/lib/util/extractUrlAndGlobal.js +1 -1
  453. package/lib/util/findGraphRoots.js +19 -9
  454. package/lib/util/fs.js +169 -141
  455. package/lib/util/hash/BatchedHash.js +50 -10
  456. package/lib/util/hash/BulkUpdateHash.js +138 -0
  457. package/lib/util/hash/DebugHash.js +75 -0
  458. package/lib/util/hash/hash-digest.js +216 -0
  459. package/lib/util/hash/md4.js +2 -2
  460. package/lib/util/hash/wasm-hash.js +59 -17
  461. package/lib/util/identifier.js +124 -61
  462. package/lib/util/internalSerializables.js +4 -6
  463. package/lib/util/magicComment.js +9 -5
  464. package/lib/util/makeSerializable.js +2 -2
  465. package/lib/util/memoize.js +5 -2
  466. package/lib/util/objectToMap.js +3 -2
  467. package/lib/util/processAsyncTree.js +5 -5
  468. package/lib/util/propertyAccess.js +1 -1
  469. package/lib/util/propertyName.js +2 -3
  470. package/lib/util/registerExternalSerializer.js +16 -20
  471. package/lib/util/removeBOM.js +25 -0
  472. package/lib/util/runtime.js +72 -56
  473. package/lib/util/semver.js +44 -33
  474. package/lib/util/serialization.js +56 -56
  475. package/lib/util/smartGrouping.js +42 -27
  476. package/lib/util/source.js +5 -4
  477. package/lib/util/traverseDestructuringAssignmentProperties.js +45 -0
  478. package/lib/validateSchema.js +7 -9
  479. package/lib/wasm/EnableWasmLoadingPlugin.js +22 -12
  480. package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +9 -5
  481. package/lib/wasm-async/AsyncWebAssemblyGenerator.js +15 -3
  482. package/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js +28 -22
  483. package/lib/wasm-async/AsyncWebAssemblyModulesPlugin.js +47 -57
  484. package/lib/wasm-async/AsyncWebAssemblyParser.js +2 -10
  485. package/lib/wasm-async/UniversalCompileAsyncWasmPlugin.js +8 -4
  486. package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +23 -17
  487. package/lib/wasm-sync/WasmFinalizeExportsPlugin.js +55 -57
  488. package/lib/wasm-sync/WebAssemblyGenerator.js +56 -41
  489. package/lib/wasm-sync/WebAssemblyInInitialChunkError.js +6 -3
  490. package/lib/wasm-sync/WebAssemblyJavascriptGenerator.js +25 -10
  491. package/lib/wasm-sync/WebAssemblyModulesPlugin.js +11 -12
  492. package/lib/wasm-sync/WebAssemblyParser.js +10 -17
  493. package/lib/wasm-sync/WebAssemblyUtils.js +1 -1
  494. package/lib/web/FetchCompileAsyncWasmPlugin.js +4 -4
  495. package/lib/web/FetchCompileWasmPlugin.js +6 -8
  496. package/lib/web/JsonpChunkLoadingPlugin.js +74 -74
  497. package/lib/web/JsonpChunkLoadingRuntimeModule.js +10 -26
  498. package/lib/web/JsonpTemplatePlugin.js +0 -1
  499. package/lib/webpack.js +107 -87
  500. package/lib/webworker/ImportScriptsChunkLoadingPlugin.js +79 -75
  501. package/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js +38 -51
  502. package/lib/webworker/WebWorkerTemplatePlugin.js +1 -0
  503. package/module.d.ts +5 -0
  504. package/package.json +149 -129
  505. package/schemas/WebpackOptions.check.d.ts +1 -1
  506. package/schemas/WebpackOptions.check.js +2 -2
  507. package/schemas/WebpackOptions.json +543 -190
  508. package/schemas/plugins/BannerPlugin.check.d.ts +1 -1
  509. package/schemas/plugins/BannerPlugin.check.js +2 -2
  510. package/schemas/plugins/BannerPlugin.json +4 -0
  511. package/schemas/plugins/DllPlugin.check.d.ts +1 -1
  512. package/schemas/plugins/DllPlugin.check.js +1 -1
  513. package/schemas/plugins/DllReferencePlugin.check.d.ts +1 -1
  514. package/schemas/plugins/DllReferencePlugin.check.js +1 -1
  515. package/schemas/plugins/IgnorePlugin.check.d.ts +1 -1
  516. package/schemas/plugins/IgnorePlugin.check.js +1 -1
  517. package/schemas/plugins/IgnorePlugin.json +1 -1
  518. package/schemas/plugins/LoaderOptionsPlugin.check.d.ts +1 -1
  519. package/schemas/plugins/LoaderOptionsPlugin.check.js +1 -1
  520. package/schemas/plugins/{HashedModuleIdsPlugin.check.d.ts → ManifestPlugin.check.d.ts} +2 -2
  521. package/schemas/plugins/ManifestPlugin.check.js +6 -0
  522. package/schemas/plugins/ManifestPlugin.json +98 -0
  523. package/schemas/plugins/ProgressPlugin.check.d.ts +1 -1
  524. package/schemas/plugins/ProgressPlugin.check.js +1 -1
  525. package/schemas/plugins/ProgressPlugin.json +1 -1
  526. package/schemas/plugins/SourceMapDevToolPlugin.check.d.ts +1 -1
  527. package/schemas/plugins/SourceMapDevToolPlugin.check.js +2 -2
  528. package/schemas/plugins/SourceMapDevToolPlugin.json +23 -6
  529. package/schemas/plugins/WatchIgnorePlugin.check.d.ts +1 -1
  530. package/schemas/plugins/WatchIgnorePlugin.check.js +1 -1
  531. package/schemas/plugins/asset/AssetGeneratorOptions.check.d.ts +1 -1
  532. package/schemas/plugins/asset/AssetGeneratorOptions.check.js +1 -1
  533. package/schemas/plugins/asset/AssetInlineGeneratorOptions.check.d.ts +1 -1
  534. package/schemas/plugins/asset/AssetInlineGeneratorOptions.check.js +1 -1
  535. package/schemas/plugins/asset/AssetParserOptions.check.d.ts +1 -1
  536. package/schemas/plugins/asset/AssetParserOptions.check.js +1 -1
  537. package/schemas/plugins/asset/AssetResourceGeneratorOptions.check.d.ts +1 -1
  538. package/schemas/plugins/asset/AssetResourceGeneratorOptions.check.js +1 -1
  539. package/schemas/plugins/container/ContainerPlugin.check.d.ts +1 -1
  540. package/schemas/plugins/container/ContainerPlugin.check.js +1 -1
  541. package/schemas/plugins/container/ContainerReferencePlugin.check.d.ts +1 -1
  542. package/schemas/plugins/container/ContainerReferencePlugin.check.js +2 -2
  543. package/schemas/plugins/container/ContainerReferencePlugin.json +4 -1
  544. package/schemas/plugins/container/ExternalsType.check.d.ts +1 -1
  545. package/schemas/plugins/container/ExternalsType.check.js +2 -2
  546. package/schemas/plugins/container/ModuleFederationPlugin.check.d.ts +1 -1
  547. package/schemas/plugins/container/ModuleFederationPlugin.check.js +2 -2
  548. package/schemas/plugins/container/ModuleFederationPlugin.json +4 -1
  549. package/schemas/plugins/css/CssGeneratorOptions.check.d.ts +1 -1
  550. package/schemas/plugins/css/CssGeneratorOptions.check.js +1 -1
  551. package/schemas/plugins/css/CssModuleGeneratorOptions.check.d.ts +1 -1
  552. package/schemas/plugins/css/CssModuleGeneratorOptions.check.js +2 -2
  553. package/schemas/plugins/css/CssModuleParserOptions.check.d.ts +1 -1
  554. package/schemas/plugins/css/CssModuleParserOptions.check.js +2 -2
  555. package/schemas/plugins/css/CssParserOptions.check.d.ts +1 -1
  556. package/schemas/plugins/css/CssParserOptions.check.js +2 -2
  557. package/schemas/plugins/debug/ProfilingPlugin.check.d.ts +1 -1
  558. package/schemas/plugins/debug/ProfilingPlugin.check.js +1 -1
  559. package/schemas/plugins/ids/HashedModuleIdsPlugin.check.d.ts +7 -0
  560. package/schemas/plugins/ids/HashedModuleIdsPlugin.check.js +6 -0
  561. package/schemas/plugins/{HashedModuleIdsPlugin.json → ids/HashedModuleIdsPlugin.json} +15 -2
  562. package/schemas/plugins/ids/OccurrenceChunkIdsPlugin.check.d.ts +1 -1
  563. package/schemas/plugins/ids/OccurrenceChunkIdsPlugin.check.js +1 -1
  564. package/schemas/plugins/ids/OccurrenceModuleIdsPlugin.check.d.ts +1 -1
  565. package/schemas/plugins/ids/OccurrenceModuleIdsPlugin.check.js +1 -1
  566. package/schemas/plugins/{css/CssGlobalParserOptions.check.d.ts → json/JsonModulesPluginGenerator.check.d.ts} +1 -1
  567. package/schemas/plugins/json/JsonModulesPluginGenerator.check.js +6 -0
  568. package/schemas/plugins/json/JsonModulesPluginGenerator.json +3 -0
  569. package/schemas/plugins/{css/CssGlobalGeneratorOptions.check.d.ts → json/JsonModulesPluginParser.check.d.ts} +1 -1
  570. package/schemas/plugins/json/JsonModulesPluginParser.check.js +6 -0
  571. package/schemas/plugins/json/JsonModulesPluginParser.json +3 -0
  572. package/schemas/plugins/optimize/AggressiveSplittingPlugin.check.d.ts +1 -1
  573. package/schemas/plugins/optimize/AggressiveSplittingPlugin.check.js +1 -1
  574. package/schemas/plugins/optimize/LimitChunkCountPlugin.check.d.ts +1 -1
  575. package/schemas/plugins/optimize/LimitChunkCountPlugin.check.js +1 -1
  576. package/schemas/plugins/optimize/MergeDuplicateChunksPlugin.check.d.ts +1 -1
  577. package/schemas/plugins/optimize/MergeDuplicateChunksPlugin.check.js +1 -1
  578. package/schemas/plugins/optimize/MinChunkSizePlugin.check.d.ts +1 -1
  579. package/schemas/plugins/optimize/MinChunkSizePlugin.check.js +1 -1
  580. package/schemas/plugins/schemes/HttpUriPlugin.check.d.ts +1 -1
  581. package/schemas/plugins/schemes/HttpUriPlugin.check.js +1 -1
  582. package/schemas/plugins/schemes/VirtualUrlPlugin.check.d.ts +7 -0
  583. package/schemas/plugins/schemes/VirtualUrlPlugin.check.js +6 -0
  584. package/schemas/plugins/schemes/VirtualUrlPlugin.json +77 -0
  585. package/schemas/plugins/sharing/ConsumeSharedPlugin.check.d.ts +1 -1
  586. package/schemas/plugins/sharing/ConsumeSharedPlugin.check.js +1 -1
  587. package/schemas/plugins/sharing/ProvideSharedPlugin.check.d.ts +1 -1
  588. package/schemas/plugins/sharing/ProvideSharedPlugin.check.js +1 -1
  589. package/schemas/plugins/sharing/SharePlugin.check.d.ts +1 -1
  590. package/schemas/plugins/sharing/SharePlugin.check.js +1 -1
  591. package/types.d.ts +5115 -1863
  592. package/SECURITY.md +0 -9
  593. package/lib/ModuleSourceTypesConstants.js +0 -112
  594. package/lib/dependencies/CssLocalIdentifierDependency.js +0 -250
  595. package/lib/dependencies/CssSelfLocalIdentifierDependency.js +0 -111
  596. package/lib/library/ModernModuleLibraryPlugin.js +0 -144
  597. package/schemas/plugins/HashedModuleIdsPlugin.check.js +0 -6
  598. package/schemas/plugins/JsonModulesPluginParser.check.d.ts +0 -7
  599. package/schemas/plugins/JsonModulesPluginParser.check.js +0 -6
  600. package/schemas/plugins/JsonModulesPluginParser.json +0 -12
  601. package/schemas/plugins/css/CssAutoGeneratorOptions.check.d.ts +0 -7
  602. package/schemas/plugins/css/CssAutoGeneratorOptions.check.js +0 -6
  603. package/schemas/plugins/css/CssAutoGeneratorOptions.json +0 -3
  604. package/schemas/plugins/css/CssAutoParserOptions.check.d.ts +0 -7
  605. package/schemas/plugins/css/CssAutoParserOptions.check.js +0 -6
  606. package/schemas/plugins/css/CssAutoParserOptions.json +0 -3
  607. package/schemas/plugins/css/CssGlobalGeneratorOptions.check.js +0 -6
  608. package/schemas/plugins/css/CssGlobalGeneratorOptions.json +0 -3
  609. package/schemas/plugins/css/CssGlobalParserOptions.check.js +0 -6
  610. package/schemas/plugins/css/CssGlobalParserOptions.json +0 -3
@@ -5,37 +5,41 @@
5
5
 
6
6
  "use strict";
7
7
 
8
- const { Parser: AcornParser, tokTypes } = require("acorn");
9
- const { SyncBailHook, HookMap } = require("tapable");
10
8
  const vm = require("vm");
9
+ const { Parser: AcornParser, tokTypes } = require("acorn");
10
+ const { HookMap, SyncBailHook } = require("tapable");
11
+ const NormalModule = require("../NormalModule");
11
12
  const Parser = require("../Parser");
12
13
  const StackedMap = require("../util/StackedMap");
13
14
  const binarySearchBounds = require("../util/binarySearchBounds");
14
15
  const {
15
- webpackCommentRegExp,
16
- createMagicCommentContext
16
+ createMagicCommentContext,
17
+ webpackCommentRegExp
17
18
  } = require("../util/magicComment");
18
19
  const memoize = require("../util/memoize");
19
20
  const BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
20
21
 
21
22
  /** @typedef {import("acorn").Options} AcornOptions */
23
+ /** @typedef {import("acorn").ecmaVersion} EcmaVersion */
22
24
  /** @typedef {import("estree").AssignmentExpression} AssignmentExpression */
23
25
  /** @typedef {import("estree").BinaryExpression} BinaryExpression */
24
26
  /** @typedef {import("estree").BlockStatement} BlockStatement */
25
27
  /** @typedef {import("estree").SequenceExpression} SequenceExpression */
26
28
  /** @typedef {import("estree").CallExpression} CallExpression */
27
- /** @typedef {import("estree").BaseCallExpression} BaseCallExpression */
28
29
  /** @typedef {import("estree").StaticBlock} StaticBlock */
29
30
  /** @typedef {import("estree").ClassDeclaration} ClassDeclaration */
30
31
  /** @typedef {import("estree").ForStatement} ForStatement */
31
32
  /** @typedef {import("estree").SwitchStatement} SwitchStatement */
32
33
  /** @typedef {import("estree").ClassExpression} ClassExpression */
33
- /** @typedef {import("estree").Comment} Comment */
34
+ /** @typedef {import("estree").SourceLocation} SourceLocation */
35
+ /** @typedef {import("estree").Comment & { start: number, end: number, loc: SourceLocation }} Comment */
34
36
  /** @typedef {import("estree").ConditionalExpression} ConditionalExpression */
35
37
  /** @typedef {import("estree").Declaration} Declaration */
36
38
  /** @typedef {import("estree").PrivateIdentifier} PrivateIdentifier */
37
39
  /** @typedef {import("estree").PropertyDefinition} PropertyDefinition */
38
40
  /** @typedef {import("estree").Expression} Expression */
41
+ /** @typedef {import("estree").ImportAttribute} ImportAttribute */
42
+ /** @typedef {import("estree").ImportDeclaration} ImportDeclaration */
39
43
  /** @typedef {import("estree").Identifier} Identifier */
40
44
  /** @typedef {import("estree").VariableDeclaration} VariableDeclaration */
41
45
  /** @typedef {import("estree").IfStatement} IfStatement */
@@ -48,7 +52,6 @@ const BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
48
52
  /** @typedef {import("estree").MetaProperty} MetaProperty */
49
53
  /** @typedef {import("estree").Property} Property */
50
54
  /** @typedef {import("estree").AssignmentPattern} AssignmentPattern */
51
- /** @typedef {import("estree").ChainElement} ChainElement */
52
55
  /** @typedef {import("estree").Pattern} Pattern */
53
56
  /** @typedef {import("estree").UpdateExpression} UpdateExpression */
54
57
  /** @typedef {import("estree").ObjectExpression} ObjectExpression */
@@ -74,6 +77,8 @@ const BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
74
77
  /** @typedef {import("estree").WhileStatement} WhileStatement */
75
78
  /** @typedef {import("estree").ArrowFunctionExpression} ArrowFunctionExpression */
76
79
  /** @typedef {import("estree").ExpressionStatement} ExpressionStatement */
80
+ /** @typedef {import("estree").ExportAllDeclaration} ExportAllDeclaration */
81
+ /** @typedef {import("estree").ExportNamedDeclaration} ExportNamedDeclaration */
77
82
  /** @typedef {import("estree").FunctionDeclaration} FunctionDeclaration */
78
83
  /** @typedef {import("estree").DoWhileStatement} DoWhileStatement */
79
84
  /** @typedef {import("estree").TryStatement} TryStatement */
@@ -85,27 +90,42 @@ const BasicEvaluatedExpression = require("./BasicEvaluatedExpression");
85
90
  /** @typedef {import("estree").Super} Super */
86
91
  /** @typedef {import("estree").TaggedTemplateExpression} TaggedTemplateExpression */
87
92
  /** @typedef {import("estree").TemplateLiteral} TemplateLiteral */
88
- /** @typedef {import("estree").AssignmentProperty} AssignmentProperty */
93
+ /** @typedef {import("estree").ModuleDeclaration} ModuleDeclaration */
94
+ /** @typedef {import("estree").MaybeNamedFunctionDeclaration} MaybeNamedFunctionDeclaration */
95
+ /** @typedef {import("estree").MaybeNamedClassDeclaration} MaybeNamedClassDeclaration */
89
96
  /**
90
97
  * @template T
91
98
  * @typedef {import("tapable").AsArray<T>} AsArray<T>
92
99
  */
93
100
  /** @typedef {import("../Parser").ParserState} ParserState */
94
101
  /** @typedef {import("../Parser").PreparsedAst} PreparsedAst */
95
- /** @typedef {{declaredScope: ScopeInfo, freeName: string | true | undefined, tagInfo: TagInfo | undefined}} VariableInfoInterface */
96
- /** @typedef {{ name: string | VariableInfo, rootInfo: string | VariableInfo, getMembers: () => string[], getMembersOptionals: () => boolean[], getMemberRanges: () => Range[] }} GetInfoResult */
97
- /** @typedef {Statement | ModuleDeclaration | Expression} StatementPathItem */
98
- /** @typedef {function(string): void} OnIdentString */
99
- /** @typedef {function(string, Identifier): void} OnIdent */
102
+
103
+ /** @typedef {import("../dependencies/LocalModule")} LocalModule */
104
+ /** @typedef {import("../dependencies/HarmonyExportImportedSpecifierDependency").HarmonyStarExportsList} HarmonyStarExportsList */
105
+
106
+ /**
107
+ * @typedef {object} KnownJavascriptParserState
108
+ * @property {Set<string>=} harmonyNamedExports
109
+ * @property {HarmonyStarExportsList=} harmonyStarExports
110
+ * @property {number=} lastHarmonyImportOrder
111
+ * @property {LocalModule[]=} localModules
112
+ */
113
+
114
+ /** @typedef {ParserState & KnownJavascriptParserState} JavascriptParserState */
115
+
116
+ /** @typedef {import("../Compilation")} Compilation */
117
+ /** @typedef {import("../Module")} Module */
118
+
119
+ /** @typedef {{ name: string | VariableInfo, rootInfo: string | VariableInfo, getMembers: () => Members, getMembersOptionals: () => MembersOptionals, getMemberRanges: () => MemberRanges }} GetInfoResult */
120
+ /** @typedef {Statement | ModuleDeclaration | Expression | MaybeNamedFunctionDeclaration | MaybeNamedClassDeclaration} StatementPathItem */
121
+ /** @typedef {(ident: string) => void} OnIdentString */
122
+ /** @typedef {(ident: string, identifier: Identifier) => void} OnIdent */
100
123
  /** @typedef {StatementPathItem[]} StatementPath */
101
124
 
125
+ /** @typedef {Set<DestructuringAssignmentProperty>} DestructuringAssignmentProperties */
126
+
102
127
  // TODO remove cast when @types/estree has been updated to import assertions
103
- /** @typedef {import("estree").BaseNode & { type: "ImportAttribute", key: Identifier | Literal, value: Literal }} ImportAttribute */
104
- /** @typedef {import("estree").ImportDeclaration & { attributes?: Array<ImportAttribute> }} ImportDeclaration */
105
- /** @typedef {import("estree").ExportNamedDeclaration & { attributes?: Array<ImportAttribute> }} ExportNamedDeclaration */
106
- /** @typedef {import("estree").ExportAllDeclaration & { attributes?: Array<ImportAttribute> }} ExportAllDeclaration */
107
- /** @typedef {import("estree").ImportExpression & { options?: Expression | null }} ImportExpression */
108
- /** @typedef {ImportDeclaration | ExportNamedDeclaration | ExportDefaultDeclaration | ExportAllDeclaration} ModuleDeclaration */
128
+ /** @typedef {import("estree").ImportExpression & { phase?: "defer" }} ImportExpression */
109
129
 
110
130
  /** @type {string[]} */
111
131
  const EMPTY_ARRAY = [];
@@ -115,69 +135,71 @@ const ALLOWED_MEMBER_TYPES_ALL = 0b11;
115
135
 
116
136
  const LEGACY_ASSERT_ATTRIBUTES = Symbol("assert");
117
137
 
118
- /**
119
- * @param {any} Parser parser
120
- * @returns {typeof AcornParser} extender acorn parser
121
- */
122
- const importAssertions = Parser =>
123
- /** @type {typeof AcornParser} */ (
124
- /** @type {unknown} */ (
125
- class extends Parser {
126
- parseWithClause() {
127
- const nodes = [];
128
-
129
- const isAssertLegacy = this.value === "assert";
130
-
131
- if (isAssertLegacy) {
132
- if (!this.eat(tokTypes.name)) {
133
- return nodes;
134
- }
135
- } else if (!this.eat(tokTypes._with)) {
136
- return nodes;
137
- }
138
-
139
- this.expect(tokTypes.braceL);
138
+ /** @type {(BaseParser: typeof AcornParser) => typeof AcornParser} */
139
+ const importAssertions = (Parser) =>
140
+ class extends Parser {
141
+ /**
142
+ * @this {InstanceType<AcornParser>}
143
+ * @returns {ImportAttribute[]} import attributes
144
+ */
145
+ parseWithClause() {
146
+ /** @type {ImportAttribute[]} */
147
+ const nodes = [];
140
148
 
141
- const attributeKeys = {};
142
- let first = true;
149
+ const isAssertLegacy = this.value === "assert";
143
150
 
144
- while (!this.eat(tokTypes.braceR)) {
145
- if (!first) {
146
- this.expect(tokTypes.comma);
147
- if (this.afterTrailingComma(tokTypes.braceR)) {
148
- break;
149
- }
150
- } else {
151
- first = false;
152
- }
151
+ if (isAssertLegacy) {
152
+ if (!this.eat(tokTypes.name)) {
153
+ return nodes;
154
+ }
155
+ } else if (!this.eat(tokTypes._with)) {
156
+ return nodes;
157
+ }
153
158
 
154
- const attr = this.parseImportAttribute();
155
- const keyName =
156
- attr.key.type === "Identifier" ? attr.key.name : attr.key.value;
159
+ this.expect(tokTypes.braceL);
157
160
 
158
- if (Object.prototype.hasOwnProperty.call(attributeKeys, keyName)) {
159
- this.raiseRecoverable(
160
- attr.key.start,
161
- `Duplicate attribute key '${keyName}'`
162
- );
163
- }
161
+ /** @type {Record<string, boolean>} */
162
+ const attributeKeys = {};
163
+ let first = true;
164
164
 
165
- attributeKeys[keyName] = true;
166
- nodes.push(attr);
165
+ while (!this.eat(tokTypes.braceR)) {
166
+ if (!first) {
167
+ this.expect(tokTypes.comma);
168
+ if (this.afterTrailingComma(tokTypes.braceR)) {
169
+ break;
167
170
  }
171
+ } else {
172
+ first = false;
173
+ }
168
174
 
169
- if (isAssertLegacy) {
170
- nodes[LEGACY_ASSERT_ATTRIBUTES] = true;
171
- }
175
+ const attr =
176
+ /** @type {ImportAttribute} */
177
+ this.parseImportAttribute();
178
+ const keyName =
179
+ attr.key.type === "Identifier" ? attr.key.name : attr.key.value;
172
180
 
173
- return nodes;
181
+ if (Object.prototype.hasOwnProperty.call(attributeKeys, keyName)) {
182
+ this.raiseRecoverable(
183
+ attr.key.start,
184
+ `Duplicate attribute key '${keyName}'`
185
+ );
174
186
  }
187
+
188
+ attributeKeys[keyName] = true;
189
+ nodes.push(attr);
175
190
  }
176
- )
177
- );
191
+
192
+ if (isAssertLegacy) {
193
+ /** @type {EXPECTED_ANY} */
194
+ (nodes)[LEGACY_ASSERT_ATTRIBUTES] = true;
195
+ }
196
+
197
+ return nodes;
198
+ }
199
+ };
178
200
 
179
201
  // Syntax: https://developer.mozilla.org/en/SpiderMonkey/Parser_API
180
- const parser = AcornParser.extend(importAssertions);
202
+ let parser = AcornParser.extend(importAssertions);
181
203
 
182
204
  /** @typedef {Record<string, string> & { _isLegacyAssert?: boolean }} ImportAttributes */
183
205
 
@@ -185,7 +207,7 @@ const parser = AcornParser.extend(importAssertions);
185
207
  * @param {ImportDeclaration | ExportNamedDeclaration | ExportAllDeclaration | ImportExpression} node node with assertions
186
208
  * @returns {ImportAttributes | undefined} import attributes
187
209
  */
188
- const getImportAttributes = node => {
210
+ const getImportAttributes = (node) => {
189
211
  if (node.type === "ImportExpression") {
190
212
  if (
191
213
  node.options &&
@@ -247,37 +269,107 @@ const getImportAttributes = node => {
247
269
  result[key] = /** @type {string} */ (attribute.value.value);
248
270
  }
249
271
 
250
- if (node.attributes[LEGACY_ASSERT_ATTRIBUTES]) {
272
+ if (/** @type {EXPECTED_ANY} */ (node.attributes)[LEGACY_ASSERT_ATTRIBUTES]) {
251
273
  result._isLegacyAssert = true;
252
274
  }
253
275
 
254
276
  return result;
255
277
  };
256
278
 
279
+ /** @typedef {typeof VariableInfoFlags.Evaluated | typeof VariableInfoFlags.Free | typeof VariableInfoFlags.Normal | typeof VariableInfoFlags.Tagged} VariableInfoFlagsType */
280
+
281
+ const VariableInfoFlags = Object.freeze({
282
+ Evaluated: 0b000,
283
+ Free: 0b001,
284
+ Normal: 0b010,
285
+ Tagged: 0b100
286
+ });
287
+
257
288
  class VariableInfo {
258
289
  /**
259
290
  * @param {ScopeInfo} declaredScope scope in which the variable is declared
260
- * @param {string | true | undefined} freeName which free name the variable aliases, or true when none
291
+ * @param {string | undefined} name which name the variable use, defined name or free name or tagged name
292
+ * @param {VariableInfoFlagsType} flags how the variable is created
261
293
  * @param {TagInfo | undefined} tagInfo info about tags
262
294
  */
263
- constructor(declaredScope, freeName, tagInfo) {
295
+ constructor(declaredScope, name, flags, tagInfo) {
264
296
  this.declaredScope = declaredScope;
265
- this.freeName = freeName;
297
+ this.name = name;
298
+ this.flags = flags;
266
299
  this.tagInfo = tagInfo;
267
300
  }
301
+
302
+ /**
303
+ * @returns {boolean} the variable is free or not
304
+ */
305
+ isFree() {
306
+ return (this.flags & VariableInfoFlags.Free) > 0;
307
+ }
308
+
309
+ /**
310
+ * @returns {boolean} the variable is tagged by tagVariable or not
311
+ */
312
+ isTagged() {
313
+ return (this.flags & VariableInfoFlags.Tagged) > 0;
314
+ }
268
315
  }
269
316
 
270
317
  /** @typedef {string | ScopeInfo | VariableInfo} ExportedVariableInfo */
271
318
  /** @typedef {Literal | string | null | undefined} ImportSource */
272
- /** @typedef {Omit<AcornOptions, "sourceType" | "ecmaVersion"> & { sourceType: "module" | "script" | "auto", ecmaVersion?: AcornOptions["ecmaVersion"] }} ParseOptions */
319
+
320
+ /**
321
+ * @typedef {Omit<ParseOptions, "sourceType"> & {sourceType: "module" | "script" | "auto"}} InternalParseOptions
322
+ */
323
+
324
+ /**
325
+ * @typedef {object} ParseOptions
326
+ * @property {"module" | "script"} sourceType
327
+ * @property {EcmaVersion=} ecmaVersion
328
+ * @property {boolean=} locations
329
+ * @property {boolean=} comments
330
+ * @property {boolean=} ranges
331
+ * @property {boolean=} semicolons
332
+ * @property {boolean=} allowHashBang
333
+ * @property {boolean=} allowReturnOutsideFunction
334
+ */
335
+
336
+ /**
337
+ * @typedef {object} ParseResult
338
+ * @property {Program} ast
339
+ * @property {Comment[]} comments
340
+ * @property {Set<number>} semicolons
341
+ */
342
+
343
+ /**
344
+ * @typedef {(code: string, options: ParseOptions) => ParseResult} ParseFunction
345
+ */
346
+
347
+ /** @typedef {symbol} Tag */
348
+
349
+ /** @typedef {import("../dependencies/HarmonyImportDependencyParserPlugin").HarmonySettings} HarmonySettings */
350
+ /** @typedef {import("../dependencies/ImportParserPlugin").ImportSettings} ImportSettings */
351
+ /** @typedef {import("../dependencies/CommonJsImportsParserPlugin").CommonJsImportSettings} CommonJsImportSettings */
352
+ /** @typedef {import("../CompatibilityPlugin").CompatibilitySettings} CompatibilitySettings */
353
+ /** @typedef {import("../optimize/InnerGraph").TopLevelSymbol} TopLevelSymbol */
354
+
355
+ /** @typedef {HarmonySettings | ImportSettings | CommonJsImportSettings | TopLevelSymbol | CompatibilitySettings} KnownTagData */
356
+ /** @typedef {KnownTagData | Record<string, EXPECTED_ANY>} TagData */
273
357
 
274
358
  /**
275
359
  * @typedef {object} TagInfo
276
- * @property {any} tag
277
- * @property {any} data
360
+ * @property {Tag} tag
361
+ * @property {TagData=} data
278
362
  * @property {TagInfo | undefined} next
279
363
  */
280
364
 
365
+ /** @typedef {string[]} CalleeMembers */
366
+ /** @typedef {string[]} Members */
367
+ /** @typedef {boolean[]} MembersOptionals */
368
+ /** @typedef {Range[]} MemberRanges */
369
+
370
+ const SCOPE_INFO_TERMINATED_RETURN = 1;
371
+ const SCOPE_INFO_TERMINATED_THROW = 2;
372
+
281
373
  /**
282
374
  * @typedef {object} ScopeInfo
283
375
  * @property {StackedMap<string, VariableInfo | ScopeInfo>} definitions
@@ -287,6 +379,7 @@ class VariableInfo {
287
379
  * @property {boolean} inTry
288
380
  * @property {boolean} isStrict
289
381
  * @property {boolean} isAsmJs
382
+ * @property {undefined | 1 | 2} terminated
290
383
  */
291
384
 
292
385
  /** @typedef {[number, number]} Range */
@@ -294,7 +387,9 @@ class VariableInfo {
294
387
  /**
295
388
  * @typedef {object} DestructuringAssignmentProperty
296
389
  * @property {string} id
297
- * @property {Range | undefined=} range
390
+ * @property {Range} range
391
+ * @property {SourceLocation} loc
392
+ * @property {Set<DestructuringAssignmentProperty> | undefined=} pattern
298
393
  * @property {boolean | string} shorthand
299
394
  */
300
395
 
@@ -302,9 +397,9 @@ class VariableInfo {
302
397
  * Helper function for joining two ranges into a single range. This is useful
303
398
  * when working with AST nodes, as it allows you to combine the ranges of child nodes
304
399
  * to create the range of the _parent node_.
305
- * @param {[number, number]} startRange start range to join
306
- * @param {[number, number]} endRange end range to join
307
- * @returns {[number, number]} joined range
400
+ * @param {Range} startRange start range to join
401
+ * @param {Range} endRange end range to join
402
+ * @returns {Range} joined range
308
403
  * @example
309
404
  * ```js
310
405
  * const startRange = [0, 5];
@@ -323,7 +418,7 @@ const joinRanges = (startRange, endRange) => {
323
418
  * Helper function used to generate a string representation of a
324
419
  * [member expression](https://github.com/estree/estree/blob/master/es5.md#memberexpression).
325
420
  * @param {string} object object to name
326
- * @param {string[]} membersReversed reversed list of members
421
+ * @param {Members} membersReversed reversed list of members
327
422
  * @returns {string} member expression as a string
328
423
  * @example
329
424
  * ```js
@@ -350,7 +445,7 @@ const objectAndMembersToName = (object, membersReversed) => {
350
445
  * @param {Expression | SpreadElement | Super} expression expression
351
446
  * @returns {string | "this" | undefined} name or variable info
352
447
  */
353
- const getRootName = expression => {
448
+ const getRootName = (expression) => {
354
449
  switch (expression.type) {
355
450
  case "Identifier":
356
451
  return expression.name;
@@ -363,15 +458,15 @@ const getRootName = expression => {
363
458
  }
364
459
  };
365
460
 
366
- /** @type {AcornOptions} */
461
+ /** @type {ParseOptions} */
367
462
  const defaultParserOptions = {
368
- ranges: true,
369
- locations: true,
370
- ecmaVersion: "latest",
371
463
  sourceType: "module",
464
+ ecmaVersion: "latest",
465
+ ranges: false,
466
+ locations: false,
467
+ comments: false,
372
468
  // https://github.com/tc39/proposal-hashbang
373
- allowHashBang: true,
374
- onComment: undefined
469
+ allowHashBang: true
375
470
  };
376
471
 
377
472
  const EMPTY_COMMENT_OPTIONS = {
@@ -379,16 +474,19 @@ const EMPTY_COMMENT_OPTIONS = {
379
474
  errors: null
380
475
  };
381
476
 
477
+ const CLASS_NAME = "JavascriptParser";
478
+
382
479
  class JavascriptParser extends Parser {
383
480
  /**
384
- * @param {"module" | "script" | "auto"} sourceType default source type
481
+ * @param {"module" | "script" | "auto"=} sourceType default source type
482
+ * @param {{ parse?: ParseFunction }=} options parser options
385
483
  */
386
- constructor(sourceType = "auto") {
484
+ constructor(sourceType = "auto", options = {}) {
387
485
  super();
388
486
  this.hooks = Object.freeze({
389
487
  /** @type {HookMap<SyncBailHook<[UnaryExpression], BasicEvaluatedExpression | null | undefined>>} */
390
488
  evaluateTypeof: new HookMap(() => new SyncBailHook(["expression"])),
391
- /** @type {HookMap<SyncBailHook<[Expression | SpreadElement | PrivateIdentifier], BasicEvaluatedExpression | null | undefined>>} */
489
+ /** @type {HookMap<SyncBailHook<[Expression | SpreadElement | PrivateIdentifier | Super], BasicEvaluatedExpression | null | undefined>>} */
392
490
  evaluate: new HookMap(() => new SyncBailHook(["expression"])),
393
491
  /** @type {HookMap<SyncBailHook<[Identifier | ThisExpression | MemberExpression | MetaProperty], BasicEvaluatedExpression | null | undefined>>} */
394
492
  evaluateIdentifier: new HookMap(() => new SyncBailHook(["expression"])),
@@ -408,27 +506,27 @@ class JavascriptParser extends Parser {
408
506
  evaluateCallExpressionMember: new HookMap(
409
507
  () => new SyncBailHook(["expression", "param"])
410
508
  ),
411
- /** @type {HookMap<SyncBailHook<[Expression | Declaration | PrivateIdentifier, number], boolean | void>>} */
509
+ /** @type {HookMap<SyncBailHook<[Expression | Declaration | PrivateIdentifier | MaybeNamedFunctionDeclaration | MaybeNamedClassDeclaration, number], boolean | void>>} */
412
510
  isPure: new HookMap(
413
511
  () => new SyncBailHook(["expression", "commentsStartPosition"])
414
512
  ),
415
- /** @type {SyncBailHook<[Statement | ModuleDeclaration], boolean | void>} */
513
+ /** @type {SyncBailHook<[Statement | ModuleDeclaration | MaybeNamedClassDeclaration | MaybeNamedFunctionDeclaration], boolean | void>} */
416
514
  preStatement: new SyncBailHook(["statement"]),
417
515
 
418
- /** @type {SyncBailHook<[Statement | ModuleDeclaration], boolean | void>} */
516
+ /** @type {SyncBailHook<[Statement | ModuleDeclaration | MaybeNamedClassDeclaration | MaybeNamedFunctionDeclaration], boolean | void>} */
419
517
  blockPreStatement: new SyncBailHook(["declaration"]),
420
- /** @type {SyncBailHook<[Statement | ModuleDeclaration], boolean | void>} */
518
+ /** @type {SyncBailHook<[Statement | ModuleDeclaration | MaybeNamedFunctionDeclaration | MaybeNamedClassDeclaration], boolean | void>} */
421
519
  statement: new SyncBailHook(["statement"]),
422
520
  /** @type {SyncBailHook<[IfStatement], boolean | void>} */
423
521
  statementIf: new SyncBailHook(["statement"]),
424
- /** @type {SyncBailHook<[Expression, ClassExpression | ClassDeclaration], boolean | void>} */
522
+ /** @type {SyncBailHook<[Expression, ClassExpression | ClassDeclaration | MaybeNamedClassDeclaration], boolean | void>} */
425
523
  classExtendsExpression: new SyncBailHook([
426
524
  "expression",
427
525
  "classDefinition"
428
526
  ]),
429
- /** @type {SyncBailHook<[MethodDefinition | PropertyDefinition | StaticBlock, ClassExpression | ClassDeclaration], boolean | void>} */
527
+ /** @type {SyncBailHook<[MethodDefinition | PropertyDefinition | StaticBlock, ClassExpression | ClassDeclaration | MaybeNamedClassDeclaration], boolean | void>} */
430
528
  classBodyElement: new SyncBailHook(["element", "classDefinition"]),
431
- /** @type {SyncBailHook<[Expression, MethodDefinition | PropertyDefinition, ClassExpression | ClassDeclaration], boolean | void>} */
529
+ /** @type {SyncBailHook<[Expression, MethodDefinition | PropertyDefinition, ClassExpression | ClassDeclaration | MaybeNamedClassDeclaration], boolean | void>} */
432
530
  classBodyValue: new SyncBailHook([
433
531
  "expression",
434
532
  "element",
@@ -451,8 +549,8 @@ class JavascriptParser extends Parser {
451
549
  exportImport: new SyncBailHook(["statement", "source"]),
452
550
  /** @type {SyncBailHook<[ExportDefaultDeclaration | ExportNamedDeclaration | ExportAllDeclaration, Declaration], boolean | void>} */
453
551
  exportDeclaration: new SyncBailHook(["statement", "declaration"]),
454
- /** @type {SyncBailHook<[ExportDefaultDeclaration, FunctionDeclaration | ClassDeclaration], boolean | void>} */
455
- exportExpression: new SyncBailHook(["statement", "declaration"]),
552
+ /** @type {SyncBailHook<[ExportDefaultDeclaration, MaybeNamedFunctionDeclaration | MaybeNamedClassDeclaration | Expression], boolean | void>} */
553
+ exportExpression: new SyncBailHook(["statement", "node"]),
456
554
  /** @type {SyncBailHook<[ExportDefaultDeclaration | ExportNamedDeclaration | ExportAllDeclaration, string, string, number | undefined], boolean | void>} */
457
555
  exportSpecifier: new SyncBailHook([
458
556
  "statement",
@@ -472,36 +570,42 @@ class JavascriptParser extends Parser {
472
570
  preDeclarator: new SyncBailHook(["declarator", "statement"]),
473
571
  /** @type {SyncBailHook<[VariableDeclarator, Statement], boolean | void>} */
474
572
  declarator: new SyncBailHook(["declarator", "statement"]),
475
- /** @type {HookMap<SyncBailHook<[Declaration], boolean | void>>} */
573
+ /** @type {HookMap<SyncBailHook<[Identifier], boolean | void>>} */
476
574
  varDeclaration: new HookMap(() => new SyncBailHook(["declaration"])),
477
- /** @type {HookMap<SyncBailHook<[Declaration], boolean | void>>} */
575
+ /** @type {HookMap<SyncBailHook<[Identifier], boolean | void>>} */
478
576
  varDeclarationLet: new HookMap(() => new SyncBailHook(["declaration"])),
479
- /** @type {HookMap<SyncBailHook<[Declaration], boolean | void>>} */
577
+ /** @type {HookMap<SyncBailHook<[Identifier], boolean | void>>} */
480
578
  varDeclarationConst: new HookMap(() => new SyncBailHook(["declaration"])),
481
- /** @type {HookMap<SyncBailHook<[Declaration], boolean | void>>} */
579
+ /** @type {HookMap<SyncBailHook<[Identifier], boolean | void>>} */
580
+ varDeclarationUsing: new HookMap(() => new SyncBailHook(["declaration"])),
581
+ /** @type {HookMap<SyncBailHook<[Identifier], boolean | void>>} */
482
582
  varDeclarationVar: new HookMap(() => new SyncBailHook(["declaration"])),
483
583
  /** @type {HookMap<SyncBailHook<[Identifier], boolean | void>>} */
484
584
  pattern: new HookMap(() => new SyncBailHook(["pattern"])),
585
+ /** @type {SyncBailHook<[Expression], boolean | void>} */
586
+ collectDestructuringAssignmentProperties: new SyncBailHook([
587
+ "expression"
588
+ ]),
485
589
  /** @type {HookMap<SyncBailHook<[Expression], boolean | void>>} */
486
590
  canRename: new HookMap(() => new SyncBailHook(["initExpression"])),
487
591
  /** @type {HookMap<SyncBailHook<[Expression], boolean | void>>} */
488
592
  rename: new HookMap(() => new SyncBailHook(["initExpression"])),
489
593
  /** @type {HookMap<SyncBailHook<[AssignmentExpression], boolean | void>>} */
490
594
  assign: new HookMap(() => new SyncBailHook(["expression"])),
491
- /** @type {HookMap<SyncBailHook<[AssignmentExpression, string[]], boolean | void>>} */
595
+ /** @type {HookMap<SyncBailHook<[AssignmentExpression, Members], boolean | void>>} */
492
596
  assignMemberChain: new HookMap(
493
597
  () => new SyncBailHook(["expression", "members"])
494
598
  ),
495
599
  /** @type {HookMap<SyncBailHook<[Expression], boolean | void>>} */
496
600
  typeof: new HookMap(() => new SyncBailHook(["expression"])),
497
- /** @type {SyncBailHook<[ImportExpression], boolean | void>} */
498
- importCall: new SyncBailHook(["expression"]),
601
+ /** @type {SyncBailHook<[ImportExpression, CallExpression?], boolean | void>} */
602
+ importCall: new SyncBailHook(["expression", "importThen"]),
499
603
  /** @type {SyncBailHook<[Expression | ForOfStatement], boolean | void>} */
500
604
  topLevelAwait: new SyncBailHook(["expression"]),
501
605
  /** @type {HookMap<SyncBailHook<[CallExpression], boolean | void>>} */
502
606
  call: new HookMap(() => new SyncBailHook(["expression"])),
503
607
  /** Something like "a.b()" */
504
- /** @type {HookMap<SyncBailHook<[CallExpression, string[], boolean[], Range[]], boolean | void>>} */
608
+ /** @type {HookMap<SyncBailHook<[CallExpression, Members, MembersOptionals, MemberRanges], boolean | void>>} */
505
609
  callMemberChain: new HookMap(
506
610
  () =>
507
611
  new SyncBailHook([
@@ -512,7 +616,7 @@ class JavascriptParser extends Parser {
512
616
  ])
513
617
  ),
514
618
  /** Something like "a.b().c.d" */
515
- /** @type {HookMap<SyncBailHook<[Expression, string[], CallExpression, string[], Range[]], boolean | void>>} */
619
+ /** @type {HookMap<SyncBailHook<[Expression, CalleeMembers, CallExpression, Members, MemberRanges], boolean | void>>} */
516
620
  memberChainOfCallMemberChain: new HookMap(
517
621
  () =>
518
622
  new SyncBailHook([
@@ -524,7 +628,7 @@ class JavascriptParser extends Parser {
524
628
  ])
525
629
  ),
526
630
  /** Something like "a.b().c.d()"" */
527
- /** @type {HookMap<SyncBailHook<[CallExpression, string[], CallExpression, string[], Range[]], boolean | void>>} */
631
+ /** @type {HookMap<SyncBailHook<[CallExpression, CalleeMembers, CallExpression, Members, MemberRanges], boolean | void>>} */
528
632
  callMemberChainOfCallMemberChain: new HookMap(
529
633
  () =>
530
634
  new SyncBailHook([
@@ -543,7 +647,7 @@ class JavascriptParser extends Parser {
543
647
  binaryExpression: new SyncBailHook(["binaryExpression"]),
544
648
  /** @type {HookMap<SyncBailHook<[Expression], boolean | void>>} */
545
649
  expression: new HookMap(() => new SyncBailHook(["expression"])),
546
- /** @type {HookMap<SyncBailHook<[MemberExpression, string[], boolean[], Range[]], boolean | void>>} */
650
+ /** @type {HookMap<SyncBailHook<[MemberExpression, Members, MembersOptionals, MemberRanges], boolean | void>>} */
547
651
  expressionMemberChain: new HookMap(
548
652
  () =>
549
653
  new SyncBailHook([
@@ -553,7 +657,7 @@ class JavascriptParser extends Parser {
553
657
  "memberRanges"
554
658
  ])
555
659
  ),
556
- /** @type {HookMap<SyncBailHook<[MemberExpression, string[]], boolean | void>>} */
660
+ /** @type {HookMap<SyncBailHook<[MemberExpression, Members], boolean | void>>} */
557
661
  unhandledExpressionMemberChain: new HookMap(
558
662
  () => new SyncBailHook(["expression", "members"])
559
663
  ),
@@ -563,31 +667,38 @@ class JavascriptParser extends Parser {
563
667
  expressionLogicalOperator: new SyncBailHook(["expression"]),
564
668
  /** @type {SyncBailHook<[Program, Comment[]], boolean | void>} */
565
669
  program: new SyncBailHook(["ast", "comments"]),
670
+ /** @type {SyncBailHook<[ThrowStatement | ReturnStatement], boolean | void>} */
671
+ terminate: new SyncBailHook(["statement"]),
566
672
  /** @type {SyncBailHook<[Program, Comment[]], boolean | void>} */
567
- finish: new SyncBailHook(["ast", "comments"])
673
+ finish: new SyncBailHook(["ast", "comments"]),
674
+ /** @type {SyncBailHook<[Statement], boolean | void>} */
675
+ unusedStatement: new SyncBailHook(["statement"])
568
676
  });
569
677
  this.sourceType = sourceType;
678
+ this.options = options;
679
+
570
680
  /** @type {ScopeInfo} */
571
- this.scope = undefined;
572
- /** @type {ParserState} */
573
- this.state = undefined;
681
+ this.scope = /** @type {EXPECTED_ANY} */ (undefined);
682
+ /** @type {JavascriptParserState} */
683
+ this.state = /** @type {EXPECTED_ANY} */ (undefined);
574
684
  /** @type {Comment[] | undefined} */
575
685
  this.comments = undefined;
576
686
  /** @type {Set<number> | undefined} */
577
687
  this.semicolons = undefined;
578
688
  /** @type {StatementPath | undefined} */
579
689
  this.statementPath = undefined;
580
- /** @type {Statement | ModuleDeclaration | Expression | undefined} */
690
+ /** @type {Statement | ModuleDeclaration | Expression | MaybeNamedFunctionDeclaration | MaybeNamedClassDeclaration | undefined} */
581
691
  this.prevStatement = undefined;
582
- /** @type {WeakMap<Expression, Set<DestructuringAssignmentProperty>> | undefined} */
692
+ /** @type {WeakMap<Expression, DestructuringAssignmentProperties> | undefined} */
583
693
  this.destructuringAssignmentProperties = undefined;
694
+ /** @type {TagData | undefined} */
584
695
  this.currentTagData = undefined;
585
696
  this.magicCommentContext = createMagicCommentContext();
586
697
  this._initializeEvaluating();
587
698
  }
588
699
 
589
700
  _initializeEvaluating() {
590
- this.hooks.evaluate.for("Literal").tap("JavascriptParser", _expr => {
701
+ this.hooks.evaluate.for("Literal").tap(CLASS_NAME, (_expr) => {
591
702
  const expr = /** @type {Literal} */ (_expr);
592
703
 
593
704
  switch (typeof expr.value) {
@@ -619,7 +730,7 @@ class JavascriptParser extends Parser {
619
730
  .setRange(/** @type {Range} */ (expr.range));
620
731
  }
621
732
  });
622
- this.hooks.evaluate.for("NewExpression").tap("JavascriptParser", _expr => {
733
+ this.hooks.evaluate.for("NewExpression").tap(CLASS_NAME, (_expr) => {
623
734
  const expr = /** @type {NewExpression} */ (_expr);
624
735
  const callee = expr.callee;
625
736
  if (callee.type !== "Identifier") return;
@@ -632,8 +743,9 @@ class JavascriptParser extends Parser {
632
743
  } else if (
633
744
  expr.arguments.length > 2 ||
634
745
  this.getVariableInfo("RegExp") !== "RegExp"
635
- )
746
+ ) {
636
747
  return;
748
+ }
637
749
 
638
750
  let regExp;
639
751
  const arg1 = expr.arguments[0];
@@ -673,8 +785,9 @@ class JavascriptParser extends Parser {
673
785
  if (
674
786
  flags === undefined ||
675
787
  !BasicEvaluatedExpression.isValidRegExpFlags(flags)
676
- )
788
+ ) {
677
789
  return;
790
+ }
678
791
  }
679
792
  }
680
793
 
@@ -682,52 +795,55 @@ class JavascriptParser extends Parser {
682
795
  .setRegExp(flags ? new RegExp(regExp, flags) : new RegExp(regExp))
683
796
  .setRange(/** @type {Range} */ (expr.range));
684
797
  });
685
- this.hooks.evaluate
686
- .for("LogicalExpression")
687
- .tap("JavascriptParser", _expr => {
688
- const expr = /** @type {LogicalExpression} */ (_expr);
689
-
690
- const left = this.evaluateExpression(expr.left);
691
- let returnRight = false;
692
- /** @type {boolean | undefined} */
693
- let allowedRight;
694
- if (expr.operator === "&&") {
695
- const leftAsBool = left.asBool();
696
- if (leftAsBool === false)
697
- return left.setRange(/** @type {Range} */ (expr.range));
698
- returnRight = leftAsBool === true;
699
- allowedRight = false;
700
- } else if (expr.operator === "||") {
701
- const leftAsBool = left.asBool();
702
- if (leftAsBool === true)
703
- return left.setRange(/** @type {Range} */ (expr.range));
704
- returnRight = leftAsBool === false;
705
- allowedRight = true;
706
- } else if (expr.operator === "??") {
707
- const leftAsNullish = left.asNullish();
708
- if (leftAsNullish === false)
709
- return left.setRange(/** @type {Range} */ (expr.range));
710
- if (leftAsNullish !== true) return;
711
- returnRight = true;
712
- } else return;
713
- const right = this.evaluateExpression(expr.right);
714
- if (returnRight) {
715
- if (left.couldHaveSideEffects()) right.setSideEffects();
716
- return right.setRange(/** @type {Range} */ (expr.range));
798
+ this.hooks.evaluate.for("LogicalExpression").tap(CLASS_NAME, (_expr) => {
799
+ const expr = /** @type {LogicalExpression} */ (_expr);
800
+
801
+ const left = this.evaluateExpression(expr.left);
802
+ let returnRight = false;
803
+ /** @type {boolean | undefined} */
804
+ let allowedRight;
805
+ if (expr.operator === "&&") {
806
+ const leftAsBool = left.asBool();
807
+ if (leftAsBool === false) {
808
+ return left.setRange(/** @type {Range} */ (expr.range));
809
+ }
810
+ returnRight = leftAsBool === true;
811
+ allowedRight = false;
812
+ } else if (expr.operator === "||") {
813
+ const leftAsBool = left.asBool();
814
+ if (leftAsBool === true) {
815
+ return left.setRange(/** @type {Range} */ (expr.range));
816
+ }
817
+ returnRight = leftAsBool === false;
818
+ allowedRight = true;
819
+ } else if (expr.operator === "??") {
820
+ const leftAsNullish = left.asNullish();
821
+ if (leftAsNullish === false) {
822
+ return left.setRange(/** @type {Range} */ (expr.range));
717
823
  }
824
+ if (leftAsNullish !== true) return;
825
+ returnRight = true;
826
+ } else {
827
+ return;
828
+ }
829
+ const right = this.evaluateExpression(expr.right);
830
+ if (returnRight) {
831
+ if (left.couldHaveSideEffects()) right.setSideEffects();
832
+ return right.setRange(/** @type {Range} */ (expr.range));
833
+ }
718
834
 
719
- const asBool = right.asBool();
835
+ const asBool = right.asBool();
720
836
 
721
- if (allowedRight === true && asBool === true) {
722
- return new BasicEvaluatedExpression()
723
- .setRange(/** @type {Range} */ (expr.range))
724
- .setTruthy();
725
- } else if (allowedRight === false && asBool === false) {
726
- return new BasicEvaluatedExpression()
727
- .setRange(/** @type {Range} */ (expr.range))
728
- .setFalsy();
729
- }
730
- });
837
+ if (allowedRight === true && asBool === true) {
838
+ return new BasicEvaluatedExpression()
839
+ .setRange(/** @type {Range} */ (expr.range))
840
+ .setTruthy();
841
+ } else if (allowedRight === false && asBool === false) {
842
+ return new BasicEvaluatedExpression()
843
+ .setRange(/** @type {Range} */ (expr.range))
844
+ .setFalsy();
845
+ }
846
+ });
731
847
 
732
848
  /**
733
849
  * In simple logical cases, we can use valueAsExpression to assist us in evaluating the expression on
@@ -797,550 +913,541 @@ class JavascriptParser extends Parser {
797
913
  }
798
914
  };
799
915
 
800
- this.hooks.evaluate
801
- .for("BinaryExpression")
802
- .tap("JavascriptParser", _expr => {
803
- const expr = /** @type {BinaryExpression} */ (_expr);
804
-
805
- /**
806
- * Evaluates a binary expression if and only if it is a const operation (e.g. 1 + 2, "a" + "b", etc.).
807
- * @template T
808
- * @param {(leftOperand: T, rightOperand: T) => boolean | number | bigint | string} operandHandler the handler for the operation (e.g. (a, b) => a + b)
809
- * @returns {BasicEvaluatedExpression | undefined} the evaluated expression
810
- */
811
- const handleConstOperation = operandHandler => {
812
- const left = this.evaluateExpression(expr.left);
813
- if (!left.isCompileTimeValue()) return;
916
+ this.hooks.evaluate.for("BinaryExpression").tap(CLASS_NAME, (_expr) => {
917
+ const expr = /** @type {BinaryExpression} */ (_expr);
814
918
 
815
- const right = this.evaluateExpression(expr.right);
816
- if (!right.isCompileTimeValue()) return;
919
+ /**
920
+ * Evaluates a binary expression if and only if it is a const operation (e.g. 1 + 2, "a" + "b", etc.).
921
+ * @template T
922
+ * @param {(leftOperand: T, rightOperand: T) => boolean | number | bigint | string} operandHandler the handler for the operation (e.g. (a, b) => a + b)
923
+ * @returns {BasicEvaluatedExpression | undefined} the evaluated expression
924
+ */
925
+ const handleConstOperation = (operandHandler) => {
926
+ const left = this.evaluateExpression(expr.left);
927
+ if (!left.isCompileTimeValue()) return;
817
928
 
818
- const result = operandHandler(
819
- left.asCompileTimeValue(),
820
- right.asCompileTimeValue()
821
- );
822
- return valueAsExpression(
823
- result,
824
- expr,
825
- left.couldHaveSideEffects() || right.couldHaveSideEffects()
826
- );
827
- };
929
+ const right = this.evaluateExpression(expr.right);
930
+ if (!right.isCompileTimeValue()) return;
828
931
 
829
- /**
830
- * Helper function to determine if two booleans are always different. This is used in `handleStrictEqualityComparison`
831
- * to determine if an expressions boolean or nullish conversion is equal or not.
832
- * @param {boolean} a first boolean to compare
833
- * @param {boolean} b second boolean to compare
834
- * @returns {boolean} true if the two booleans are always different, false otherwise
835
- */
836
- const isAlwaysDifferent = (a, b) =>
837
- (a === true && b === false) || (a === false && b === true);
932
+ const result = operandHandler(
933
+ /** @type {T} */ (left.asCompileTimeValue()),
934
+ /** @type {T} */ (right.asCompileTimeValue())
935
+ );
936
+ return valueAsExpression(
937
+ result,
938
+ expr,
939
+ left.couldHaveSideEffects() || right.couldHaveSideEffects()
940
+ );
941
+ };
838
942
 
943
+ /**
944
+ * Helper function to determine if two booleans are always different. This is used in `handleStrictEqualityComparison`
945
+ * to determine if an expressions boolean or nullish conversion is equal or not.
946
+ * @param {boolean} a first boolean to compare
947
+ * @param {boolean} b second boolean to compare
948
+ * @returns {boolean} true if the two booleans are always different, false otherwise
949
+ */
950
+ const isAlwaysDifferent = (a, b) =>
951
+ (a === true && b === false) || (a === false && b === true);
952
+
953
+ /**
954
+ * @param {BasicEvaluatedExpression} left left
955
+ * @param {BasicEvaluatedExpression} right right
956
+ * @param {BasicEvaluatedExpression} res res
957
+ * @param {boolean} eql true for "===" and false for "!=="
958
+ * @returns {BasicEvaluatedExpression | undefined} result
959
+ */
960
+ const handleTemplateStringCompare = (left, right, res, eql) => {
839
961
  /**
840
- * @param {BasicEvaluatedExpression} left left
841
- * @param {BasicEvaluatedExpression} right right
842
- * @param {BasicEvaluatedExpression} res res
843
- * @param {boolean} eql true for "===" and false for "!=="
844
- * @returns {BasicEvaluatedExpression | undefined} result
962
+ * @param {BasicEvaluatedExpression[]} parts parts
963
+ * @returns {string} value
845
964
  */
846
- const handleTemplateStringCompare = (left, right, res, eql) => {
847
- /**
848
- * @param {BasicEvaluatedExpression[]} parts parts
849
- * @returns {string} value
850
- */
851
- const getPrefix = parts => {
852
- let value = "";
853
- for (const p of parts) {
854
- const v = p.asString();
855
- if (v !== undefined) value += v;
856
- else break;
857
- }
858
- return value;
859
- };
860
- /**
861
- * @param {BasicEvaluatedExpression[]} parts parts
862
- * @returns {string} value
863
- */
864
- const getSuffix = parts => {
865
- let value = "";
866
- for (let i = parts.length - 1; i >= 0; i--) {
867
- const v = parts[i].asString();
868
- if (v !== undefined) value = v + value;
869
- else break;
870
- }
871
- return value;
872
- };
873
- const leftPrefix = getPrefix(
874
- /** @type {BasicEvaluatedExpression[]} */ (left.parts)
875
- );
876
- const rightPrefix = getPrefix(
877
- /** @type {BasicEvaluatedExpression[]} */ (right.parts)
878
- );
879
- const leftSuffix = getSuffix(
880
- /** @type {BasicEvaluatedExpression[]} */ (left.parts)
881
- );
882
- const rightSuffix = getSuffix(
883
- /** @type {BasicEvaluatedExpression[]} */ (right.parts)
884
- );
885
- const lenPrefix = Math.min(leftPrefix.length, rightPrefix.length);
886
- const lenSuffix = Math.min(leftSuffix.length, rightSuffix.length);
887
- const prefixMismatch =
888
- lenPrefix > 0 &&
889
- leftPrefix.slice(0, lenPrefix) !== rightPrefix.slice(0, lenPrefix);
890
- const suffixMismatch =
891
- lenSuffix > 0 &&
892
- leftSuffix.slice(-lenSuffix) !== rightSuffix.slice(-lenSuffix);
893
- if (prefixMismatch || suffixMismatch) {
894
- return res
895
- .setBoolean(!eql)
896
- .setSideEffects(
897
- left.couldHaveSideEffects() || right.couldHaveSideEffects()
898
- );
965
+ const getPrefix = (parts) => {
966
+ let value = "";
967
+ for (const p of parts) {
968
+ const v = p.asString();
969
+ if (v !== undefined) value += v;
970
+ else break;
899
971
  }
972
+ return value;
900
973
  };
901
-
902
974
  /**
903
- * Helper function to handle BinaryExpressions using strict equality comparisons (e.g. "===" and "!==").
904
- * @param {boolean} eql true for "===" and false for "!=="
905
- * @returns {BasicEvaluatedExpression | undefined} the evaluated expression
975
+ * @param {BasicEvaluatedExpression[]} parts parts
976
+ * @returns {string} value
906
977
  */
907
- const handleStrictEqualityComparison = eql => {
908
- const left = this.evaluateExpression(expr.left);
909
- const right = this.evaluateExpression(expr.right);
910
- const res = new BasicEvaluatedExpression();
911
- res.setRange(/** @type {Range} */ (expr.range));
912
-
913
- const leftConst = left.isCompileTimeValue();
914
- const rightConst = right.isCompileTimeValue();
915
-
916
- if (leftConst && rightConst) {
917
- return res
918
- .setBoolean(
919
- eql ===
920
- (left.asCompileTimeValue() === right.asCompileTimeValue())
921
- )
922
- .setSideEffects(
923
- left.couldHaveSideEffects() || right.couldHaveSideEffects()
924
- );
978
+ const getSuffix = (parts) => {
979
+ let value = "";
980
+ for (let i = parts.length - 1; i >= 0; i--) {
981
+ const v = parts[i].asString();
982
+ if (v !== undefined) value = v + value;
983
+ else break;
925
984
  }
985
+ return value;
986
+ };
987
+ const leftPrefix = getPrefix(
988
+ /** @type {BasicEvaluatedExpression[]} */ (left.parts)
989
+ );
990
+ const rightPrefix = getPrefix(
991
+ /** @type {BasicEvaluatedExpression[]} */ (right.parts)
992
+ );
993
+ const leftSuffix = getSuffix(
994
+ /** @type {BasicEvaluatedExpression[]} */ (left.parts)
995
+ );
996
+ const rightSuffix = getSuffix(
997
+ /** @type {BasicEvaluatedExpression[]} */ (right.parts)
998
+ );
999
+ const lenPrefix = Math.min(leftPrefix.length, rightPrefix.length);
1000
+ const lenSuffix = Math.min(leftSuffix.length, rightSuffix.length);
1001
+ const prefixMismatch =
1002
+ lenPrefix > 0 &&
1003
+ leftPrefix.slice(0, lenPrefix) !== rightPrefix.slice(0, lenPrefix);
1004
+ const suffixMismatch =
1005
+ lenSuffix > 0 &&
1006
+ leftSuffix.slice(-lenSuffix) !== rightSuffix.slice(-lenSuffix);
1007
+ if (prefixMismatch || suffixMismatch) {
1008
+ return res
1009
+ .setBoolean(!eql)
1010
+ .setSideEffects(
1011
+ left.couldHaveSideEffects() || right.couldHaveSideEffects()
1012
+ );
1013
+ }
1014
+ };
926
1015
 
927
- if (left.isArray() && right.isArray()) {
928
- return res
929
- .setBoolean(!eql)
930
- .setSideEffects(
931
- left.couldHaveSideEffects() || right.couldHaveSideEffects()
932
- );
933
- }
934
- if (left.isTemplateString() && right.isTemplateString()) {
935
- return handleTemplateStringCompare(left, right, res, eql);
936
- }
1016
+ /**
1017
+ * Helper function to handle BinaryExpressions using strict equality comparisons (e.g. "===" and "!==").
1018
+ * @param {boolean} eql true for "===" and false for "!=="
1019
+ * @returns {BasicEvaluatedExpression | undefined} the evaluated expression
1020
+ */
1021
+ const handleStrictEqualityComparison = (eql) => {
1022
+ const left = this.evaluateExpression(expr.left);
1023
+ const right = this.evaluateExpression(expr.right);
1024
+ const res = new BasicEvaluatedExpression();
1025
+ res.setRange(/** @type {Range} */ (expr.range));
937
1026
 
938
- const leftPrimitive = left.isPrimitiveType();
939
- const rightPrimitive = right.isPrimitiveType();
1027
+ const leftConst = left.isCompileTimeValue();
1028
+ const rightConst = right.isCompileTimeValue();
940
1029
 
941
- if (
942
- // Primitive !== Object or
943
- // compile-time object types are never equal to something at runtime
944
- (leftPrimitive === false &&
945
- (leftConst || rightPrimitive === true)) ||
946
- (rightPrimitive === false &&
947
- (rightConst || leftPrimitive === true)) ||
948
- // Different nullish or boolish status also means not equal
949
- isAlwaysDifferent(
950
- /** @type {boolean} */ (left.asBool()),
951
- /** @type {boolean} */ (right.asBool())
952
- ) ||
953
- isAlwaysDifferent(
954
- /** @type {boolean} */ (left.asNullish()),
955
- /** @type {boolean} */ (right.asNullish())
1030
+ if (leftConst && rightConst) {
1031
+ return res
1032
+ .setBoolean(
1033
+ eql === (left.asCompileTimeValue() === right.asCompileTimeValue())
956
1034
  )
957
- ) {
958
- return res
959
- .setBoolean(!eql)
960
- .setSideEffects(
961
- left.couldHaveSideEffects() || right.couldHaveSideEffects()
962
- );
963
- }
964
- };
1035
+ .setSideEffects(
1036
+ left.couldHaveSideEffects() || right.couldHaveSideEffects()
1037
+ );
1038
+ }
965
1039
 
966
- /**
967
- * Helper function to handle BinaryExpressions using abstract equality comparisons (e.g. "==" and "!=").
968
- * @param {boolean} eql true for "==" and false for "!="
969
- * @returns {BasicEvaluatedExpression | undefined} the evaluated expression
970
- */
971
- const handleAbstractEqualityComparison = eql => {
972
- const left = this.evaluateExpression(expr.left);
973
- const right = this.evaluateExpression(expr.right);
974
- const res = new BasicEvaluatedExpression();
975
- res.setRange(/** @type {Range} */ (expr.range));
976
-
977
- const leftConst = left.isCompileTimeValue();
978
- const rightConst = right.isCompileTimeValue();
979
-
980
- if (leftConst && rightConst) {
981
- return res
982
- .setBoolean(
983
- eql ===
984
- // eslint-disable-next-line eqeqeq
985
- (left.asCompileTimeValue() == right.asCompileTimeValue())
986
- )
987
- .setSideEffects(
988
- left.couldHaveSideEffects() || right.couldHaveSideEffects()
989
- );
990
- }
1040
+ if (left.isArray() && right.isArray()) {
1041
+ return res
1042
+ .setBoolean(!eql)
1043
+ .setSideEffects(
1044
+ left.couldHaveSideEffects() || right.couldHaveSideEffects()
1045
+ );
1046
+ }
1047
+ if (left.isTemplateString() && right.isTemplateString()) {
1048
+ return handleTemplateStringCompare(left, right, res, eql);
1049
+ }
991
1050
 
992
- if (left.isArray() && right.isArray()) {
993
- return res
994
- .setBoolean(!eql)
995
- .setSideEffects(
996
- left.couldHaveSideEffects() || right.couldHaveSideEffects()
997
- );
998
- }
999
- if (left.isTemplateString() && right.isTemplateString()) {
1000
- return handleTemplateStringCompare(left, right, res, eql);
1001
- }
1002
- };
1051
+ const leftPrimitive = left.isPrimitiveType();
1052
+ const rightPrimitive = right.isPrimitiveType();
1003
1053
 
1004
- if (expr.operator === "+") {
1005
- const left = this.evaluateExpression(expr.left);
1006
- const right = this.evaluateExpression(expr.right);
1007
- const res = new BasicEvaluatedExpression();
1008
- if (left.isString()) {
1009
- if (right.isString()) {
1010
- res.setString(
1011
- /** @type {string} */ (left.string) +
1012
- /** @type {string} */ (right.string)
1013
- );
1014
- } else if (right.isNumber()) {
1015
- res.setString(/** @type {string} */ (left.string) + right.number);
1016
- } else if (
1017
- right.isWrapped() &&
1018
- right.prefix &&
1019
- right.prefix.isString()
1020
- ) {
1021
- // "left" + ("prefix" + inner + "postfix")
1022
- // => ("leftPrefix" + inner + "postfix")
1023
- res.setWrapped(
1024
- new BasicEvaluatedExpression()
1025
- .setString(
1026
- /** @type {string} */ (left.string) +
1027
- /** @type {string} */ (right.prefix.string)
1028
- )
1029
- .setRange(
1030
- joinRanges(
1031
- /** @type {Range} */ (left.range),
1032
- /** @type {Range} */ (right.prefix.range)
1033
- )
1034
- ),
1035
- right.postfix,
1036
- right.wrappedInnerExpressions
1037
- );
1038
- } else if (right.isWrapped()) {
1039
- // "left" + ([null] + inner + "postfix")
1040
- // => ("left" + inner + "postfix")
1041
- res.setWrapped(
1042
- left,
1043
- right.postfix,
1044
- right.wrappedInnerExpressions
1045
- );
1046
- } else {
1047
- // "left" + expr
1048
- // => ("left" + expr + "")
1049
- res.setWrapped(left, null, [right]);
1050
- }
1051
- } else if (left.isNumber()) {
1052
- if (right.isString()) {
1053
- res.setString(left.number + /** @type {string} */ (right.string));
1054
- } else if (right.isNumber()) {
1055
- res.setNumber(
1056
- /** @type {number} */ (left.number) +
1057
- /** @type {number} */ (right.number)
1058
- );
1059
- } else {
1060
- return;
1061
- }
1062
- } else if (left.isBigInt()) {
1063
- if (right.isBigInt()) {
1064
- res.setBigInt(
1065
- /** @type {bigint} */ (left.bigint) +
1066
- /** @type {bigint} */ (right.bigint)
1067
- );
1068
- }
1069
- } else if (left.isWrapped()) {
1070
- if (left.postfix && left.postfix.isString() && right.isString()) {
1071
- // ("prefix" + inner + "postfix") + "right"
1072
- // => ("prefix" + inner + "postfixRight")
1073
- res.setWrapped(
1074
- left.prefix,
1075
- new BasicEvaluatedExpression()
1076
- .setString(
1077
- /** @type {string} */ (left.postfix.string) +
1078
- /** @type {string} */ (right.string)
1054
+ if (
1055
+ // Primitive !== Object or
1056
+ // compile-time object types are never equal to something at runtime
1057
+ (leftPrimitive === false && (leftConst || rightPrimitive === true)) ||
1058
+ (rightPrimitive === false &&
1059
+ (rightConst || leftPrimitive === true)) ||
1060
+ // Different nullish or boolish status also means not equal
1061
+ isAlwaysDifferent(
1062
+ /** @type {boolean} */ (left.asBool()),
1063
+ /** @type {boolean} */ (right.asBool())
1064
+ ) ||
1065
+ isAlwaysDifferent(
1066
+ /** @type {boolean} */ (left.asNullish()),
1067
+ /** @type {boolean} */ (right.asNullish())
1068
+ )
1069
+ ) {
1070
+ return res
1071
+ .setBoolean(!eql)
1072
+ .setSideEffects(
1073
+ left.couldHaveSideEffects() || right.couldHaveSideEffects()
1074
+ );
1075
+ }
1076
+ };
1077
+
1078
+ /**
1079
+ * Helper function to handle BinaryExpressions using abstract equality comparisons (e.g. "==" and "!=").
1080
+ * @param {boolean} eql true for "==" and false for "!="
1081
+ * @returns {BasicEvaluatedExpression | undefined} the evaluated expression
1082
+ */
1083
+ const handleAbstractEqualityComparison = (eql) => {
1084
+ const left = this.evaluateExpression(expr.left);
1085
+ const right = this.evaluateExpression(expr.right);
1086
+ const res = new BasicEvaluatedExpression();
1087
+ res.setRange(/** @type {Range} */ (expr.range));
1088
+
1089
+ const leftConst = left.isCompileTimeValue();
1090
+ const rightConst = right.isCompileTimeValue();
1091
+
1092
+ if (leftConst && rightConst) {
1093
+ return res
1094
+ .setBoolean(
1095
+ eql ===
1096
+ // eslint-disable-next-line eqeqeq
1097
+ (left.asCompileTimeValue() == right.asCompileTimeValue())
1098
+ )
1099
+ .setSideEffects(
1100
+ left.couldHaveSideEffects() || right.couldHaveSideEffects()
1101
+ );
1102
+ }
1103
+
1104
+ if (left.isArray() && right.isArray()) {
1105
+ return res
1106
+ .setBoolean(!eql)
1107
+ .setSideEffects(
1108
+ left.couldHaveSideEffects() || right.couldHaveSideEffects()
1109
+ );
1110
+ }
1111
+ if (left.isTemplateString() && right.isTemplateString()) {
1112
+ return handleTemplateStringCompare(left, right, res, eql);
1113
+ }
1114
+ };
1115
+
1116
+ if (expr.operator === "+") {
1117
+ const left = this.evaluateExpression(expr.left);
1118
+ const right = this.evaluateExpression(expr.right);
1119
+ const res = new BasicEvaluatedExpression();
1120
+ if (left.isString()) {
1121
+ if (right.isString()) {
1122
+ res.setString(
1123
+ /** @type {string} */ (left.string) +
1124
+ /** @type {string} */ (right.string)
1125
+ );
1126
+ } else if (right.isNumber()) {
1127
+ res.setString(/** @type {string} */ (left.string) + right.number);
1128
+ } else if (
1129
+ right.isWrapped() &&
1130
+ right.prefix &&
1131
+ right.prefix.isString()
1132
+ ) {
1133
+ // "left" + ("prefix" + inner + "postfix")
1134
+ // => ("leftPrefix" + inner + "postfix")
1135
+ res.setWrapped(
1136
+ new BasicEvaluatedExpression()
1137
+ .setString(
1138
+ /** @type {string} */ (left.string) +
1139
+ /** @type {string} */ (right.prefix.string)
1140
+ )
1141
+ .setRange(
1142
+ joinRanges(
1143
+ /** @type {Range} */ (left.range),
1144
+ /** @type {Range} */ (right.prefix.range)
1079
1145
  )
1080
- .setRange(
1081
- joinRanges(
1082
- /** @type {Range} */ (left.postfix.range),
1083
- /** @type {Range} */ (right.range)
1084
- )
1085
- ),
1086
- left.wrappedInnerExpressions
1087
- );
1088
- } else if (
1089
- left.postfix &&
1090
- left.postfix.isString() &&
1091
- right.isNumber()
1092
- ) {
1093
- // ("prefix" + inner + "postfix") + 123
1094
- // => ("prefix" + inner + "postfix123")
1095
- res.setWrapped(
1096
- left.prefix,
1097
- new BasicEvaluatedExpression()
1098
- .setString(
1099
- /** @type {string} */ (left.postfix.string) +
1100
- /** @type {number} */ (right.number)
1146
+ ),
1147
+ right.postfix,
1148
+ right.wrappedInnerExpressions
1149
+ );
1150
+ } else if (right.isWrapped()) {
1151
+ // "left" + ([null] + inner + "postfix")
1152
+ // => ("left" + inner + "postfix")
1153
+ res.setWrapped(left, right.postfix, right.wrappedInnerExpressions);
1154
+ } else {
1155
+ // "left" + expr
1156
+ // => ("left" + expr + "")
1157
+ res.setWrapped(left, null, [right]);
1158
+ }
1159
+ } else if (left.isNumber()) {
1160
+ if (right.isString()) {
1161
+ res.setString(left.number + /** @type {string} */ (right.string));
1162
+ } else if (right.isNumber()) {
1163
+ res.setNumber(
1164
+ /** @type {number} */ (left.number) +
1165
+ /** @type {number} */ (right.number)
1166
+ );
1167
+ } else {
1168
+ return;
1169
+ }
1170
+ } else if (left.isBigInt()) {
1171
+ if (right.isBigInt()) {
1172
+ res.setBigInt(
1173
+ /** @type {bigint} */ (left.bigint) +
1174
+ /** @type {bigint} */ (right.bigint)
1175
+ );
1176
+ }
1177
+ } else if (left.isWrapped()) {
1178
+ if (left.postfix && left.postfix.isString() && right.isString()) {
1179
+ // ("prefix" + inner + "postfix") + "right"
1180
+ // => ("prefix" + inner + "postfixRight")
1181
+ res.setWrapped(
1182
+ left.prefix,
1183
+ new BasicEvaluatedExpression()
1184
+ .setString(
1185
+ /** @type {string} */ (left.postfix.string) +
1186
+ /** @type {string} */ (right.string)
1187
+ )
1188
+ .setRange(
1189
+ joinRanges(
1190
+ /** @type {Range} */ (left.postfix.range),
1191
+ /** @type {Range} */ (right.range)
1101
1192
  )
1102
- .setRange(
1103
- joinRanges(
1104
- /** @type {Range} */ (left.postfix.range),
1105
- /** @type {Range} */ (right.range)
1106
- )
1107
- ),
1108
- left.wrappedInnerExpressions
1109
- );
1110
- } else if (right.isString()) {
1111
- // ("prefix" + inner + [null]) + "right"
1112
- // => ("prefix" + inner + "right")
1113
- res.setWrapped(left.prefix, right, left.wrappedInnerExpressions);
1114
- } else if (right.isNumber()) {
1115
- // ("prefix" + inner + [null]) + 123
1116
- // => ("prefix" + inner + "123")
1117
- res.setWrapped(
1118
- left.prefix,
1119
- new BasicEvaluatedExpression()
1120
- .setString(String(right.number))
1121
- .setRange(/** @type {Range} */ (right.range)),
1122
- left.wrappedInnerExpressions
1123
- );
1124
- } else if (right.isWrapped()) {
1125
- // ("prefix1" + inner1 + "postfix1") + ("prefix2" + inner2 + "postfix2")
1126
- // ("prefix1" + inner1 + "postfix1" + "prefix2" + inner2 + "postfix2")
1127
- res.setWrapped(
1128
- left.prefix,
1129
- right.postfix,
1130
- left.wrappedInnerExpressions &&
1131
- right.wrappedInnerExpressions &&
1132
- left.wrappedInnerExpressions
1133
- .concat(left.postfix ? [left.postfix] : [])
1134
- .concat(right.prefix ? [right.prefix] : [])
1135
- .concat(right.wrappedInnerExpressions)
1136
- );
1137
- } else {
1138
- // ("prefix" + inner + postfix) + expr
1139
- // => ("prefix" + inner + postfix + expr + [null])
1140
- res.setWrapped(
1141
- left.prefix,
1142
- null,
1143
- left.wrappedInnerExpressions &&
1144
- left.wrappedInnerExpressions.concat(
1145
- left.postfix ? [left.postfix, right] : [right]
1193
+ ),
1194
+ left.wrappedInnerExpressions
1195
+ );
1196
+ } else if (
1197
+ left.postfix &&
1198
+ left.postfix.isString() &&
1199
+ right.isNumber()
1200
+ ) {
1201
+ // ("prefix" + inner + "postfix") + 123
1202
+ // => ("prefix" + inner + "postfix123")
1203
+ res.setWrapped(
1204
+ left.prefix,
1205
+ new BasicEvaluatedExpression()
1206
+ .setString(
1207
+ /** @type {string} */ (left.postfix.string) +
1208
+ /** @type {number} */ (right.number)
1209
+ )
1210
+ .setRange(
1211
+ joinRanges(
1212
+ /** @type {Range} */ (left.postfix.range),
1213
+ /** @type {Range} */ (right.range)
1146
1214
  )
1147
- );
1148
- }
1215
+ ),
1216
+ left.wrappedInnerExpressions
1217
+ );
1149
1218
  } else if (right.isString()) {
1150
- // left + "right"
1151
- // => ([null] + left + "right")
1152
- res.setWrapped(null, right, [left]);
1219
+ // ("prefix" + inner + [null]) + "right"
1220
+ // => ("prefix" + inner + "right")
1221
+ res.setWrapped(left.prefix, right, left.wrappedInnerExpressions);
1222
+ } else if (right.isNumber()) {
1223
+ // ("prefix" + inner + [null]) + 123
1224
+ // => ("prefix" + inner + "123")
1225
+ res.setWrapped(
1226
+ left.prefix,
1227
+ new BasicEvaluatedExpression()
1228
+ .setString(String(right.number))
1229
+ .setRange(/** @type {Range} */ (right.range)),
1230
+ left.wrappedInnerExpressions
1231
+ );
1153
1232
  } else if (right.isWrapped()) {
1154
- // left + (prefix + inner + "postfix")
1155
- // => ([null] + left + prefix + inner + "postfix")
1233
+ // ("prefix1" + inner1 + "postfix1") + ("prefix2" + inner2 + "postfix2")
1234
+ // ("prefix1" + inner1 + "postfix1" + "prefix2" + inner2 + "postfix2")
1156
1235
  res.setWrapped(
1157
- null,
1236
+ left.prefix,
1158
1237
  right.postfix,
1159
- right.wrappedInnerExpressions &&
1160
- (right.prefix ? [left, right.prefix] : [left]).concat(
1161
- right.wrappedInnerExpressions
1162
- )
1238
+ left.wrappedInnerExpressions &&
1239
+ right.wrappedInnerExpressions && [
1240
+ ...left.wrappedInnerExpressions,
1241
+ ...(left.postfix ? [left.postfix] : []),
1242
+ ...(right.prefix ? [right.prefix] : []),
1243
+ ...right.wrappedInnerExpressions
1244
+ ]
1163
1245
  );
1164
1246
  } else {
1165
- return;
1247
+ // ("prefix" + inner + postfix) + expr
1248
+ // => ("prefix" + inner + postfix + expr + [null])
1249
+ res.setWrapped(
1250
+ left.prefix,
1251
+ null,
1252
+ left.wrappedInnerExpressions && [
1253
+ ...left.wrappedInnerExpressions,
1254
+ ...(left.postfix ? [left.postfix, right] : [right])
1255
+ ]
1256
+ );
1166
1257
  }
1167
- if (left.couldHaveSideEffects() || right.couldHaveSideEffects())
1168
- res.setSideEffects();
1169
- res.setRange(/** @type {Range} */ (expr.range));
1170
- return res;
1171
- } else if (expr.operator === "-") {
1172
- return handleConstOperation((l, r) => l - r);
1173
- } else if (expr.operator === "*") {
1174
- return handleConstOperation((l, r) => l * r);
1175
- } else if (expr.operator === "/") {
1176
- return handleConstOperation((l, r) => l / r);
1177
- } else if (expr.operator === "**") {
1178
- return handleConstOperation((l, r) => l ** r);
1179
- } else if (expr.operator === "===") {
1180
- return handleStrictEqualityComparison(true);
1181
- } else if (expr.operator === "==") {
1182
- return handleAbstractEqualityComparison(true);
1183
- } else if (expr.operator === "!==") {
1184
- return handleStrictEqualityComparison(false);
1185
- } else if (expr.operator === "!=") {
1186
- return handleAbstractEqualityComparison(false);
1187
- } else if (expr.operator === "&") {
1188
- return handleConstOperation((l, r) => l & r);
1189
- } else if (expr.operator === "|") {
1190
- return handleConstOperation((l, r) => l | r);
1191
- } else if (expr.operator === "^") {
1192
- return handleConstOperation((l, r) => l ^ r);
1193
- } else if (expr.operator === ">>>") {
1194
- return handleConstOperation((l, r) => l >>> r);
1195
- } else if (expr.operator === ">>") {
1196
- return handleConstOperation((l, r) => l >> r);
1197
- } else if (expr.operator === "<<") {
1198
- return handleConstOperation((l, r) => l << r);
1199
- } else if (expr.operator === "<") {
1200
- return handleConstOperation((l, r) => l < r);
1201
- } else if (expr.operator === ">") {
1202
- return handleConstOperation((l, r) => l > r);
1203
- } else if (expr.operator === "<=") {
1204
- return handleConstOperation((l, r) => l <= r);
1205
- } else if (expr.operator === ">=") {
1206
- return handleConstOperation((l, r) => l >= r);
1207
- }
1208
- });
1209
- this.hooks.evaluate
1210
- .for("UnaryExpression")
1211
- .tap("JavascriptParser", _expr => {
1212
- const expr = /** @type {UnaryExpression} */ (_expr);
1213
-
1214
- /**
1215
- * Evaluates a UnaryExpression if and only if it is a basic const operator (e.g. +a, -a, ~a).
1216
- * @template T
1217
- * @param {(operand: T) => boolean | number | bigint | string} operandHandler handler for the operand
1218
- * @returns {BasicEvaluatedExpression | undefined} evaluated expression
1219
- */
1220
- const handleConstOperation = operandHandler => {
1221
- const argument = this.evaluateExpression(expr.argument);
1222
- if (!argument.isCompileTimeValue()) return;
1223
- const result = operandHandler(argument.asCompileTimeValue());
1224
- return valueAsExpression(
1225
- result,
1226
- expr,
1227
- argument.couldHaveSideEffects()
1258
+ } else if (right.isString()) {
1259
+ // left + "right"
1260
+ // => ([null] + left + "right")
1261
+ res.setWrapped(null, right, [left]);
1262
+ } else if (right.isWrapped()) {
1263
+ // left + (prefix + inner + "postfix")
1264
+ // => ([null] + left + prefix + inner + "postfix")
1265
+ res.setWrapped(
1266
+ null,
1267
+ right.postfix,
1268
+ right.wrappedInnerExpressions && [
1269
+ ...(right.prefix ? [left, right.prefix] : [left]),
1270
+ ...right.wrappedInnerExpressions
1271
+ ]
1228
1272
  );
1229
- };
1273
+ } else {
1274
+ return;
1275
+ }
1276
+ if (left.couldHaveSideEffects() || right.couldHaveSideEffects()) {
1277
+ res.setSideEffects();
1278
+ }
1279
+ res.setRange(/** @type {Range} */ (expr.range));
1280
+ return res;
1281
+ } else if (expr.operator === "-") {
1282
+ return handleConstOperation((l, r) => l - r);
1283
+ } else if (expr.operator === "*") {
1284
+ return handleConstOperation((l, r) => l * r);
1285
+ } else if (expr.operator === "/") {
1286
+ return handleConstOperation((l, r) => l / r);
1287
+ } else if (expr.operator === "**") {
1288
+ return handleConstOperation((l, r) => l ** r);
1289
+ } else if (expr.operator === "===") {
1290
+ return handleStrictEqualityComparison(true);
1291
+ } else if (expr.operator === "==") {
1292
+ return handleAbstractEqualityComparison(true);
1293
+ } else if (expr.operator === "!==") {
1294
+ return handleStrictEqualityComparison(false);
1295
+ } else if (expr.operator === "!=") {
1296
+ return handleAbstractEqualityComparison(false);
1297
+ } else if (expr.operator === "&") {
1298
+ return handleConstOperation((l, r) => l & r);
1299
+ } else if (expr.operator === "|") {
1300
+ return handleConstOperation((l, r) => l | r);
1301
+ } else if (expr.operator === "^") {
1302
+ return handleConstOperation((l, r) => l ^ r);
1303
+ } else if (expr.operator === ">>>") {
1304
+ return handleConstOperation((l, r) => l >>> r);
1305
+ } else if (expr.operator === ">>") {
1306
+ return handleConstOperation((l, r) => l >> r);
1307
+ } else if (expr.operator === "<<") {
1308
+ return handleConstOperation((l, r) => l << r);
1309
+ } else if (expr.operator === "<") {
1310
+ return handleConstOperation((l, r) => l < r);
1311
+ } else if (expr.operator === ">") {
1312
+ return handleConstOperation((l, r) => l > r);
1313
+ } else if (expr.operator === "<=") {
1314
+ return handleConstOperation((l, r) => l <= r);
1315
+ } else if (expr.operator === ">=") {
1316
+ return handleConstOperation((l, r) => l >= r);
1317
+ }
1318
+ });
1319
+ this.hooks.evaluate.for("UnaryExpression").tap(CLASS_NAME, (_expr) => {
1320
+ const expr = /** @type {UnaryExpression} */ (_expr);
1321
+
1322
+ /**
1323
+ * Evaluates a UnaryExpression if and only if it is a basic const operator (e.g. +a, -a, ~a).
1324
+ * @template T
1325
+ * @param {(operand: T) => boolean | number | bigint | string} operandHandler handler for the operand
1326
+ * @returns {BasicEvaluatedExpression | undefined} evaluated expression
1327
+ */
1328
+ const handleConstOperation = (operandHandler) => {
1329
+ const argument = this.evaluateExpression(expr.argument);
1330
+ if (!argument.isCompileTimeValue()) return;
1331
+ const result = operandHandler(
1332
+ /** @type {T} */ (argument.asCompileTimeValue())
1333
+ );
1334
+ return valueAsExpression(result, expr, argument.couldHaveSideEffects());
1335
+ };
1230
1336
 
1231
- if (expr.operator === "typeof") {
1232
- switch (expr.argument.type) {
1233
- case "Identifier": {
1234
- const res = this.callHooksForName(
1235
- this.hooks.evaluateTypeof,
1236
- expr.argument.name,
1237
- expr
1238
- );
1239
- if (res !== undefined) return res;
1240
- break;
1241
- }
1242
- case "MetaProperty": {
1243
- const res = this.callHooksForName(
1244
- this.hooks.evaluateTypeof,
1245
- /** @type {string} */ (getRootName(expr.argument)),
1246
- expr
1247
- );
1248
- if (res !== undefined) return res;
1249
- break;
1250
- }
1251
- case "MemberExpression": {
1252
- const res = this.callHooksForExpression(
1253
- this.hooks.evaluateTypeof,
1254
- expr.argument,
1255
- expr
1256
- );
1257
- if (res !== undefined) return res;
1258
- break;
1259
- }
1260
- case "ChainExpression": {
1261
- const res = this.callHooksForExpression(
1262
- this.hooks.evaluateTypeof,
1263
- expr.argument.expression,
1264
- expr
1265
- );
1266
- if (res !== undefined) return res;
1267
- break;
1268
- }
1269
- case "FunctionExpression": {
1270
- return new BasicEvaluatedExpression()
1271
- .setString("function")
1272
- .setRange(/** @type {Range} */ (expr.range));
1273
- }
1274
- }
1275
- const arg = this.evaluateExpression(expr.argument);
1276
- if (arg.isUnknown()) return;
1277
- if (arg.isString()) {
1278
- return new BasicEvaluatedExpression()
1279
- .setString("string")
1280
- .setRange(/** @type {Range} */ (expr.range));
1281
- }
1282
- if (arg.isWrapped()) {
1283
- return new BasicEvaluatedExpression()
1284
- .setString("string")
1285
- .setSideEffects()
1286
- .setRange(/** @type {Range} */ (expr.range));
1287
- }
1288
- if (arg.isUndefined()) {
1289
- return new BasicEvaluatedExpression()
1290
- .setString("undefined")
1291
- .setRange(/** @type {Range} */ (expr.range));
1292
- }
1293
- if (arg.isNumber()) {
1294
- return new BasicEvaluatedExpression()
1295
- .setString("number")
1296
- .setRange(/** @type {Range} */ (expr.range));
1337
+ if (expr.operator === "typeof") {
1338
+ switch (expr.argument.type) {
1339
+ case "Identifier": {
1340
+ const res = this.callHooksForName(
1341
+ this.hooks.evaluateTypeof,
1342
+ expr.argument.name,
1343
+ expr
1344
+ );
1345
+ if (res !== undefined) return res;
1346
+ break;
1297
1347
  }
1298
- if (arg.isBigInt()) {
1299
- return new BasicEvaluatedExpression()
1300
- .setString("bigint")
1301
- .setRange(/** @type {Range} */ (expr.range));
1348
+ case "MetaProperty": {
1349
+ const res = this.callHooksForName(
1350
+ this.hooks.evaluateTypeof,
1351
+ /** @type {string} */
1352
+ (getRootName(expr.argument)),
1353
+ expr
1354
+ );
1355
+ if (res !== undefined) return res;
1356
+ break;
1302
1357
  }
1303
- if (arg.isBoolean()) {
1304
- return new BasicEvaluatedExpression()
1305
- .setString("boolean")
1306
- .setRange(/** @type {Range} */ (expr.range));
1358
+ case "MemberExpression": {
1359
+ const res = this.callHooksForExpression(
1360
+ this.hooks.evaluateTypeof,
1361
+ expr.argument,
1362
+ expr
1363
+ );
1364
+ if (res !== undefined) return res;
1365
+ break;
1307
1366
  }
1308
- if (arg.isConstArray() || arg.isRegExp() || arg.isNull()) {
1309
- return new BasicEvaluatedExpression()
1310
- .setString("object")
1311
- .setRange(/** @type {Range} */ (expr.range));
1367
+ case "ChainExpression": {
1368
+ const res = this.callHooksForExpression(
1369
+ this.hooks.evaluateTypeof,
1370
+ expr.argument.expression,
1371
+ expr
1372
+ );
1373
+ if (res !== undefined) return res;
1374
+ break;
1312
1375
  }
1313
- if (arg.isArray()) {
1376
+ case "FunctionExpression": {
1314
1377
  return new BasicEvaluatedExpression()
1315
- .setString("object")
1316
- .setSideEffects(arg.couldHaveSideEffects())
1378
+ .setString("function")
1317
1379
  .setRange(/** @type {Range} */ (expr.range));
1318
1380
  }
1319
- } else if (expr.operator === "!") {
1320
- const argument = this.evaluateExpression(expr.argument);
1321
- const bool = argument.asBool();
1322
- if (typeof bool !== "boolean") return;
1381
+ }
1382
+ const arg = this.evaluateExpression(expr.argument);
1383
+ if (arg.isUnknown()) return;
1384
+ if (arg.isString()) {
1323
1385
  return new BasicEvaluatedExpression()
1324
- .setBoolean(!bool)
1325
- .setSideEffects(argument.couldHaveSideEffects())
1386
+ .setString("string")
1326
1387
  .setRange(/** @type {Range} */ (expr.range));
1327
- } else if (expr.operator === "~") {
1328
- return handleConstOperation(v => ~v);
1329
- } else if (expr.operator === "+") {
1330
- // eslint-disable-next-line no-implicit-coercion
1331
- return handleConstOperation(v => +v);
1332
- } else if (expr.operator === "-") {
1333
- return handleConstOperation(v => -v);
1334
1388
  }
1335
- });
1389
+ if (arg.isWrapped()) {
1390
+ return new BasicEvaluatedExpression()
1391
+ .setString("string")
1392
+ .setSideEffects()
1393
+ .setRange(/** @type {Range} */ (expr.range));
1394
+ }
1395
+ if (arg.isUndefined()) {
1396
+ return new BasicEvaluatedExpression()
1397
+ .setString("undefined")
1398
+ .setRange(/** @type {Range} */ (expr.range));
1399
+ }
1400
+ if (arg.isNumber()) {
1401
+ return new BasicEvaluatedExpression()
1402
+ .setString("number")
1403
+ .setRange(/** @type {Range} */ (expr.range));
1404
+ }
1405
+ if (arg.isBigInt()) {
1406
+ return new BasicEvaluatedExpression()
1407
+ .setString("bigint")
1408
+ .setRange(/** @type {Range} */ (expr.range));
1409
+ }
1410
+ if (arg.isBoolean()) {
1411
+ return new BasicEvaluatedExpression()
1412
+ .setString("boolean")
1413
+ .setRange(/** @type {Range} */ (expr.range));
1414
+ }
1415
+ if (arg.isConstArray() || arg.isRegExp() || arg.isNull()) {
1416
+ return new BasicEvaluatedExpression()
1417
+ .setString("object")
1418
+ .setRange(/** @type {Range} */ (expr.range));
1419
+ }
1420
+ if (arg.isArray()) {
1421
+ return new BasicEvaluatedExpression()
1422
+ .setString("object")
1423
+ .setSideEffects(arg.couldHaveSideEffects())
1424
+ .setRange(/** @type {Range} */ (expr.range));
1425
+ }
1426
+ } else if (expr.operator === "!") {
1427
+ const argument = this.evaluateExpression(expr.argument);
1428
+ const bool = argument.asBool();
1429
+ if (typeof bool !== "boolean") return;
1430
+ return new BasicEvaluatedExpression()
1431
+ .setBoolean(!bool)
1432
+ .setSideEffects(argument.couldHaveSideEffects())
1433
+ .setRange(/** @type {Range} */ (expr.range));
1434
+ } else if (expr.operator === "~") {
1435
+ return handleConstOperation((v) => ~v);
1436
+ } else if (expr.operator === "+") {
1437
+ // eslint-disable-next-line no-implicit-coercion
1438
+ return handleConstOperation((v) => +v);
1439
+ } else if (expr.operator === "-") {
1440
+ return handleConstOperation((v) => -v);
1441
+ }
1442
+ });
1336
1443
  this.hooks.evaluateTypeof
1337
1444
  .for("undefined")
1338
- .tap("JavascriptParser", expr =>
1445
+ .tap(CLASS_NAME, (expr) =>
1339
1446
  new BasicEvaluatedExpression()
1340
1447
  .setString("undefined")
1341
1448
  .setRange(/** @type {Range} */ (expr.range))
1342
1449
  );
1343
- this.hooks.evaluate.for("Identifier").tap("JavascriptParser", expr => {
1450
+ this.hooks.evaluate.for("Identifier").tap(CLASS_NAME, (expr) => {
1344
1451
  if (/** @type {Identifier} */ (expr).name === "undefined") {
1345
1452
  return new BasicEvaluatedExpression()
1346
1453
  .setUndefined()
@@ -1349,7 +1456,7 @@ class JavascriptParser extends Parser {
1349
1456
  });
1350
1457
  /**
1351
1458
  * @param {"Identifier" | "ThisExpression" | "MemberExpression"} exprType expression type name
1352
- * @param {function(Expression | SpreadElement): GetInfoResult | undefined} getInfo get info
1459
+ * @param {(node: Expression | SpreadElement) => GetInfoResult | undefined} getInfo get info
1353
1460
  * @returns {void}
1354
1461
  */
1355
1462
  const tapEvaluateWithVariableInfo = (exprType, getInfo) => {
@@ -1357,7 +1464,7 @@ class JavascriptParser extends Parser {
1357
1464
  let cachedExpression;
1358
1465
  /** @type {GetInfoResult | undefined} */
1359
1466
  let cachedInfo;
1360
- this.hooks.evaluate.for(exprType).tap("JavascriptParser", expr => {
1467
+ this.hooks.evaluate.for(exprType).tap(CLASS_NAME, (expr) => {
1361
1468
  const expression =
1362
1469
  /** @type {Identifier | ThisExpression | MemberExpression} */ (expr);
1363
1470
 
@@ -1366,11 +1473,12 @@ class JavascriptParser extends Parser {
1366
1473
  return this.callHooksForInfoWithFallback(
1367
1474
  this.hooks.evaluateIdentifier,
1368
1475
  info.name,
1369
- name => {
1476
+ (_name) => {
1370
1477
  cachedExpression = expression;
1371
1478
  cachedInfo = info;
1479
+ return undefined;
1372
1480
  },
1373
- name => {
1481
+ (name) => {
1374
1482
  const hook = this.hooks.evaluateDefinedIdentifier.get(name);
1375
1483
  if (hook !== undefined) {
1376
1484
  return hook.call(expression);
@@ -1382,7 +1490,7 @@ class JavascriptParser extends Parser {
1382
1490
  });
1383
1491
  this.hooks.evaluate
1384
1492
  .for(exprType)
1385
- .tap({ name: "JavascriptParser", stage: 100 }, expr => {
1493
+ .tap({ name: CLASS_NAME, stage: 100 }, (expr) => {
1386
1494
  const expression =
1387
1495
  /** @type {Identifier | ThisExpression | MemberExpression} */
1388
1496
  (expr);
@@ -1400,16 +1508,16 @@ class JavascriptParser extends Parser {
1400
1508
  .setRange(/** @type {Range} */ (expression.range));
1401
1509
  }
1402
1510
  });
1403
- this.hooks.finish.tap("JavascriptParser", () => {
1511
+ this.hooks.finish.tap(CLASS_NAME, () => {
1404
1512
  // Cleanup for GC
1405
1513
  cachedExpression = cachedInfo = undefined;
1406
1514
  });
1407
1515
  };
1408
- tapEvaluateWithVariableInfo("Identifier", expr => {
1516
+ tapEvaluateWithVariableInfo("Identifier", (expr) => {
1409
1517
  const info = this.getVariableInfo(/** @type {Identifier} */ (expr).name);
1410
1518
  if (
1411
1519
  typeof info === "string" ||
1412
- (info instanceof VariableInfo && typeof info.freeName === "string")
1520
+ (info instanceof VariableInfo && (info.isFree() || info.isTagged()))
1413
1521
  ) {
1414
1522
  return {
1415
1523
  name: info,
@@ -1420,11 +1528,11 @@ class JavascriptParser extends Parser {
1420
1528
  };
1421
1529
  }
1422
1530
  });
1423
- tapEvaluateWithVariableInfo("ThisExpression", expr => {
1531
+ tapEvaluateWithVariableInfo("ThisExpression", (_expr) => {
1424
1532
  const info = this.getVariableInfo("this");
1425
1533
  if (
1426
1534
  typeof info === "string" ||
1427
- (info instanceof VariableInfo && typeof info.freeName === "string")
1535
+ (info instanceof VariableInfo && (info.isFree() || info.isTagged()))
1428
1536
  ) {
1429
1537
  return {
1430
1538
  name: info,
@@ -1435,23 +1543,24 @@ class JavascriptParser extends Parser {
1435
1543
  };
1436
1544
  }
1437
1545
  });
1438
- this.hooks.evaluate.for("MetaProperty").tap("JavascriptParser", expr => {
1546
+ this.hooks.evaluate.for("MetaProperty").tap(CLASS_NAME, (expr) => {
1439
1547
  const metaProperty = /** @type {MetaProperty} */ (expr);
1440
1548
 
1441
1549
  return this.callHooksForName(
1442
1550
  this.hooks.evaluateIdentifier,
1443
- /** @type {string} */ (getRootName(metaProperty)),
1551
+ /** @type {string} */
1552
+ (getRootName(metaProperty)),
1444
1553
  metaProperty
1445
1554
  );
1446
1555
  });
1447
- tapEvaluateWithVariableInfo("MemberExpression", expr =>
1556
+ tapEvaluateWithVariableInfo("MemberExpression", (expr) =>
1448
1557
  this.getMemberExpressionInfo(
1449
1558
  /** @type {MemberExpression} */ (expr),
1450
1559
  ALLOWED_MEMBER_TYPES_EXPRESSION
1451
1560
  )
1452
1561
  );
1453
1562
 
1454
- this.hooks.evaluate.for("CallExpression").tap("JavascriptParser", _expr => {
1563
+ this.hooks.evaluate.for("CallExpression").tap(CLASS_NAME, (_expr) => {
1455
1564
  const expr = /** @type {CallExpression} */ (_expr);
1456
1565
  if (
1457
1566
  expr.callee.type === "MemberExpression" &&
@@ -1480,7 +1589,7 @@ class JavascriptParser extends Parser {
1480
1589
  });
1481
1590
  this.hooks.evaluateCallExpressionMember
1482
1591
  .for("indexOf")
1483
- .tap("JavascriptParser", (expr, param) => {
1592
+ .tap(CLASS_NAME, (expr, param) => {
1484
1593
  if (!param.isString()) return;
1485
1594
  if (expr.arguments.length === 0) return;
1486
1595
  const [arg1, arg2] = expr.arguments;
@@ -1508,7 +1617,7 @@ class JavascriptParser extends Parser {
1508
1617
  });
1509
1618
  this.hooks.evaluateCallExpressionMember
1510
1619
  .for("replace")
1511
- .tap("JavascriptParser", (expr, param) => {
1620
+ .tap(CLASS_NAME, (expr, param) => {
1512
1621
  if (!param.isString()) return;
1513
1622
  if (expr.arguments.length !== 2) return;
1514
1623
  if (expr.arguments[0].type === "SpreadElement") return;
@@ -1531,7 +1640,7 @@ class JavascriptParser extends Parser {
1531
1640
  for (const fn of ["substr", "substring", "slice"]) {
1532
1641
  this.hooks.evaluateCallExpressionMember
1533
1642
  .for(fn)
1534
- .tap("JavascriptParser", (expr, param) => {
1643
+ .tap(CLASS_NAME, (expr, param) => {
1535
1644
  if (!param.isString()) return;
1536
1645
  let arg1;
1537
1646
  let result;
@@ -1623,22 +1732,20 @@ class JavascriptParser extends Parser {
1623
1732
  };
1624
1733
  };
1625
1734
 
1626
- this.hooks.evaluate
1627
- .for("TemplateLiteral")
1628
- .tap("JavascriptParser", _node => {
1629
- const node = /** @type {TemplateLiteral} */ (_node);
1735
+ this.hooks.evaluate.for("TemplateLiteral").tap(CLASS_NAME, (_node) => {
1736
+ const node = /** @type {TemplateLiteral} */ (_node);
1630
1737
 
1631
- const { quasis, parts } = getSimplifiedTemplateResult("cooked", node);
1632
- if (parts.length === 1) {
1633
- return parts[0].setRange(/** @type {Range} */ (node.range));
1634
- }
1635
- return new BasicEvaluatedExpression()
1636
- .setTemplateString(quasis, parts, "cooked")
1637
- .setRange(/** @type {Range} */ (node.range));
1638
- });
1738
+ const { quasis, parts } = getSimplifiedTemplateResult("cooked", node);
1739
+ if (parts.length === 1) {
1740
+ return parts[0].setRange(/** @type {Range} */ (node.range));
1741
+ }
1742
+ return new BasicEvaluatedExpression()
1743
+ .setTemplateString(quasis, parts, "cooked")
1744
+ .setRange(/** @type {Range} */ (node.range));
1745
+ });
1639
1746
  this.hooks.evaluate
1640
1747
  .for("TaggedTemplateExpression")
1641
- .tap("JavascriptParser", _node => {
1748
+ .tap(CLASS_NAME, (_node) => {
1642
1749
  const node = /** @type {TaggedTemplateExpression} */ (_node);
1643
1750
  const tag = this.evaluateExpression(node.tag);
1644
1751
 
@@ -1655,10 +1762,11 @@ class JavascriptParser extends Parser {
1655
1762
 
1656
1763
  this.hooks.evaluateCallExpressionMember
1657
1764
  .for("concat")
1658
- .tap("JavascriptParser", (expr, param) => {
1765
+ .tap(CLASS_NAME, (expr, param) => {
1659
1766
  if (!param.isString() && !param.isWrapped()) return;
1660
1767
  let stringSuffix = null;
1661
1768
  let hasUnknownParams = false;
1769
+ /** @type {BasicEvaluatedExpression[]} */
1662
1770
  const innerExpressions = [];
1663
1771
  for (let i = expr.arguments.length - 1; i >= 0; i--) {
1664
1772
  const arg = expr.arguments[i];
@@ -1673,13 +1781,14 @@ class JavascriptParser extends Parser {
1673
1781
  continue;
1674
1782
  }
1675
1783
 
1676
- /** @type {string} */
1677
1784
  const value = argExpr.isString()
1678
1785
  ? /** @type {string} */ (argExpr.string)
1679
- : String(/** @type {number} */ (argExpr.number));
1786
+ : String(argExpr.number);
1680
1787
 
1681
1788
  /** @type {string} */
1682
- const newString = value + (stringSuffix ? stringSuffix.string : "");
1789
+ const newString =
1790
+ value +
1791
+ (stringSuffix ? /** @type {string} */ (stringSuffix.string) : "");
1683
1792
  const newRange = /** @type {Range} */ ([
1684
1793
  /** @type {Range} */ (argExpr.range)[0],
1685
1794
  /** @type {Range} */ ((stringSuffix || argExpr).range)[1]
@@ -1697,7 +1806,10 @@ class JavascriptParser extends Parser {
1697
1806
  const prefix = param.isString() ? param : param.prefix;
1698
1807
  const inner =
1699
1808
  param.isWrapped() && param.wrappedInnerExpressions
1700
- ? param.wrappedInnerExpressions.concat(innerExpressions.reverse())
1809
+ ? [
1810
+ ...param.wrappedInnerExpressions,
1811
+ ...innerExpressions.reverse()
1812
+ ]
1701
1813
  : innerExpressions.reverse();
1702
1814
  return new BasicEvaluatedExpression()
1703
1815
  .setWrapped(prefix, stringSuffix, inner)
@@ -1705,7 +1817,7 @@ class JavascriptParser extends Parser {
1705
1817
  } else if (param.isWrapped()) {
1706
1818
  const postfix = stringSuffix || param.postfix;
1707
1819
  const inner = param.wrappedInnerExpressions
1708
- ? param.wrappedInnerExpressions.concat(innerExpressions.reverse())
1820
+ ? [...param.wrappedInnerExpressions, ...innerExpressions.reverse()]
1709
1821
  : innerExpressions.reverse();
1710
1822
  return new BasicEvaluatedExpression()
1711
1823
  .setWrapped(param.prefix, postfix, inner)
@@ -1724,7 +1836,7 @@ class JavascriptParser extends Parser {
1724
1836
  });
1725
1837
  this.hooks.evaluateCallExpressionMember
1726
1838
  .for("split")
1727
- .tap("JavascriptParser", (expr, param) => {
1839
+ .tap(CLASS_NAME, (expr, param) => {
1728
1840
  if (!param.isString()) return;
1729
1841
  if (expr.arguments.length !== 1) return;
1730
1842
  if (expr.arguments[0].type === "SpreadElement") return;
@@ -1748,7 +1860,7 @@ class JavascriptParser extends Parser {
1748
1860
  });
1749
1861
  this.hooks.evaluate
1750
1862
  .for("ConditionalExpression")
1751
- .tap("JavascriptParser", _expr => {
1863
+ .tap(CLASS_NAME, (_expr) => {
1752
1864
  const expr = /** @type {ConditionalExpression} */ (_expr);
1753
1865
 
1754
1866
  const condition = this.evaluateExpression(expr.test);
@@ -1781,71 +1893,67 @@ class JavascriptParser extends Parser {
1781
1893
  res.setRange(/** @type {Range} */ (expr.range));
1782
1894
  return res;
1783
1895
  });
1784
- this.hooks.evaluate
1785
- .for("ArrayExpression")
1786
- .tap("JavascriptParser", _expr => {
1787
- const expr = /** @type {ArrayExpression} */ (_expr);
1788
-
1789
- const items = expr.elements.map(
1790
- element =>
1791
- element !== null &&
1792
- element.type !== "SpreadElement" &&
1793
- this.evaluateExpression(element)
1794
- );
1795
- if (!items.every(Boolean)) return;
1796
- return new BasicEvaluatedExpression()
1797
- .setItems(/** @type {BasicEvaluatedExpression[]} */ (items))
1798
- .setRange(/** @type {Range} */ (expr.range));
1799
- });
1800
- this.hooks.evaluate
1801
- .for("ChainExpression")
1802
- .tap("JavascriptParser", _expr => {
1803
- const expr = /** @type {ChainExpression} */ (_expr);
1804
- /** @type {Expression[]} */
1805
- const optionalExpressionsStack = [];
1806
- /** @type {Expression|Super} */
1807
- let next = expr.expression;
1808
-
1809
- while (
1810
- next.type === "MemberExpression" ||
1811
- next.type === "CallExpression"
1812
- ) {
1813
- if (next.type === "MemberExpression") {
1814
- if (next.optional) {
1815
- // SuperNode can not be optional
1816
- optionalExpressionsStack.push(
1817
- /** @type {Expression} */ (next.object)
1818
- );
1819
- }
1820
- next = next.object;
1821
- } else {
1822
- if (next.optional) {
1823
- // SuperNode can not be optional
1824
- optionalExpressionsStack.push(
1825
- /** @type {Expression} */ (next.callee)
1826
- );
1827
- }
1828
- next = next.callee;
1896
+ this.hooks.evaluate.for("ArrayExpression").tap(CLASS_NAME, (_expr) => {
1897
+ const expr = /** @type {ArrayExpression} */ (_expr);
1898
+
1899
+ const items = expr.elements.map(
1900
+ (element) =>
1901
+ element !== null &&
1902
+ element.type !== "SpreadElement" &&
1903
+ this.evaluateExpression(element)
1904
+ );
1905
+ if (!items.every(Boolean)) return;
1906
+ return new BasicEvaluatedExpression()
1907
+ .setItems(/** @type {BasicEvaluatedExpression[]} */ (items))
1908
+ .setRange(/** @type {Range} */ (expr.range));
1909
+ });
1910
+ this.hooks.evaluate.for("ChainExpression").tap(CLASS_NAME, (_expr) => {
1911
+ const expr = /** @type {ChainExpression} */ (_expr);
1912
+ /** @type {Expression[]} */
1913
+ const optionalExpressionsStack = [];
1914
+ /** @type {Expression | Super} */
1915
+ let next = expr.expression;
1916
+
1917
+ while (
1918
+ next.type === "MemberExpression" ||
1919
+ next.type === "CallExpression"
1920
+ ) {
1921
+ if (next.type === "MemberExpression") {
1922
+ if (next.optional) {
1923
+ // SuperNode can not be optional
1924
+ optionalExpressionsStack.push(
1925
+ /** @type {Expression} */ (next.object)
1926
+ );
1927
+ }
1928
+ next = next.object;
1929
+ } else {
1930
+ if (next.optional) {
1931
+ // SuperNode can not be optional
1932
+ optionalExpressionsStack.push(
1933
+ /** @type {Expression} */ (next.callee)
1934
+ );
1829
1935
  }
1936
+ next = next.callee;
1830
1937
  }
1938
+ }
1831
1939
 
1832
- while (optionalExpressionsStack.length > 0) {
1833
- const expression =
1834
- /** @type {Expression} */
1835
- (optionalExpressionsStack.pop());
1836
- const evaluated = this.evaluateExpression(expression);
1940
+ while (optionalExpressionsStack.length > 0) {
1941
+ const expression =
1942
+ /** @type {Expression} */
1943
+ (optionalExpressionsStack.pop());
1944
+ const evaluated = this.evaluateExpression(expression);
1837
1945
 
1838
- if (evaluated.asNullish()) {
1839
- return evaluated.setRange(/** @type {Range} */ (_expr.range));
1840
- }
1946
+ if (evaluated.asNullish()) {
1947
+ return evaluated.setRange(/** @type {Range} */ (_expr.range));
1841
1948
  }
1842
- return this.evaluateExpression(expr.expression);
1843
- });
1949
+ }
1950
+ return this.evaluateExpression(expr.expression);
1951
+ });
1844
1952
  }
1845
1953
 
1846
1954
  /**
1847
1955
  * @param {Expression} node node
1848
- * @returns {Set<DestructuringAssignmentProperty> | undefined} destructured identifiers
1956
+ * @returns {DestructuringAssignmentProperties | undefined} destructured identifiers
1849
1957
  */
1850
1958
  destructuringAssignmentPropertiesFor(node) {
1851
1959
  if (!this.destructuringAssignmentProperties) return;
@@ -1854,7 +1962,7 @@ class JavascriptParser extends Parser {
1854
1962
 
1855
1963
  /**
1856
1964
  * @param {Expression | SpreadElement} expr expression
1857
- * @returns {string | VariableInfoInterface | undefined} identifier
1965
+ * @returns {string | VariableInfo | undefined} identifier
1858
1966
  */
1859
1967
  getRenameIdentifier(expr) {
1860
1968
  const result = this.evaluateExpression(expr);
@@ -1864,7 +1972,7 @@ class JavascriptParser extends Parser {
1864
1972
  }
1865
1973
 
1866
1974
  /**
1867
- * @param {ClassExpression | ClassDeclaration} classy a class node
1975
+ * @param {ClassExpression | ClassDeclaration | MaybeNamedClassDeclaration} classy a class node
1868
1976
  * @returns {void}
1869
1977
  */
1870
1978
  walkClass(classy) {
@@ -1881,13 +1989,20 @@ class JavascriptParser extends Parser {
1881
1989
  scopeParams.push(classy.id);
1882
1990
  }
1883
1991
  this.inClassScope(true, scopeParams, () => {
1884
- for (const classElement of /** @type {TODO} */ (classy.body.body)) {
1992
+ for (const classElement of classy.body.body) {
1885
1993
  if (!this.hooks.classBodyElement.call(classElement, classy)) {
1886
- if (classElement.computed && classElement.key) {
1887
- this.walkExpression(classElement.key);
1888
- }
1889
- if (classElement.value) {
1994
+ if (classElement.type === "StaticBlock") {
1995
+ const wasTopLevel = this.scope.topLevelScope;
1996
+ this.scope.topLevelScope = false;
1997
+ this.walkBlockStatement(classElement);
1998
+ this.scope.topLevelScope = wasTopLevel;
1999
+ } else {
2000
+ if (classElement.computed && classElement.key) {
2001
+ this.walkExpression(classElement.key);
2002
+ }
2003
+
1890
2004
  if (
2005
+ classElement.value &&
1891
2006
  !this.hooks.classBodyValue.call(
1892
2007
  classElement.value,
1893
2008
  classElement,
@@ -1899,11 +2014,6 @@ class JavascriptParser extends Parser {
1899
2014
  this.walkExpression(classElement.value);
1900
2015
  this.scope.topLevelScope = wasTopLevel;
1901
2016
  }
1902
- } else if (classElement.type === "StaticBlock") {
1903
- const wasTopLevel = this.scope.topLevelScope;
1904
- this.scope.topLevelScope = false;
1905
- this.walkBlockStatement(classElement);
1906
- this.scope.topLevelScope = wasTopLevel;
1907
2017
  }
1908
2018
  }
1909
2019
  }
@@ -1911,6 +2021,32 @@ class JavascriptParser extends Parser {
1911
2021
  }
1912
2022
  }
1913
2023
 
2024
+ /**
2025
+ * Module pre walking iterates the scope for import entries
2026
+ * @param {(Statement | ModuleDeclaration)[]} statements statements
2027
+ */
2028
+ modulePreWalkStatements(statements) {
2029
+ for (let index = 0, len = statements.length; index < len; index++) {
2030
+ const statement = statements[index];
2031
+ /** @type {StatementPath} */
2032
+ (this.statementPath).push(statement);
2033
+ switch (statement.type) {
2034
+ case "ImportDeclaration":
2035
+ this.modulePreWalkImportDeclaration(statement);
2036
+ break;
2037
+ case "ExportAllDeclaration":
2038
+ this.modulePreWalkExportAllDeclaration(statement);
2039
+ break;
2040
+ case "ExportNamedDeclaration":
2041
+ this.modulePreWalkExportNamedDeclaration(statement);
2042
+ break;
2043
+ }
2044
+ this.prevStatement =
2045
+ /** @type {StatementPath} */
2046
+ (this.statementPath).pop();
2047
+ }
2048
+ }
2049
+
1914
2050
  /**
1915
2051
  * Pre walking iterates the scope for variable declarations
1916
2052
  * @param {(Statement | ModuleDeclaration)[]} statements statements
@@ -1938,15 +2074,30 @@ class JavascriptParser extends Parser {
1938
2074
  * @param {(Statement | ModuleDeclaration)[]} statements statements
1939
2075
  */
1940
2076
  walkStatements(statements) {
2077
+ let onlyFunctionDeclaration = false;
2078
+
1941
2079
  for (let index = 0, len = statements.length; index < len; index++) {
1942
2080
  const statement = statements[index];
2081
+
2082
+ if (
2083
+ onlyFunctionDeclaration &&
2084
+ statement.type !== "FunctionDeclaration" &&
2085
+ this.hooks.unusedStatement.call(/** @type {Statement} */ (statement))
2086
+ ) {
2087
+ continue;
2088
+ }
2089
+
1943
2090
  this.walkStatement(statement);
2091
+
2092
+ if (this.scope.terminated) {
2093
+ onlyFunctionDeclaration = true;
2094
+ }
1944
2095
  }
1945
2096
  }
1946
2097
 
1947
2098
  /**
1948
2099
  * Walking iterates the statements and expressions and processes them
1949
- * @param {Statement | ModuleDeclaration} statement statement
2100
+ * @param {Statement | ModuleDeclaration | MaybeNamedClassDeclaration | MaybeNamedFunctionDeclaration} statement statement
1950
2101
  */
1951
2102
  preWalkStatement(statement) {
1952
2103
  /** @type {StatementPath} */
@@ -2004,7 +2155,7 @@ class JavascriptParser extends Parser {
2004
2155
  }
2005
2156
 
2006
2157
  /**
2007
- * @param {Statement | ModuleDeclaration} statement statement
2158
+ * @param {Statement | ModuleDeclaration | MaybeNamedClassDeclaration | MaybeNamedFunctionDeclaration} statement statement
2008
2159
  */
2009
2160
  blockPreWalkStatement(statement) {
2010
2161
  /** @type {StatementPath} */
@@ -2016,12 +2167,6 @@ class JavascriptParser extends Parser {
2016
2167
  return;
2017
2168
  }
2018
2169
  switch (statement.type) {
2019
- case "ImportDeclaration":
2020
- this.blockPreWalkImportDeclaration(statement);
2021
- break;
2022
- case "ExportAllDeclaration":
2023
- this.blockPreWalkExportAllDeclaration(statement);
2024
- break;
2025
2170
  case "ExportDefaultDeclaration":
2026
2171
  this.blockPreWalkExportDefaultDeclaration(statement);
2027
2172
  break;
@@ -2043,7 +2188,7 @@ class JavascriptParser extends Parser {
2043
2188
  }
2044
2189
 
2045
2190
  /**
2046
- * @param {Statement | ModuleDeclaration} statement statement
2191
+ * @param {Statement | ModuleDeclaration | MaybeNamedFunctionDeclaration | MaybeNamedClassDeclaration} statement statement
2047
2192
  */
2048
2193
  walkStatement(statement) {
2049
2194
  /** @type {StatementPath} */
@@ -2138,7 +2283,7 @@ class JavascriptParser extends Parser {
2138
2283
  }
2139
2284
 
2140
2285
  /**
2141
- * @param {BlockStatement} statement block statement
2286
+ * @param {BlockStatement | StaticBlock} statement block statement
2142
2287
  */
2143
2288
  walkBlockStatement(statement) {
2144
2289
  this.inBlockScope(() => {
@@ -2147,7 +2292,7 @@ class JavascriptParser extends Parser {
2147
2292
  this.blockPreWalkStatements(body);
2148
2293
  this.prevStatement = prev;
2149
2294
  this.walkStatements(body);
2150
- });
2295
+ }, true);
2151
2296
  }
2152
2297
 
2153
2298
  /**
@@ -2175,9 +2320,20 @@ class JavascriptParser extends Parser {
2175
2320
  if (result === undefined) {
2176
2321
  this.walkExpression(statement.test);
2177
2322
  this.walkNestedStatement(statement.consequent);
2323
+
2324
+ const consequentTerminated = this.scope.terminated;
2325
+ this.scope.terminated = undefined;
2326
+
2178
2327
  if (statement.alternate) {
2179
2328
  this.walkNestedStatement(statement.alternate);
2180
2329
  }
2330
+
2331
+ const alternateTerminated = this.scope.terminated;
2332
+
2333
+ this.scope.terminated =
2334
+ consequentTerminated && alternateTerminated
2335
+ ? alternateTerminated
2336
+ : undefined;
2181
2337
  } else if (result) {
2182
2338
  this.walkNestedStatement(statement.consequent);
2183
2339
  } else if (statement.alternate) {
@@ -2201,7 +2357,9 @@ class JavascriptParser extends Parser {
2201
2357
  const result = hook.call(statement);
2202
2358
  if (result === true) return;
2203
2359
  }
2204
- this.walkNestedStatement(statement.body);
2360
+ this.inBlockScope(() => {
2361
+ this.walkNestedStatement(statement.body);
2362
+ });
2205
2363
  }
2206
2364
 
2207
2365
  /**
@@ -2215,8 +2373,10 @@ class JavascriptParser extends Parser {
2215
2373
  * @param {WithStatement} statement with statement
2216
2374
  */
2217
2375
  walkWithStatement(statement) {
2218
- this.walkExpression(statement.object);
2219
- this.walkNestedStatement(statement.body);
2376
+ this.inBlockScope(() => {
2377
+ this.walkExpression(statement.object);
2378
+ this.walkNestedStatement(statement.body);
2379
+ });
2220
2380
  }
2221
2381
 
2222
2382
  /**
@@ -2239,6 +2399,14 @@ class JavascriptParser extends Parser {
2239
2399
  */
2240
2400
  walkTerminatingStatement(statement) {
2241
2401
  if (statement.argument) this.walkExpression(statement.argument);
2402
+ // Skip top level scope because to handle `export` and `module.exports` after terminate
2403
+ if (this.scope.topLevelScope === true) return;
2404
+ if (this.hooks.terminate.call(statement)) {
2405
+ this.scope.terminated =
2406
+ statement.type === "ReturnStatement"
2407
+ ? SCOPE_INFO_TERMINATED_RETURN
2408
+ : SCOPE_INFO_TERMINATED_THROW;
2409
+ }
2242
2410
  }
2243
2411
 
2244
2412
  /**
@@ -2275,8 +2443,30 @@ class JavascriptParser extends Parser {
2275
2443
  this.walkStatement(statement.block);
2276
2444
  this.scope.inTry = false;
2277
2445
  }
2446
+
2447
+ const tryTerminated = this.scope.terminated;
2448
+ this.scope.terminated = undefined;
2449
+
2278
2450
  if (statement.handler) this.walkCatchClause(statement.handler);
2279
- if (statement.finalizer) this.walkStatement(statement.finalizer);
2451
+
2452
+ const handlerTerminated = this.scope.terminated;
2453
+ this.scope.terminated = undefined;
2454
+
2455
+ if (statement.finalizer) {
2456
+ this.walkStatement(statement.finalizer);
2457
+ }
2458
+
2459
+ const finalizerTerminated = this.scope.terminated;
2460
+ this.scope.terminated = undefined;
2461
+
2462
+ if (finalizerTerminated) {
2463
+ this.scope.terminated = finalizerTerminated;
2464
+ } else if (
2465
+ tryTerminated &&
2466
+ (statement.handler ? handlerTerminated : true)
2467
+ ) {
2468
+ this.scope.terminated = handlerTerminated || tryTerminated;
2469
+ }
2280
2470
  }
2281
2471
 
2282
2472
  /**
@@ -2290,8 +2480,10 @@ class JavascriptParser extends Parser {
2290
2480
  * @param {WhileStatement} statement while statement
2291
2481
  */
2292
2482
  walkWhileStatement(statement) {
2293
- this.walkExpression(statement.test);
2294
- this.walkNestedStatement(statement.body);
2483
+ this.inBlockScope(() => {
2484
+ this.walkExpression(statement.test);
2485
+ this.walkNestedStatement(statement.body);
2486
+ });
2295
2487
  }
2296
2488
 
2297
2489
  /**
@@ -2305,8 +2497,10 @@ class JavascriptParser extends Parser {
2305
2497
  * @param {DoWhileStatement} statement do while statement
2306
2498
  */
2307
2499
  walkDoWhileStatement(statement) {
2308
- this.walkNestedStatement(statement.body);
2309
- this.walkExpression(statement.test);
2500
+ this.inBlockScope(() => {
2501
+ this.walkNestedStatement(statement.body);
2502
+ this.walkExpression(statement.test);
2503
+ });
2310
2504
  }
2311
2505
 
2312
2506
  /**
@@ -2339,7 +2533,9 @@ class JavascriptParser extends Parser {
2339
2533
  if (statement.update) {
2340
2534
  this.walkExpression(statement.update);
2341
2535
  }
2536
+
2342
2537
  const body = statement.body;
2538
+
2343
2539
  if (body.type === "BlockStatement") {
2344
2540
  // no need to add additional scope
2345
2541
  const prev = this.prevStatement;
@@ -2373,8 +2569,11 @@ class JavascriptParser extends Parser {
2373
2569
  } else {
2374
2570
  this.walkPattern(statement.left);
2375
2571
  }
2572
+
2376
2573
  this.walkExpression(statement.right);
2574
+
2377
2575
  const body = statement.body;
2576
+
2378
2577
  if (body.type === "BlockStatement") {
2379
2578
  // no need to add additional scope
2380
2579
  const prev = this.prevStatement;
@@ -2411,8 +2610,11 @@ class JavascriptParser extends Parser {
2411
2610
  } else {
2412
2611
  this.walkPattern(statement.left);
2413
2612
  }
2613
+
2414
2614
  this.walkExpression(statement.right);
2615
+
2415
2616
  const body = statement.body;
2617
+
2416
2618
  if (body.type === "BlockStatement") {
2417
2619
  // no need to add additional scope
2418
2620
  const prev = this.prevStatement;
@@ -2426,7 +2628,7 @@ class JavascriptParser extends Parser {
2426
2628
  }
2427
2629
 
2428
2630
  /**
2429
- * @param {FunctionDeclaration} statement function declaration
2631
+ * @param {FunctionDeclaration | MaybeNamedFunctionDeclaration} statement function declaration
2430
2632
  */
2431
2633
  preWalkFunctionDeclaration(statement) {
2432
2634
  if (statement.id) {
@@ -2435,7 +2637,7 @@ class JavascriptParser extends Parser {
2435
2637
  }
2436
2638
 
2437
2639
  /**
2438
- * @param {FunctionDeclaration} statement function declaration
2640
+ * @param {FunctionDeclaration | MaybeNamedFunctionDeclaration} statement function declaration
2439
2641
  */
2440
2642
  walkFunctionDeclaration(statement) {
2441
2643
  const wasTopLevel = this.scope.topLevelScope;
@@ -2444,15 +2646,14 @@ class JavascriptParser extends Parser {
2444
2646
  for (const param of statement.params) {
2445
2647
  this.walkPattern(param);
2446
2648
  }
2447
- if (statement.body.type === "BlockStatement") {
2448
- this.detectMode(statement.body.body);
2449
- const prev = this.prevStatement;
2450
- this.preWalkStatement(statement.body);
2451
- this.prevStatement = prev;
2452
- this.walkStatement(statement.body);
2453
- } else {
2454
- this.walkExpression(statement.body);
2455
- }
2649
+
2650
+ this.detectMode(statement.body.body);
2651
+
2652
+ const prev = this.prevStatement;
2653
+
2654
+ this.preWalkStatement(statement.body);
2655
+ this.prevStatement = prev;
2656
+ this.walkStatement(statement.body);
2456
2657
  });
2457
2658
  this.scope.topLevelScope = wasTopLevel;
2458
2659
  }
@@ -2472,39 +2673,54 @@ class JavascriptParser extends Parser {
2472
2673
  * @param {AssignmentExpression} expression assignment expression
2473
2674
  */
2474
2675
  preWalkAssignmentExpression(expression) {
2676
+ this.enterDestructuringAssignment(expression.left, expression.right);
2677
+ }
2678
+
2679
+ /**
2680
+ * @param {Pattern} pattern pattern
2681
+ * @param {Expression} expression assignment expression
2682
+ * @returns {Expression | undefined} destructuring expression
2683
+ */
2684
+ enterDestructuringAssignment(pattern, expression) {
2475
2685
  if (
2476
- expression.left.type !== "ObjectPattern" ||
2686
+ pattern.type !== "ObjectPattern" ||
2477
2687
  !this.destructuringAssignmentProperties
2478
- )
2688
+ ) {
2479
2689
  return;
2480
- const keys = this._preWalkObjectPattern(expression.left);
2481
- if (!keys) return;
2482
-
2483
- // check multiple assignments
2484
- if (this.destructuringAssignmentProperties.has(expression)) {
2485
- const set =
2486
- /** @type {Set<DestructuringAssignmentProperty>} */
2487
- (this.destructuringAssignmentProperties.get(expression));
2488
- this.destructuringAssignmentProperties.delete(expression);
2489
- for (const id of set) keys.add(id);
2490
2690
  }
2491
2691
 
2492
- this.destructuringAssignmentProperties.set(
2493
- expression.right.type === "AwaitExpression"
2494
- ? expression.right.argument
2495
- : expression.right,
2496
- keys
2497
- );
2498
-
2499
- if (expression.right.type === "AssignmentExpression") {
2500
- this.preWalkAssignmentExpression(expression.right);
2692
+ const expr =
2693
+ expression.type === "AwaitExpression" ? expression.argument : expression;
2694
+
2695
+ const destructuring =
2696
+ expr.type === "AssignmentExpression"
2697
+ ? this.enterDestructuringAssignment(expr.left, expr.right)
2698
+ : this.hooks.collectDestructuringAssignmentProperties.call(expr)
2699
+ ? expr
2700
+ : undefined;
2701
+
2702
+ if (destructuring) {
2703
+ const keys = this._preWalkObjectPattern(pattern);
2704
+ if (!keys) return;
2705
+
2706
+ // check multiple assignments
2707
+ if (this.destructuringAssignmentProperties.has(destructuring)) {
2708
+ const set =
2709
+ /** @type {DestructuringAssignmentProperties} */
2710
+ (this.destructuringAssignmentProperties.get(destructuring));
2711
+ for (const id of keys) set.add(id);
2712
+ } else {
2713
+ this.destructuringAssignmentProperties.set(destructuring, keys);
2714
+ }
2501
2715
  }
2716
+
2717
+ return destructuring;
2502
2718
  }
2503
2719
 
2504
2720
  /**
2505
2721
  * @param {ImportDeclaration} statement statement
2506
2722
  */
2507
- blockPreWalkImportDeclaration(statement) {
2723
+ modulePreWalkImportDeclaration(statement) {
2508
2724
  const source = /** @type {ImportSource} */ (statement.source.value);
2509
2725
  this.hooks.import.call(statement, source);
2510
2726
  for (const specifier of statement.specifiers) {
@@ -2574,14 +2790,49 @@ class JavascriptParser extends Parser {
2574
2790
  /**
2575
2791
  * @param {ExportNamedDeclaration} statement statement
2576
2792
  */
2577
- blockPreWalkExportNamedDeclaration(statement) {
2578
- let source;
2579
- if (statement.source) {
2580
- source = /** @type {ImportSource} */ (statement.source.value);
2581
- this.hooks.exportImport.call(statement, source);
2582
- } else {
2583
- this.hooks.export.call(statement);
2793
+ modulePreWalkExportNamedDeclaration(statement) {
2794
+ if (!statement.source) return;
2795
+ const source = /** @type {ImportSource} */ (statement.source.value);
2796
+ this.hooks.exportImport.call(statement, source);
2797
+ if (statement.specifiers) {
2798
+ for (
2799
+ let specifierIndex = 0;
2800
+ specifierIndex < statement.specifiers.length;
2801
+ specifierIndex++
2802
+ ) {
2803
+ const specifier = statement.specifiers[specifierIndex];
2804
+ switch (specifier.type) {
2805
+ case "ExportSpecifier": {
2806
+ const localName =
2807
+ /** @type {Identifier} */ (specifier.local).name ||
2808
+ /** @type {string} */ (
2809
+ /** @type {Literal} */ (specifier.local).value
2810
+ );
2811
+ const name =
2812
+ /** @type {Identifier} */
2813
+ (specifier.exported).name ||
2814
+ /** @type {string} */
2815
+ (/** @type {Literal} */ (specifier.exported).value);
2816
+ this.hooks.exportImportSpecifier.call(
2817
+ statement,
2818
+ source,
2819
+ localName,
2820
+ name,
2821
+ specifierIndex
2822
+ );
2823
+ break;
2824
+ }
2825
+ }
2826
+ }
2584
2827
  }
2828
+ }
2829
+
2830
+ /**
2831
+ * @param {ExportNamedDeclaration} statement statement
2832
+ */
2833
+ blockPreWalkExportNamedDeclaration(statement) {
2834
+ if (statement.source) return;
2835
+ this.hooks.export.call(statement);
2585
2836
  if (
2586
2837
  statement.declaration &&
2587
2838
  !this.hooks.exportDeclaration.call(statement, statement.declaration)
@@ -2591,7 +2842,7 @@ class JavascriptParser extends Parser {
2591
2842
  this.prevStatement = prev;
2592
2843
  this.blockPreWalkStatement(statement.declaration);
2593
2844
  let index = 0;
2594
- this.enterDeclaration(statement.declaration, def => {
2845
+ this.enterDeclaration(statement.declaration, (def) => {
2595
2846
  this.hooks.exportSpecifier.call(statement, def, def, index++);
2596
2847
  });
2597
2848
  }
@@ -2614,22 +2865,12 @@ class JavascriptParser extends Parser {
2614
2865
  (specifier.exported).name ||
2615
2866
  /** @type {string} */
2616
2867
  (/** @type {Literal} */ (specifier.exported).value);
2617
- if (source) {
2618
- this.hooks.exportImportSpecifier.call(
2619
- statement,
2620
- source,
2621
- localName,
2622
- name,
2623
- specifierIndex
2624
- );
2625
- } else {
2626
- this.hooks.exportSpecifier.call(
2627
- statement,
2628
- localName,
2629
- name,
2630
- specifierIndex
2631
- );
2632
- }
2868
+ this.hooks.exportSpecifier.call(
2869
+ statement,
2870
+ localName,
2871
+ name,
2872
+ specifierIndex
2873
+ );
2633
2874
  break;
2634
2875
  }
2635
2876
  }
@@ -2647,26 +2888,34 @@ class JavascriptParser extends Parser {
2647
2888
  }
2648
2889
 
2649
2890
  /**
2650
- * @param {TODO} statement statement
2891
+ * @param {ExportDefaultDeclaration} statement statement
2651
2892
  */
2652
2893
  blockPreWalkExportDefaultDeclaration(statement) {
2653
- const prev = this.prevStatement;
2654
- this.preWalkStatement(statement.declaration);
2655
- this.prevStatement = prev;
2656
- this.blockPreWalkStatement(statement.declaration);
2657
2894
  if (
2658
- /** @type {FunctionDeclaration | ClassDeclaration} */ (
2659
- statement.declaration
2660
- ).id &&
2895
+ statement.declaration.type === "FunctionDeclaration" ||
2896
+ statement.declaration.type === "ClassDeclaration"
2897
+ ) {
2898
+ const prev = this.prevStatement;
2899
+
2900
+ this.preWalkStatement(statement.declaration);
2901
+ this.prevStatement = prev;
2902
+ this.blockPreWalkStatement(statement.declaration);
2903
+ }
2904
+
2905
+ if (
2906
+ /** @type {MaybeNamedFunctionDeclaration | MaybeNamedClassDeclaration} */
2907
+ (statement.declaration).id &&
2661
2908
  statement.declaration.type !== "FunctionExpression" &&
2662
2909
  statement.declaration.type !== "ClassExpression"
2663
2910
  ) {
2664
2911
  const declaration =
2665
- /** @type {FunctionDeclaration | ClassDeclaration} */
2912
+ /** @type {MaybeNamedFunctionDeclaration | MaybeNamedClassDeclaration} */
2666
2913
  (statement.declaration);
2914
+
2667
2915
  this.hooks.exportSpecifier.call(
2668
2916
  statement,
2669
- declaration.id.name,
2917
+ /** @type {Identifier} */
2918
+ (declaration.id).name,
2670
2919
  "default",
2671
2920
  undefined
2672
2921
  );
@@ -2679,9 +2928,8 @@ class JavascriptParser extends Parser {
2679
2928
  walkExportDefaultDeclaration(statement) {
2680
2929
  this.hooks.export.call(statement);
2681
2930
  if (
2682
- /** @type {FunctionDeclaration | ClassDeclaration} */ (
2683
- statement.declaration
2684
- ).id &&
2931
+ /** @type {FunctionDeclaration | ClassDeclaration} */
2932
+ (statement.declaration).id &&
2685
2933
  statement.declaration.type !== "FunctionExpression" &&
2686
2934
  statement.declaration.type !== "ClassExpression"
2687
2935
  ) {
@@ -2699,34 +2947,19 @@ class JavascriptParser extends Parser {
2699
2947
  statement.declaration.type === "FunctionDeclaration" ||
2700
2948
  statement.declaration.type === "ClassDeclaration"
2701
2949
  ) {
2702
- this.walkStatement(
2703
- /** @type {FunctionDeclaration | ClassDeclaration} */
2704
- (statement.declaration)
2705
- );
2950
+ this.walkStatement(statement.declaration);
2706
2951
  } else {
2707
2952
  this.walkExpression(statement.declaration);
2708
2953
  }
2709
2954
 
2710
- if (
2711
- !this.hooks.exportExpression.call(
2712
- statement,
2713
- /** @type {TODO} */ (statement).declaration
2714
- )
2715
- ) {
2716
- this.hooks.exportSpecifier.call(
2717
- statement,
2718
- /** @type {TODO} */ (statement.declaration),
2719
- "default",
2720
- undefined
2721
- );
2722
- }
2955
+ this.hooks.exportExpression.call(statement, statement.declaration);
2723
2956
  }
2724
2957
  }
2725
2958
 
2726
2959
  /**
2727
2960
  * @param {ExportAllDeclaration} statement statement
2728
2961
  */
2729
- blockPreWalkExportAllDeclaration(statement) {
2962
+ modulePreWalkExportAllDeclaration(statement) {
2730
2963
  const source = /** @type {ImportSource} */ (statement.source.value);
2731
2964
  const name = statement.exported
2732
2965
  ? /** @type {Identifier} */
@@ -2751,16 +2984,19 @@ class JavascriptParser extends Parser {
2751
2984
  */
2752
2985
  blockPreWalkVariableDeclaration(statement) {
2753
2986
  if (statement.kind === "var") return;
2987
+
2754
2988
  const hookMap =
2755
2989
  statement.kind === "const"
2756
2990
  ? this.hooks.varDeclarationConst
2757
- : this.hooks.varDeclarationLet;
2991
+ : statement.kind === "using" || statement.kind === "await using"
2992
+ ? this.hooks.varDeclarationUsing
2993
+ : this.hooks.varDeclarationLet;
2758
2994
  this._preWalkVariableDeclaration(statement, hookMap);
2759
2995
  }
2760
2996
 
2761
2997
  /**
2762
2998
  * @param {VariableDeclaration} statement variable declaration
2763
- * @param {TODO} hookMap map of hooks
2999
+ * @param {HookMap<SyncBailHook<[Identifier], boolean | void>>} hookMap map of hooks
2764
3000
  */
2765
3001
  _preWalkVariableDeclaration(statement, hookMap) {
2766
3002
  for (const declarator of statement.declarations) {
@@ -2768,11 +3004,11 @@ class JavascriptParser extends Parser {
2768
3004
  case "VariableDeclarator": {
2769
3005
  this.preWalkVariableDeclarator(declarator);
2770
3006
  if (!this.hooks.preDeclarator.call(declarator, statement)) {
2771
- this.enterPattern(declarator.id, (name, decl) => {
3007
+ this.enterPattern(declarator.id, (name, ident) => {
2772
3008
  let hook = hookMap.get(name);
2773
- if (hook === undefined || !hook.call(decl)) {
3009
+ if (hook === undefined || !hook.call(ident)) {
2774
3010
  hook = this.hooks.varDeclaration.get(name);
2775
- if (hook === undefined || !hook.call(decl)) {
3011
+ if (hook === undefined || !hook.call(ident)) {
2776
3012
  this.defineVariable(name);
2777
3013
  }
2778
3014
  }
@@ -2786,32 +3022,55 @@ class JavascriptParser extends Parser {
2786
3022
 
2787
3023
  /**
2788
3024
  * @param {ObjectPattern} objectPattern object pattern
2789
- * @returns {Set<DestructuringAssignmentProperty> | undefined} set of names or undefined if not all keys are identifiers
3025
+ * @returns {DestructuringAssignmentProperties | undefined} set of names or undefined if not all keys are identifiers
2790
3026
  */
2791
3027
  _preWalkObjectPattern(objectPattern) {
2792
- /** @type {Set<DestructuringAssignmentProperty>} */
3028
+ /** @type {DestructuringAssignmentProperties} */
2793
3029
  const props = new Set();
2794
3030
  const properties = objectPattern.properties;
2795
3031
  for (let i = 0; i < properties.length; i++) {
2796
3032
  const property = properties[i];
2797
3033
  if (property.type !== "Property") return;
2798
- if (property.shorthand && property.value.type === "Identifier") {
2799
- this.scope.inShorthand = property.value.name;
3034
+ if (property.shorthand) {
3035
+ if (property.value.type === "Identifier") {
3036
+ this.scope.inShorthand = property.value.name;
3037
+ } else if (
3038
+ property.value.type === "AssignmentPattern" &&
3039
+ property.value.left.type === "Identifier"
3040
+ ) {
3041
+ this.scope.inShorthand = property.value.left.name;
3042
+ }
2800
3043
  }
2801
3044
  const key = property.key;
2802
- if (key.type === "Identifier") {
3045
+ if (key.type === "Identifier" && !property.computed) {
3046
+ const pattern =
3047
+ property.value.type === "ObjectPattern"
3048
+ ? this._preWalkObjectPattern(property.value)
3049
+ : property.value.type === "ArrayPattern"
3050
+ ? this._preWalkArrayPattern(property.value)
3051
+ : undefined;
2803
3052
  props.add({
2804
3053
  id: key.name,
2805
- range: key.range,
3054
+ range: /** @type {Range} */ (key.range),
3055
+ loc: /** @type {SourceLocation} */ (key.loc),
3056
+ pattern,
2806
3057
  shorthand: this.scope.inShorthand
2807
3058
  });
2808
3059
  } else {
2809
3060
  const id = this.evaluateExpression(key);
2810
3061
  const str = id.asString();
2811
3062
  if (str) {
3063
+ const pattern =
3064
+ property.value.type === "ObjectPattern"
3065
+ ? this._preWalkObjectPattern(property.value)
3066
+ : property.value.type === "ArrayPattern"
3067
+ ? this._preWalkArrayPattern(property.value)
3068
+ : undefined;
2812
3069
  props.add({
2813
3070
  id: str,
2814
- range: key.range,
3071
+ range: /** @type {Range} */ (key.range),
3072
+ loc: /** @type {SourceLocation} */ (key.loc),
3073
+ pattern,
2815
3074
  shorthand: this.scope.inShorthand
2816
3075
  });
2817
3076
  } else {
@@ -2825,28 +3084,42 @@ class JavascriptParser extends Parser {
2825
3084
  return props;
2826
3085
  }
2827
3086
 
3087
+ /**
3088
+ * @param {ArrayPattern} arrayPattern array pattern
3089
+ * @returns {Set<DestructuringAssignmentProperty> | undefined} set of names or undefined if not all keys are identifiers
3090
+ */
3091
+ _preWalkArrayPattern(arrayPattern) {
3092
+ /** @type {Set<DestructuringAssignmentProperty>} */
3093
+ const props = new Set();
3094
+ const elements = arrayPattern.elements;
3095
+ for (let i = 0; i < elements.length; i++) {
3096
+ const element = elements[i];
3097
+ if (!element) continue;
3098
+ if (element.type === "RestElement") return;
3099
+ const pattern =
3100
+ element.type === "ObjectPattern"
3101
+ ? this._preWalkObjectPattern(element)
3102
+ : element.type === "ArrayPattern"
3103
+ ? this._preWalkArrayPattern(element)
3104
+ : undefined;
3105
+ props.add({
3106
+ id: `${i}`,
3107
+ range: /** @type {Range} */ (element.range),
3108
+ loc: /** @type {SourceLocation} */ (element.loc),
3109
+ pattern,
3110
+ shorthand: false
3111
+ });
3112
+ }
3113
+
3114
+ return props;
3115
+ }
3116
+
2828
3117
  /**
2829
3118
  * @param {VariableDeclarator} declarator variable declarator
2830
3119
  */
2831
3120
  preWalkVariableDeclarator(declarator) {
2832
- if (
2833
- !declarator.init ||
2834
- declarator.id.type !== "ObjectPattern" ||
2835
- !this.destructuringAssignmentProperties
2836
- )
2837
- return;
2838
- const keys = this._preWalkObjectPattern(declarator.id);
2839
-
2840
- if (!keys) return;
2841
- this.destructuringAssignmentProperties.set(
2842
- declarator.init.type === "AwaitExpression"
2843
- ? declarator.init.argument
2844
- : declarator.init,
2845
- keys
2846
- );
2847
-
2848
- if (declarator.init.type === "AssignmentExpression") {
2849
- this.preWalkAssignmentExpression(declarator.init);
3121
+ if (declarator.init) {
3122
+ this.enterDestructuringAssignment(declarator.id, declarator.init);
2850
3123
  }
2851
3124
  }
2852
3125
 
@@ -2887,7 +3160,7 @@ class JavascriptParser extends Parser {
2887
3160
  }
2888
3161
 
2889
3162
  /**
2890
- * @param {ClassDeclaration} statement class declaration
3163
+ * @param {ClassDeclaration | MaybeNamedClassDeclaration} statement class declaration
2891
3164
  */
2892
3165
  blockPreWalkClassDeclaration(statement) {
2893
3166
  if (statement.id) {
@@ -2896,7 +3169,7 @@ class JavascriptParser extends Parser {
2896
3169
  }
2897
3170
 
2898
3171
  /**
2899
- * @param {ClassDeclaration} statement class declaration
3172
+ * @param {ClassDeclaration | MaybeNamedClassDeclaration} statement class declaration
2900
3173
  */
2901
3174
  walkClassDeclaration(statement) {
2902
3175
  this.walkClass(statement);
@@ -2943,8 +3216,10 @@ class JavascriptParser extends Parser {
2943
3216
  if (switchCase.test) {
2944
3217
  this.walkExpression(switchCase.test);
2945
3218
  }
3219
+
2946
3220
  if (switchCase.consequent.length > 0) {
2947
3221
  this.walkStatements(switchCase.consequent);
3222
+ this.scope.terminated = undefined;
2948
3223
  }
2949
3224
  }
2950
3225
  });
@@ -2964,7 +3239,7 @@ class JavascriptParser extends Parser {
2964
3239
  this.inBlockScope(() => {
2965
3240
  // Error binding is optional in catch clause since ECMAScript 2019
2966
3241
  if (catchClause.param !== null) {
2967
- this.enterPattern(catchClause.param, ident => {
3242
+ this.enterPattern(catchClause.param, (ident) => {
2968
3243
  this.defineVariable(ident);
2969
3244
  });
2970
3245
  this.walkPattern(catchClause.param);
@@ -2973,7 +3248,7 @@ class JavascriptParser extends Parser {
2973
3248
  this.blockPreWalkStatement(catchClause.body);
2974
3249
  this.prevStatement = prev;
2975
3250
  this.walkStatement(catchClause.body);
2976
- });
3251
+ }, true);
2977
3252
  }
2978
3253
 
2979
3254
  /**
@@ -3052,7 +3327,7 @@ class JavascriptParser extends Parser {
3052
3327
  }
3053
3328
 
3054
3329
  /**
3055
- * @param {TODO} expression expression
3330
+ * @param {Expression | SpreadElement | PrivateIdentifier | Super} expression expression
3056
3331
  */
3057
3332
  walkExpression(expression) {
3058
3333
  switch (expression.type) {
@@ -3138,8 +3413,9 @@ class JavascriptParser extends Parser {
3138
3413
  * @param {AwaitExpression} expression await expression
3139
3414
  */
3140
3415
  walkAwaitExpression(expression) {
3141
- if (this.scope.topLevelScope === true)
3416
+ if (this.scope.topLevelScope === true) {
3142
3417
  this.hooks.topLevelAwait.call(expression);
3418
+ }
3143
3419
  this.walkExpression(expression.argument);
3144
3420
  }
3145
3421
 
@@ -3191,7 +3467,10 @@ class JavascriptParser extends Parser {
3191
3467
  this.walkIdentifier(prop.value);
3192
3468
  this.scope.inShorthand = false;
3193
3469
  } else {
3194
- this.walkExpression(prop.value);
3470
+ this.walkExpression(
3471
+ /** @type {Exclude<Property["value"], AssignmentPattern | ObjectPattern | ArrayPattern | RestElement>} */
3472
+ (prop.value)
3473
+ );
3195
3474
  }
3196
3475
  }
3197
3476
 
@@ -3212,15 +3491,14 @@ class JavascriptParser extends Parser {
3212
3491
  for (const param of expression.params) {
3213
3492
  this.walkPattern(param);
3214
3493
  }
3215
- if (expression.body.type === "BlockStatement") {
3216
- this.detectMode(expression.body.body);
3217
- const prev = this.prevStatement;
3218
- this.preWalkStatement(expression.body);
3219
- this.prevStatement = prev;
3220
- this.walkStatement(expression.body);
3221
- } else {
3222
- this.walkExpression(expression.body);
3223
- }
3494
+
3495
+ this.detectMode(expression.body.body);
3496
+
3497
+ const prev = this.prevStatement;
3498
+
3499
+ this.preWalkStatement(expression.body);
3500
+ this.prevStatement = prev;
3501
+ this.walkStatement(expression.body);
3224
3502
  });
3225
3503
  this.scope.topLevelScope = wasTopLevel;
3226
3504
  }
@@ -3377,16 +3655,17 @@ class JavascriptParser extends Parser {
3377
3655
  return;
3378
3656
  }
3379
3657
  this.walkExpression(expression.right);
3380
- this.enterPattern(expression.left, (name, decl) => {
3658
+ this.enterPattern(expression.left, (name, _decl) => {
3381
3659
  if (!this.callHooksForName(this.hooks.assign, name, expression)) {
3382
- this.walkExpression(expression.left);
3660
+ this.walkExpression(
3661
+ /** @type {MemberExpression} */
3662
+ (expression.left)
3663
+ );
3383
3664
  }
3384
3665
  });
3385
- return;
3386
- }
3387
- if (expression.left.type.endsWith("Pattern")) {
3666
+ } else if (expression.left.type.endsWith("Pattern")) {
3388
3667
  this.walkExpression(expression.right);
3389
- this.enterPattern(expression.left, (name, decl) => {
3668
+ this.enterPattern(expression.left, (name, _decl) => {
3390
3669
  if (!this.callHooksForName(this.hooks.assign, name, expression)) {
3391
3670
  this.defineVariable(name);
3392
3671
  }
@@ -3412,7 +3691,10 @@ class JavascriptParser extends Parser {
3412
3691
  this.walkExpression(expression.left);
3413
3692
  } else {
3414
3693
  this.walkExpression(expression.right);
3415
- this.walkExpression(expression.left);
3694
+ this.walkExpression(
3695
+ /** @type {Exclude<AssignmentExpression["left"], Identifier | RestElement | MemberExpression | ObjectPattern | ArrayPattern | AssignmentPattern>} */
3696
+ (expression.left)
3697
+ );
3416
3698
  }
3417
3699
  }
3418
3700
 
@@ -3424,6 +3706,7 @@ class JavascriptParser extends Parser {
3424
3706
  if (result === undefined) {
3425
3707
  this.walkExpression(expression.test);
3426
3708
  this.walkExpression(expression.consequent);
3709
+
3427
3710
  if (expression.alternate) {
3428
3711
  this.walkExpression(expression.alternate);
3429
3712
  }
@@ -3513,9 +3796,9 @@ class JavascriptParser extends Parser {
3513
3796
  _walkIIFE(functionExpression, options, currentThis) {
3514
3797
  /**
3515
3798
  * @param {Expression | SpreadElement} argOrThis arg or this
3516
- * @returns {string | VariableInfoInterface | undefined} var info
3799
+ * @returns {string | VariableInfo | undefined} var info
3517
3800
  */
3518
- const getVarInfo = argOrThis => {
3801
+ const getVarInfo = (argOrThis) => {
3519
3802
  const renameIdentifier = this.getRenameIdentifier(argOrThis);
3520
3803
  if (
3521
3804
  renameIdentifier &&
@@ -3597,19 +3880,19 @@ class JavascriptParser extends Parser {
3597
3880
  * @param {FunctionExpression | ArrowFunctionExpression} fn function
3598
3881
  * @returns {boolean} true when simple function
3599
3882
  */
3600
- const isSimpleFunction = fn =>
3601
- fn.params.every(p => p.type === "Identifier");
3883
+ const isSimpleFunction = (fn) =>
3884
+ fn.params.every((p) => p.type === "Identifier");
3602
3885
  if (
3603
3886
  expression.callee.type === "MemberExpression" &&
3604
3887
  expression.callee.object.type.endsWith("FunctionExpression") &&
3605
3888
  !expression.callee.computed &&
3606
- // eslint-disable-next-line no-warning-comments
3607
- // @ts-ignore
3608
- // TODO check me and handle more cases
3609
- (expression.callee.property.name === "call" ||
3610
- // eslint-disable-next-line no-warning-comments
3611
- // @ts-ignore
3612
- expression.callee.property.name === "bind") &&
3889
+ /** @type {boolean} */
3890
+ (
3891
+ /** @type {Identifier} */
3892
+ (expression.callee.property).name === "call" ||
3893
+ /** @type {Identifier} */
3894
+ (expression.callee.property).name === "bind"
3895
+ ) &&
3613
3896
  expression.arguments.length > 0 &&
3614
3897
  isSimpleFunction(
3615
3898
  /** @type {FunctionExpression | ArrowFunctionExpression} */
@@ -3655,10 +3938,20 @@ class JavascriptParser extends Parser {
3655
3938
  );
3656
3939
  if (result === true) return;
3657
3940
  }
3941
+ // import("./m").then(m => { ... })
3942
+ if (
3943
+ expression.callee.object.type === "ImportExpression" &&
3944
+ expression.callee.property.type === "Identifier" &&
3945
+ expression.callee.property.name === "then"
3946
+ ) {
3947
+ const result = this.hooks.importCall.call(
3948
+ expression.callee.object,
3949
+ expression
3950
+ );
3951
+ if (result === true) return;
3952
+ }
3658
3953
  }
3659
- const callee = this.evaluateExpression(
3660
- /** @type {TODO} */ (expression.callee)
3661
- );
3954
+ const callee = this.evaluateExpression(expression.callee);
3662
3955
  if (callee.isIdentifier()) {
3663
3956
  const result1 = this.callHooksForInfo(
3664
3957
  this.hooks.callMemberChain,
@@ -3687,8 +3980,9 @@ class JavascriptParser extends Parser {
3687
3980
  if (expression.callee.type === "MemberExpression") {
3688
3981
  // because of call context we need to walk the call context as expression
3689
3982
  this.walkExpression(expression.callee.object);
3690
- if (expression.callee.computed === true)
3983
+ if (expression.callee.computed === true) {
3691
3984
  this.walkExpression(expression.callee.property);
3985
+ }
3692
3986
  } else {
3693
3987
  this.walkExpression(expression.callee);
3694
3988
  }
@@ -3730,7 +4024,7 @@ class JavascriptParser extends Parser {
3730
4024
  expression,
3731
4025
  exprInfo.name,
3732
4026
  exprInfo.rootInfo,
3733
- members.slice(),
4027
+ [...members],
3734
4028
  () =>
3735
4029
  this.callHooksForInfo(
3736
4030
  this.hooks.unhandledExpressionMemberChain,
@@ -3764,11 +4058,12 @@ class JavascriptParser extends Parser {
3764
4058
  }
3765
4059
 
3766
4060
  /**
3767
- * @param {TODO} expression member expression
4061
+ * @template R
4062
+ * @param {MemberExpression} expression member expression
3768
4063
  * @param {string} name name
3769
4064
  * @param {string | VariableInfo} rootInfo root info
3770
- * @param {string[]} members members
3771
- * @param {TODO} onUnhandled on unhandled callback
4065
+ * @param {Members} members members
4066
+ * @param {() => R | undefined} onUnhandled on unhandled callback
3772
4067
  */
3773
4068
  walkMemberExpressionWithExpressionName(
3774
4069
  expression,
@@ -3781,7 +4076,9 @@ class JavascriptParser extends Parser {
3781
4076
  // optimize the case where expression.object is a MemberExpression too.
3782
4077
  // we can keep info here when calling walkMemberExpression directly
3783
4078
  const property =
3784
- expression.property.name || `${expression.property.value}`;
4079
+ /** @type {Identifier} */
4080
+ (expression.property).name ||
4081
+ `${/** @type {Literal} */ (expression.property).value}`;
3785
4082
  name = name.slice(0, -property.length - 1);
3786
4083
  members.pop();
3787
4084
  const result = this.callHooksForInfo(
@@ -3847,8 +4144,8 @@ class JavascriptParser extends Parser {
3847
4144
  * @template R
3848
4145
  * @param {HookMap<SyncBailHook<T, R>>} hookMap hooks the should be called
3849
4146
  * @param {Expression | Super} expr expression info
3850
- * @param {(function(string, string | ScopeInfo | VariableInfo, function(): string[]): any) | undefined} fallback callback when variable in not handled by hooks
3851
- * @param {(function(string): any) | undefined} defined callback when variable is defined
4147
+ * @param {((name: string, rootInfo: string | ScopeInfo | VariableInfo, getMembers: () => Members) => R) | undefined} fallback callback when variable in not handled by hooks
4148
+ * @param {((result?: string) => R | undefined) | undefined} defined callback when variable is defined
3852
4149
  * @param {AsArray<T>} args args for the hook
3853
4150
  * @returns {R | undefined} result of hook
3854
4151
  */
@@ -3869,7 +4166,7 @@ class JavascriptParser extends Parser {
3869
4166
  hookMap,
3870
4167
  members.length === 0 ? exprName.rootInfo : exprName.name,
3871
4168
  fallback &&
3872
- (name => fallback(name, exprName.rootInfo, exprName.getMembers)),
4169
+ ((name) => fallback(name, exprName.rootInfo, exprName.getMembers)),
3873
4170
  defined && (() => defined(exprName.name)),
3874
4171
  ...args
3875
4172
  );
@@ -3899,7 +4196,7 @@ class JavascriptParser extends Parser {
3899
4196
  * @template R
3900
4197
  * @param {HookMap<SyncBailHook<T, R>>} hookMap hooks that should be called
3901
4198
  * @param {ExportedVariableInfo} info variable info
3902
- * @param {AsArray<T>} args args for the hook
4199
+ * @param {AsArray<T>} args args for the hook
3903
4200
  * @returns {R | undefined} result of hook
3904
4201
  */
3905
4202
  callHooksForInfo(hookMap, info, ...args) {
@@ -3917,8 +4214,8 @@ class JavascriptParser extends Parser {
3917
4214
  * @template R
3918
4215
  * @param {HookMap<SyncBailHook<T, R>>} hookMap hooks the should be called
3919
4216
  * @param {ExportedVariableInfo} info variable info
3920
- * @param {(function(string): any) | undefined} fallback callback when variable in not handled by hooks
3921
- * @param {(function(string=): any) | undefined} defined callback when variable is defined
4217
+ * @param {((name: string) => R | undefined) | undefined} fallback callback when variable in not handled by hooks
4218
+ * @param {((result?: string) => R | undefined) | undefined} defined callback when variable is defined
3922
4219
  * @param {AsArray<T>} args args for the hook
3923
4220
  * @returns {R | undefined} result of hook
3924
4221
  */
@@ -3944,13 +4241,13 @@ class JavascriptParser extends Parser {
3944
4241
  }
3945
4242
  tagInfo = tagInfo.next;
3946
4243
  }
3947
- if (info.freeName === true) {
4244
+ if (!info.isFree() && !info.isTagged()) {
3948
4245
  if (defined !== undefined) {
3949
4246
  return defined();
3950
4247
  }
3951
4248
  return;
3952
4249
  }
3953
- name = info.freeName;
4250
+ name = info.name;
3954
4251
  }
3955
4252
  const hook = hookMap.get(name);
3956
4253
  if (hook !== undefined) {
@@ -3967,8 +4264,8 @@ class JavascriptParser extends Parser {
3967
4264
  * @template R
3968
4265
  * @param {HookMap<SyncBailHook<T, R>>} hookMap hooks the should be called
3969
4266
  * @param {string} name key in map
3970
- * @param {(function(string): any) | undefined} fallback callback when variable in not handled by hooks
3971
- * @param {(function(): any) | undefined} defined callback when variable is defined
4267
+ * @param {((value: string) => R | undefined) | undefined} fallback callback when variable in not handled by hooks
4268
+ * @param {(() => R) | undefined} defined callback when variable is defined
3972
4269
  * @param {AsArray<T>} args args for the hook
3973
4270
  * @returns {R | undefined} result of hook
3974
4271
  */
@@ -3984,8 +4281,8 @@ class JavascriptParser extends Parser {
3984
4281
 
3985
4282
  /**
3986
4283
  * @deprecated
3987
- * @param {any} params scope params
3988
- * @param {function(): void} fn inner function
4284
+ * @param {(string | Pattern | Property)[]} params scope params
4285
+ * @param {() => void} fn inner function
3989
4286
  * @returns {void}
3990
4287
  */
3991
4288
  inScope(params, fn) {
@@ -3997,12 +4294,13 @@ class JavascriptParser extends Parser {
3997
4294
  inTaggedTemplateTag: false,
3998
4295
  isStrict: oldScope.isStrict,
3999
4296
  isAsmJs: oldScope.isAsmJs,
4297
+ terminated: undefined,
4000
4298
  definitions: oldScope.definitions.createChild()
4001
4299
  };
4002
4300
 
4003
4301
  this.undefineVariable("this");
4004
4302
 
4005
- this.enterPatterns(params, ident => {
4303
+ this.enterPatterns(params, (ident) => {
4006
4304
  this.defineVariable(ident);
4007
4305
  });
4008
4306
 
@@ -4014,7 +4312,7 @@ class JavascriptParser extends Parser {
4014
4312
  /**
4015
4313
  * @param {boolean} hasThis true, when this is defined
4016
4314
  * @param {Identifier[]} params scope params
4017
- * @param {function(): void} fn inner function
4315
+ * @param {() => void} fn inner function
4018
4316
  * @returns {void}
4019
4317
  */
4020
4318
  inClassScope(hasThis, params, fn) {
@@ -4026,6 +4324,7 @@ class JavascriptParser extends Parser {
4026
4324
  inTaggedTemplateTag: false,
4027
4325
  isStrict: oldScope.isStrict,
4028
4326
  isAsmJs: oldScope.isAsmJs,
4327
+ terminated: undefined,
4029
4328
  definitions: oldScope.definitions.createChild()
4030
4329
  };
4031
4330
 
@@ -4033,7 +4332,7 @@ class JavascriptParser extends Parser {
4033
4332
  this.undefineVariable("this");
4034
4333
  }
4035
4334
 
4036
- this.enterPatterns(params, ident => {
4335
+ this.enterPatterns(params, (ident) => {
4037
4336
  this.defineVariable(ident);
4038
4337
  });
4039
4338
 
@@ -4045,7 +4344,7 @@ class JavascriptParser extends Parser {
4045
4344
  /**
4046
4345
  * @param {boolean} hasThis true, when this is defined
4047
4346
  * @param {(Pattern | string)[]} params scope params
4048
- * @param {function(): void} fn inner function
4347
+ * @param {() => void} fn inner function
4049
4348
  * @returns {void}
4050
4349
  */
4051
4350
  inFunctionScope(hasThis, params, fn) {
@@ -4057,6 +4356,7 @@ class JavascriptParser extends Parser {
4057
4356
  inTaggedTemplateTag: false,
4058
4357
  isStrict: oldScope.isStrict,
4059
4358
  isAsmJs: oldScope.isAsmJs,
4359
+ terminated: undefined,
4060
4360
  definitions: oldScope.definitions.createChild()
4061
4361
  };
4062
4362
 
@@ -4064,7 +4364,7 @@ class JavascriptParser extends Parser {
4064
4364
  this.undefineVariable("this");
4065
4365
  }
4066
4366
 
4067
- this.enterPatterns(params, ident => {
4367
+ this.enterPatterns(params, (ident) => {
4068
4368
  this.defineVariable(ident);
4069
4369
  });
4070
4370
 
@@ -4074,10 +4374,11 @@ class JavascriptParser extends Parser {
4074
4374
  }
4075
4375
 
4076
4376
  /**
4077
- * @param {function(): void} fn inner function
4377
+ * @param {() => void} fn inner function
4378
+ * @param {boolean} inExecutedPath executed state
4078
4379
  * @returns {void}
4079
4380
  */
4080
- inBlockScope(fn) {
4381
+ inBlockScope(fn, inExecutedPath = false) {
4081
4382
  const oldScope = this.scope;
4082
4383
  this.scope = {
4083
4384
  topLevelScope: oldScope.topLevelScope,
@@ -4086,16 +4387,23 @@ class JavascriptParser extends Parser {
4086
4387
  inTaggedTemplateTag: false,
4087
4388
  isStrict: oldScope.isStrict,
4088
4389
  isAsmJs: oldScope.isAsmJs,
4390
+ terminated: oldScope.terminated,
4089
4391
  definitions: oldScope.definitions.createChild()
4090
4392
  };
4091
4393
 
4092
4394
  fn();
4093
4395
 
4396
+ const terminated = this.scope.terminated;
4397
+
4398
+ if (inExecutedPath && terminated) {
4399
+ oldScope.terminated = terminated;
4400
+ }
4401
+
4094
4402
  this.scope = oldScope;
4095
4403
  }
4096
4404
 
4097
4405
  /**
4098
- * @param {Array<Directive | Statement | ModuleDeclaration>} statements statements
4406
+ * @param {(Directive | Statement | ModuleDeclaration)[]} statements statements
4099
4407
  */
4100
4408
  detectMode(statements) {
4101
4409
  const isLiteral =
@@ -4228,7 +4536,7 @@ class JavascriptParser extends Parser {
4228
4536
  }
4229
4537
 
4230
4538
  /**
4231
- * @param {Expression | SpreadElement | PrivateIdentifier} expression expression node
4539
+ * @param {Expression | SpreadElement | PrivateIdentifier | Super} expression expression node
4232
4540
  * @returns {BasicEvaluatedExpression} evaluation result
4233
4541
  */
4234
4542
  evaluateExpression(expression) {
@@ -4242,6 +4550,7 @@ class JavascriptParser extends Parser {
4242
4550
  }
4243
4551
  }
4244
4552
  } catch (err) {
4553
+ // eslint-disable-next-line no-console
4245
4554
  console.warn(err);
4246
4555
  // ignore error
4247
4556
  }
@@ -4272,9 +4581,11 @@ class JavascriptParser extends Parser {
4272
4581
  );
4273
4582
  }
4274
4583
 
4584
+ /** @typedef {{ range?: Range, value: string, code: boolean, conditional: false | CalculatedStringResult[] }} CalculatedStringResult */
4585
+
4275
4586
  /**
4276
4587
  * @param {Expression} expression expression
4277
- * @returns {{ range?: Range, value: string, code: boolean, conditional: TODO }} result
4588
+ * @returns {CalculatedStringResult} result
4278
4589
  */
4279
4590
  parseCalculatedString(expression) {
4280
4591
  switch (expression.type) {
@@ -4322,6 +4633,7 @@ class JavascriptParser extends Parser {
4322
4633
  case "ConditionalExpression": {
4323
4634
  const consequent = this.parseCalculatedString(expression.consequent);
4324
4635
  const alternate = this.parseCalculatedString(expression.alternate);
4636
+ /** @type {CalculatedStringResult[]} */
4325
4637
  const items = [];
4326
4638
  if (consequent.conditional) {
4327
4639
  items.push(...consequent.conditional);
@@ -4366,26 +4678,44 @@ class JavascriptParser extends Parser {
4366
4678
  * @returns {ParserState} the parser state
4367
4679
  */
4368
4680
  parse(source, state) {
4369
- let ast;
4370
- /** @type {import("acorn").Comment[]} */
4371
- let comments;
4372
- const semicolons = new Set();
4373
4681
  if (source === null) {
4374
4682
  throw new Error("source must not be null");
4375
4683
  }
4684
+
4376
4685
  if (Buffer.isBuffer(source)) {
4377
- source = source.toString("utf-8");
4686
+ source = source.toString("utf8");
4378
4687
  }
4688
+
4689
+ let ast;
4690
+ /** @type {Comment[]} */
4691
+ let comments;
4692
+ /** @type {Set<number>} */
4693
+ let semicolons;
4694
+
4379
4695
  if (typeof source === "object") {
4696
+ semicolons = new Set();
4697
+
4380
4698
  ast = /** @type {Program} */ (source);
4381
4699
  comments = source.comments;
4700
+ if (source.semicolons) {
4701
+ // Forward semicolon information from the preparsed AST if present
4702
+ // This ensures the output is consistent with that of a fresh AST
4703
+ for (const pos of source.semicolons) {
4704
+ semicolons.add(pos);
4705
+ }
4706
+ }
4382
4707
  } else {
4383
- comments = [];
4384
- ast = JavascriptParser._parse(source, {
4385
- sourceType: this.sourceType,
4386
- onComment: comments,
4387
- onInsertedSemicolon: pos => semicolons.add(pos)
4388
- });
4708
+ ({ ast, comments, semicolons } = JavascriptParser._parse(
4709
+ source,
4710
+ {
4711
+ sourceType: this.sourceType,
4712
+ locations: true,
4713
+ ranges: true,
4714
+ comments: true,
4715
+ semicolons: true
4716
+ },
4717
+ this.options.parse
4718
+ ));
4389
4719
  }
4390
4720
 
4391
4721
  const oldScope = this.scope;
@@ -4401,9 +4731,9 @@ class JavascriptParser extends Parser {
4401
4731
  inTaggedTemplateTag: false,
4402
4732
  isStrict: false,
4403
4733
  isAsmJs: false,
4734
+ terminated: undefined,
4404
4735
  definitions: new StackedMap()
4405
4736
  };
4406
- /** @type {ParserState} */
4407
4737
  this.state = state;
4408
4738
  this.comments = comments;
4409
4739
  this.semicolons = semicolons;
@@ -4412,6 +4742,7 @@ class JavascriptParser extends Parser {
4412
4742
  if (this.hooks.program.call(ast, comments) === undefined) {
4413
4743
  this.destructuringAssignmentProperties = new WeakMap();
4414
4744
  this.detectMode(ast.body);
4745
+ this.modulePreWalkStatements(ast.body);
4415
4746
  this.preWalkStatements(ast.body);
4416
4747
  this.prevStatement = undefined;
4417
4748
  this.blockPreWalkStatements(ast.body);
@@ -4421,7 +4752,6 @@ class JavascriptParser extends Parser {
4421
4752
  }
4422
4753
  this.hooks.finish.call(ast, comments);
4423
4754
  this.scope = oldScope;
4424
- /** @type {ParserState} */
4425
4755
  this.state = oldState;
4426
4756
  this.comments = oldComments;
4427
4757
  this.semicolons = oldSemicolons;
@@ -4435,10 +4765,11 @@ class JavascriptParser extends Parser {
4435
4765
  * @returns {BasicEvaluatedExpression} evaluation result
4436
4766
  */
4437
4767
  evaluate(source) {
4438
- const ast = JavascriptParser._parse(`(${source})`, {
4439
- sourceType: this.sourceType,
4440
- locations: false
4441
- });
4768
+ const { ast } = JavascriptParser._parse(
4769
+ `(${source})`,
4770
+ { sourceType: this.sourceType },
4771
+ this.options.parse
4772
+ );
4442
4773
  if (ast.body.length !== 1 || ast.body[0].type !== "ExpressionStatement") {
4443
4774
  throw new Error("evaluate: Source is not a expression");
4444
4775
  }
@@ -4446,7 +4777,7 @@ class JavascriptParser extends Parser {
4446
4777
  }
4447
4778
 
4448
4779
  /**
4449
- * @param {Expression | Declaration | PrivateIdentifier | null | undefined} expr an expression
4780
+ * @param {Expression | Declaration | PrivateIdentifier | MaybeNamedFunctionDeclaration | MaybeNamedClassDeclaration | null | undefined} expr an expression
4450
4781
  * @param {number} commentsStartPos source position from which annotation comments are checked
4451
4782
  * @returns {boolean} true, when the expression is pure
4452
4783
  */
@@ -4467,14 +4798,20 @@ class JavascriptParser extends Parser {
4467
4798
  ) {
4468
4799
  return false;
4469
4800
  }
4470
- const items =
4471
- /** @type {TODO[]} */
4472
- (expr.body.body);
4473
- return items.every(item => {
4801
+ const items = expr.body.body;
4802
+ return items.every((item) => {
4803
+ if (item.type === "StaticBlock") {
4804
+ return false;
4805
+ }
4806
+
4474
4807
  if (
4475
4808
  item.computed &&
4476
4809
  item.key &&
4477
- !this.isPure(item.key, item.range[0])
4810
+ !this.isPure(
4811
+ item.key,
4812
+ /** @type {Range} */
4813
+ (item.range)[0]
4814
+ )
4478
4815
  ) {
4479
4816
  return false;
4480
4817
  }
@@ -4484,16 +4821,14 @@ class JavascriptParser extends Parser {
4484
4821
  item.value &&
4485
4822
  !this.isPure(
4486
4823
  item.value,
4487
- item.key ? item.key.range[1] : item.range[0]
4824
+ item.key
4825
+ ? /** @type {Range} */ (item.key.range)[1]
4826
+ : /** @type {Range} */ (item.range)[0]
4488
4827
  )
4489
4828
  ) {
4490
4829
  return false;
4491
4830
  }
4492
4831
 
4493
- if (item.type === "StaticBlock") {
4494
- return false;
4495
- }
4496
-
4497
4832
  if (
4498
4833
  expr.superClass &&
4499
4834
  item.type === "MethodDefinition" &&
@@ -4517,7 +4852,7 @@ class JavascriptParser extends Parser {
4517
4852
  return true;
4518
4853
 
4519
4854
  case "VariableDeclaration":
4520
- return expr.declarations.every(decl =>
4855
+ return expr.declarations.every((decl) =>
4521
4856
  this.isPure(decl.init, /** @type {Range} */ (decl.range)[0])
4522
4857
  );
4523
4858
 
@@ -4541,7 +4876,7 @@ class JavascriptParser extends Parser {
4541
4876
  );
4542
4877
 
4543
4878
  case "SequenceExpression":
4544
- return expr.expressions.every(expr => {
4879
+ return expr.expressions.every((expr) => {
4545
4880
  const pureFlag = this.isPure(expr, commentsStartPos);
4546
4881
  commentsStartPos = /** @type {Range} */ (expr.range)[1];
4547
4882
  return pureFlag;
@@ -4554,13 +4889,13 @@ class JavascriptParser extends Parser {
4554
4889
  commentsStartPos,
4555
4890
  /** @type {Range} */ (expr.range)[0]
4556
4891
  ]).some(
4557
- comment =>
4892
+ (comment) =>
4558
4893
  comment.type === "Block" &&
4559
4894
  /^\s*(#|@)__PURE__\s*$/.test(comment.value)
4560
4895
  );
4561
4896
  if (!pureFlag) return false;
4562
4897
  commentsStartPos = /** @type {Range} */ (expr.callee.range)[1];
4563
- return expr.arguments.every(arg => {
4898
+ return expr.arguments.every((arg) => {
4564
4899
  if (arg.type === "SpreadElement") return false;
4565
4900
  const pureFlag = this.isPure(arg, commentsStartPos);
4566
4901
  commentsStartPos = /** @type {Range} */ (arg.range)[1];
@@ -4666,8 +5001,8 @@ class JavascriptParser extends Parser {
4666
5001
 
4667
5002
  /**
4668
5003
  * @param {string} name name
4669
- * @param {symbol} tag tag info
4670
- * @returns {TODO} tag data
5004
+ * @param {Tag} tag tag info
5005
+ * @returns {TagData | undefined} tag data
4671
5006
  */
4672
5007
  getTagData(name, tag) {
4673
5008
  const info = this.scope.definitions.get(name);
@@ -4682,27 +5017,33 @@ class JavascriptParser extends Parser {
4682
5017
 
4683
5018
  /**
4684
5019
  * @param {string} name name
4685
- * @param {symbol} tag tag info
4686
- * @param {TODO=} data data
5020
+ * @param {Tag} tag tag info
5021
+ * @param {TagData=} data data
5022
+ * @param {VariableInfoFlagsType=} flags flags
4687
5023
  */
4688
- tagVariable(name, tag, data) {
5024
+ tagVariable(name, tag, data, flags = VariableInfoFlags.Tagged) {
4689
5025
  const oldInfo = this.scope.definitions.get(name);
4690
5026
  /** @type {VariableInfo} */
4691
5027
  let newInfo;
4692
5028
  if (oldInfo === undefined) {
4693
- newInfo = new VariableInfo(this.scope, name, {
5029
+ newInfo = new VariableInfo(this.scope, name, flags, {
4694
5030
  tag,
4695
5031
  data,
4696
5032
  next: undefined
4697
5033
  });
4698
5034
  } else if (oldInfo instanceof VariableInfo) {
4699
- newInfo = new VariableInfo(oldInfo.declaredScope, oldInfo.freeName, {
4700
- tag,
4701
- data,
4702
- next: oldInfo.tagInfo
4703
- });
5035
+ newInfo = new VariableInfo(
5036
+ oldInfo.declaredScope,
5037
+ oldInfo.name,
5038
+ /** @type {VariableInfoFlagsType} */ (oldInfo.flags | flags),
5039
+ {
5040
+ tag,
5041
+ data,
5042
+ next: oldInfo.tagInfo
5043
+ }
5044
+ );
4704
5045
  } else {
4705
- newInfo = new VariableInfo(oldInfo, true, {
5046
+ newInfo = new VariableInfo(oldInfo, name, flags, {
4706
5047
  tag,
4707
5048
  data,
4708
5049
  next: undefined
@@ -4717,8 +5058,12 @@ class JavascriptParser extends Parser {
4717
5058
  defineVariable(name) {
4718
5059
  const oldInfo = this.scope.definitions.get(name);
4719
5060
  // Don't redefine variable in same scope to keep existing tags
4720
- if (oldInfo instanceof VariableInfo && oldInfo.declaredScope === this.scope)
5061
+ if (
5062
+ oldInfo instanceof VariableInfo &&
5063
+ oldInfo.declaredScope === this.scope
5064
+ ) {
4721
5065
  return;
5066
+ }
4722
5067
  this.scope.definitions.set(name, this.scope);
4723
5068
  }
4724
5069
 
@@ -4737,14 +5082,14 @@ class JavascriptParser extends Parser {
4737
5082
  const info = this.scope.definitions.get(name);
4738
5083
  if (info === undefined) return false;
4739
5084
  if (info instanceof VariableInfo) {
4740
- return info.freeName === true;
5085
+ return !info.isFree();
4741
5086
  }
4742
5087
  return true;
4743
5088
  }
4744
5089
 
4745
5090
  /**
4746
5091
  * @param {string} name variable name
4747
- * @returns {string | ExportedVariableInfo} info for this variable
5092
+ * @returns {ExportedVariableInfo} info for this variable
4748
5093
  */
4749
5094
  getVariableInfo(name) {
4750
5095
  const value = this.scope.definitions.get(name);
@@ -4756,7 +5101,7 @@ class JavascriptParser extends Parser {
4756
5101
 
4757
5102
  /**
4758
5103
  * @param {string} name variable name
4759
- * @param {string | ExportedVariableInfo} variableInfo new info for this variable
5104
+ * @param {ExportedVariableInfo} variableInfo new info for this variable
4760
5105
  * @returns {void}
4761
5106
  */
4762
5107
  setVariable(name, variableInfo) {
@@ -4766,7 +5111,12 @@ class JavascriptParser extends Parser {
4766
5111
  } else {
4767
5112
  this.scope.definitions.set(
4768
5113
  name,
4769
- new VariableInfo(this.scope, variableInfo, undefined)
5114
+ new VariableInfo(
5115
+ this.scope,
5116
+ variableInfo,
5117
+ VariableInfoFlags.Free,
5118
+ undefined
5119
+ )
4770
5120
  );
4771
5121
  }
4772
5122
  } else {
@@ -4779,19 +5129,24 @@ class JavascriptParser extends Parser {
4779
5129
  * @returns {VariableInfo} variable info
4780
5130
  */
4781
5131
  evaluatedVariable(tagInfo) {
4782
- return new VariableInfo(this.scope, undefined, tagInfo);
5132
+ return new VariableInfo(
5133
+ this.scope,
5134
+ undefined,
5135
+ VariableInfoFlags.Evaluated,
5136
+ tagInfo
5137
+ );
4783
5138
  }
4784
5139
 
4785
5140
  /**
4786
5141
  * @param {Range} range range of the comment
4787
- * @returns {{ options: Record<string, any> | null, errors: (Error & { comment: Comment })[] | null }} result
5142
+ * @returns {{ options: Record<string, EXPECTED_ANY> | null, errors: (Error & { comment: Comment })[] | null }} result
4788
5143
  */
4789
5144
  parseCommentOptions(range) {
4790
5145
  const comments = this.getComments(range);
4791
5146
  if (comments.length === 0) {
4792
5147
  return EMPTY_COMMENT_OPTIONS;
4793
5148
  }
4794
- /** @type {Record<string, EXPECTED_ANY> } */
5149
+ /** @type {Record<string, EXPECTED_ANY>} */
4795
5150
  const options = {};
4796
5151
  /** @type {(Error & { comment: Comment })[]} */
4797
5152
  const errors = [];
@@ -4827,7 +5182,7 @@ class JavascriptParser extends Parser {
4827
5182
 
4828
5183
  /**
4829
5184
  * @param {Expression | Super} expression a member expression
4830
- * @returns {{ members: string[], object: Expression | Super, membersOptionals: boolean[], memberRanges: Range[] }} member names (reverse order) and remaining object
5185
+ * @returns {{ members: Members, object: Expression | Super, membersOptionals: MembersOptionals, memberRanges: MemberRanges }} member names (reverse order) and remaining object
4831
5186
  */
4832
5187
  extractMemberExpressionChain(expression) {
4833
5188
  /** @type {Node} */
@@ -4864,9 +5219,27 @@ class JavascriptParser extends Parser {
4864
5219
  getFreeInfoFromVariable(varName) {
4865
5220
  const info = this.getVariableInfo(varName);
4866
5221
  let name;
4867
- if (info instanceof VariableInfo) {
4868
- name = info.freeName;
4869
- if (typeof name !== "string") return;
5222
+ if (info instanceof VariableInfo && info.name) {
5223
+ if (!info.isFree()) return;
5224
+ name = info.name;
5225
+ } else if (typeof info !== "string") {
5226
+ return;
5227
+ } else {
5228
+ name = info;
5229
+ }
5230
+ return { info, name };
5231
+ }
5232
+
5233
+ /**
5234
+ * @param {string} varName variable name
5235
+ * @returns {{name: string, info: VariableInfo | string} | undefined} name of the free variable and variable info for that
5236
+ */
5237
+ getNameInfoFromVariable(varName) {
5238
+ const info = this.getVariableInfo(varName);
5239
+ let name;
5240
+ if (info instanceof VariableInfo && info.name) {
5241
+ if (!info.isFree() && !info.isTagged()) return;
5242
+ name = info.name;
4870
5243
  } else if (typeof info !== "string") {
4871
5244
  return;
4872
5245
  } else {
@@ -4875,8 +5248,8 @@ class JavascriptParser extends Parser {
4875
5248
  return { info, name };
4876
5249
  }
4877
5250
 
4878
- /** @typedef {{ type: "call", call: CallExpression, calleeName: string, rootInfo: string | VariableInfo, getCalleeMembers: () => string[], name: string, getMembers: () => string[], getMembersOptionals: () => boolean[], getMemberRanges: () => Range[]}} CallExpressionInfo */
4879
- /** @typedef {{ type: "expression", rootInfo: string | VariableInfo, name: string, getMembers: () => string[], getMembersOptionals: () => boolean[], getMemberRanges: () => Range[]}} ExpressionExpressionInfo */
5251
+ /** @typedef {{ type: "call", call: CallExpression, calleeName: string, rootInfo: string | VariableInfo, getCalleeMembers: () => CalleeMembers, name: string, getMembers: () => Members, getMembersOptionals: () => MembersOptionals, getMemberRanges: () => MemberRanges }} CallExpressionInfo */
5252
+ /** @typedef {{ type: "expression", rootInfo: string | VariableInfo, name: string, getMembers: () => Members, getMembersOptionals: () => MembersOptionals, getMemberRanges: () => MemberRanges }} ExpressionExpressionInfo */
4880
5253
 
4881
5254
  /**
4882
5255
  * @param {Expression | Super} expression a member expression
@@ -4897,7 +5270,7 @@ class JavascriptParser extends Parser {
4897
5270
  }
4898
5271
  const rootName = getRootName(callee);
4899
5272
  if (!rootName) return;
4900
- const result = this.getFreeInfoFromVariable(rootName);
5273
+ const result = this.getNameInfoFromVariable(rootName);
4901
5274
  if (!result) return;
4902
5275
  const { info: rootInfo, name: resolvedRoot } = result;
4903
5276
  const calleeName = objectAndMembersToName(resolvedRoot, rootMembers);
@@ -4920,7 +5293,7 @@ class JavascriptParser extends Parser {
4920
5293
  const rootName = getRootName(object);
4921
5294
  if (!rootName) return;
4922
5295
 
4923
- const result = this.getFreeInfoFromVariable(rootName);
5296
+ const result = this.getNameInfoFromVariable(rootName);
4924
5297
  if (!result) return;
4925
5298
  const { info: rootInfo, name: resolvedRoot } = result;
4926
5299
  return {
@@ -4936,8 +5309,8 @@ class JavascriptParser extends Parser {
4936
5309
  }
4937
5310
 
4938
5311
  /**
4939
- * @param {MemberExpression} expression an expression
4940
- * @returns {{ name: string, rootInfo: ExportedVariableInfo, getMembers: () => string[]} | undefined} name info
5312
+ * @param {Expression} expression an expression
5313
+ * @returns {{ name: string, rootInfo: ExportedVariableInfo, getMembers: () => Members } | undefined} name info
4941
5314
  */
4942
5315
  getNameForExpression(expression) {
4943
5316
  return this.getMemberExpressionInfo(
@@ -4946,27 +5319,84 @@ class JavascriptParser extends Parser {
4946
5319
  );
4947
5320
  }
4948
5321
 
5322
+ /**
5323
+ * @param {Compilation} compilation compilation
5324
+ * @param {Module} module module
5325
+ * @returns {ParseFunction | undefined} parser
5326
+ */
5327
+ static _getModuleParseFunction(compilation, module) {
5328
+ // Get from module if available
5329
+ if (
5330
+ module instanceof NormalModule &&
5331
+ module.parser instanceof JavascriptParser
5332
+ ) {
5333
+ return module.parser.options.parse;
5334
+ }
5335
+
5336
+ // Fallback to the global javascript parse function
5337
+ if (typeof compilation.options.module.parser.javascript !== "undefined") {
5338
+ return compilation.options.module.parser.javascript.parse;
5339
+ }
5340
+ }
5341
+
4949
5342
  /**
4950
5343
  * @param {string} code source code
4951
- * @param {ParseOptions} options parsing options
4952
- * @returns {Program} parsed ast
5344
+ * @param {InternalParseOptions} options parsing options
5345
+ * @param {ParseFunction=} customParse custom function to parse
5346
+ * @returns {ParseResult} parse result
4953
5347
  */
4954
- static _parse(code, options) {
5348
+ static _parse(code, options, customParse) {
4955
5349
  const type = options ? options.sourceType : "module";
4956
- /** @type {AcornOptions} */
5350
+ /** @type {ParseOptions} */
4957
5351
  const parserOptions = {
4958
5352
  ...defaultParserOptions,
4959
5353
  allowReturnOutsideFunction: type === "script",
4960
5354
  ...options,
4961
5355
  sourceType: type === "auto" ? "module" : type
4962
5356
  };
5357
+ /**
5358
+ * @param {string} code source code
5359
+ * @param {ParseOptions} options parsing options
5360
+ * @returns {ParseResult} parse result
5361
+ */
5362
+ const internalParse = (code, options) => {
5363
+ if (typeof customParse === "function") {
5364
+ return customParse(code, options);
5365
+ }
5366
+
5367
+ /** @type {Comment[]} */
5368
+ const comments = [];
5369
+
5370
+ if (options.comments) {
5371
+ /** @type {AcornOptions} */
5372
+ (options).onComment = comments;
5373
+ }
5374
+
5375
+ /** @type {Set<number>} */
5376
+ const semicolons = new Set();
5377
+
5378
+ if (options.semicolons) {
5379
+ /** @type {AcornOptions} */
5380
+ (options).onInsertedSemicolon = (pos) => semicolons.add(pos);
5381
+ }
5382
+
5383
+ const ast =
5384
+ /** @type {Program} */
5385
+ (parser.parse(code, /** @type {AcornOptions} */ (options)));
5386
+
5387
+ return { ast, comments, semicolons };
5388
+ };
4963
5389
 
4964
- /** @type {import("acorn").Program | undefined} */
5390
+ /** @type {Program | undefined} */
4965
5391
  let ast;
5392
+ /** @type {Comment[] | undefined} */
5393
+ let comments;
5394
+ /** @type {Set<number> | undefined} */
5395
+ let semicolons;
4966
5396
  let error;
4967
5397
  let threw = false;
4968
5398
  try {
4969
- ast = parser.parse(code, parserOptions);
5399
+ ({ ast, comments, semicolons } = internalParse(code, parserOptions));
4970
5400
  } catch (err) {
4971
5401
  error = err;
4972
5402
  threw = true;
@@ -4974,14 +5404,10 @@ class JavascriptParser extends Parser {
4974
5404
 
4975
5405
  if (threw && type === "auto") {
4976
5406
  parserOptions.sourceType = "script";
4977
- if (!("allowReturnOutsideFunction" in options)) {
4978
- parserOptions.allowReturnOutsideFunction = true;
4979
- }
4980
- if (Array.isArray(parserOptions.onComment)) {
4981
- parserOptions.onComment.length = 0;
4982
- }
5407
+ parserOptions.allowReturnOutsideFunction = true;
5408
+
4983
5409
  try {
4984
- ast = parser.parse(code, parserOptions);
5410
+ ({ ast, comments, semicolons } = internalParse(code, parserOptions));
4985
5411
  threw = false;
4986
5412
  } catch (_err) {
4987
5413
  // we use the error from first parse try
@@ -4993,15 +5419,25 @@ class JavascriptParser extends Parser {
4993
5419
  throw error;
4994
5420
  }
4995
5421
 
4996
- return /** @type {Program} */ (ast);
5422
+ return /** @type {ParseResult} */ ({ ast, comments, semicolons });
5423
+ }
5424
+
5425
+ /**
5426
+ * @param {((BaseParser: typeof AcornParser) => typeof AcornParser)[]} plugins parser plugin
5427
+ * @returns {typeof JavascriptParser} parser
5428
+ */
5429
+ static extend(...plugins) {
5430
+ parser = parser.extend(...plugins);
5431
+ return JavascriptParser;
4997
5432
  }
4998
5433
  }
4999
5434
 
5000
5435
  module.exports = JavascriptParser;
5001
5436
  module.exports.ALLOWED_MEMBER_TYPES_ALL = ALLOWED_MEMBER_TYPES_ALL;
5002
- module.exports.ALLOWED_MEMBER_TYPES_EXPRESSION =
5003
- ALLOWED_MEMBER_TYPES_EXPRESSION;
5004
5437
  module.exports.ALLOWED_MEMBER_TYPES_CALL_EXPRESSION =
5005
5438
  ALLOWED_MEMBER_TYPES_CALL_EXPRESSION;
5006
- module.exports.getImportAttributes = getImportAttributes;
5439
+ module.exports.ALLOWED_MEMBER_TYPES_EXPRESSION =
5440
+ ALLOWED_MEMBER_TYPES_EXPRESSION;
5007
5441
  module.exports.VariableInfo = VariableInfo;
5442
+ module.exports.VariableInfoFlags = VariableInfoFlags;
5443
+ module.exports.getImportAttributes = getImportAttributes;