@depup/webpack 5.109.2-depup.0 → 5.110.1-depup.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (640) hide show
  1. package/README.md +5 -5
  2. package/changes.json +7 -7
  3. package/lib/APIPlugin.js +123 -17
  4. package/lib/AsyncDependenciesBlock.js +10 -7
  5. package/lib/AutomaticPrefetchPlugin.js +1 -1
  6. package/lib/BannerPlugin.js +10 -6
  7. package/lib/CacheFacade.js +6 -6
  8. package/lib/Chunk.js +14 -11
  9. package/lib/ChunkGraph.js +26 -17
  10. package/lib/ChunkGroup.js +7 -7
  11. package/lib/ChunkTemplate.js +35 -44
  12. package/lib/CircularModulesPlugin.js +205 -28
  13. package/lib/CleanPlugin.js +4 -7
  14. package/lib/CodeGenerationResults.js +11 -8
  15. package/lib/CompatibilityPlugin.js +7 -7
  16. package/lib/Compilation.js +688 -409
  17. package/lib/Compiler.js +53 -38
  18. package/lib/ConcatenationScope.js +117 -8
  19. package/lib/ConditionalInitFragment.js +3 -3
  20. package/lib/ConstPlugin.js +13 -11
  21. package/lib/ContextExclusionPlugin.js +1 -1
  22. package/lib/ContextModule.js +146 -54
  23. package/lib/ContextModuleFactory.js +46 -14
  24. package/lib/ContextReplacementPlugin.js +12 -14
  25. package/lib/DefinePlugin.js +121 -37
  26. package/lib/DependenciesBlock.js +9 -6
  27. package/lib/Dependency.js +36 -16
  28. package/lib/DependencyTemplate.js +11 -12
  29. package/lib/DependencyTemplates.js +3 -3
  30. package/lib/DotenvPlugin.js +50 -13
  31. package/lib/DynamicEntryPlugin.js +8 -4
  32. package/lib/EntryOptionPlugin.js +8 -4
  33. package/lib/EntryPlugin.js +2 -2
  34. package/lib/Entrypoint.js +6 -2
  35. package/lib/EnvironmentPlugin.js +2 -2
  36. package/lib/EvalDevToolModulePlugin.js +8 -4
  37. package/lib/EvalSourceMapDevToolPlugin.js +15 -8
  38. package/lib/ExportsInfo.js +101 -14
  39. package/lib/ExportsInfoApiPlugin.js +2 -4
  40. package/lib/ExternalModule.js +232 -77
  41. package/lib/ExternalModuleFactoryPlugin.js +97 -38
  42. package/lib/ExternalsPlugin.js +10 -6
  43. package/lib/FileSystemInfo.js +44 -70
  44. package/lib/FlagAllModulesAsUsedPlugin.js +2 -3
  45. package/lib/FlagDependencyExportsPlugin.js +76 -19
  46. package/lib/FlagDependencyUsagePlugin.js +32 -47
  47. package/lib/FlagEntryExportAsUsedPlugin.js +1 -1
  48. package/lib/Generator.js +36 -15
  49. package/lib/HotModuleReplacementPlugin.js +16 -44
  50. package/lib/IgnorePlugin.js +8 -4
  51. package/lib/IgnoreWarningsPlugin.js +2 -2
  52. package/lib/InitFragment.js +8 -4
  53. package/lib/JavascriptMetaInfoPlugin.js +35 -4
  54. package/lib/LazyBarrel.js +3 -4
  55. package/lib/LibraryTemplatePlugin.js +10 -6
  56. package/lib/LoaderOptionsPlugin.js +7 -3
  57. package/lib/LoaderTargetPlugin.js +1 -1
  58. package/lib/MainTemplate.js +49 -42
  59. package/lib/ManifestPlugin.js +12 -11
  60. package/lib/Module.js +62 -33
  61. package/lib/ModuleFactory.js +3 -3
  62. package/lib/ModuleFilenameHelpers.js +9 -4
  63. package/lib/ModuleGraph.js +195 -21
  64. package/lib/ModuleGraphConnection.js +6 -13
  65. package/lib/ModuleInfoHeaderPlugin.js +8 -10
  66. package/lib/ModuleTemplate.js +62 -63
  67. package/lib/MultiCompiler.js +130 -64
  68. package/lib/MultiStats.js +40 -9
  69. package/lib/MultiWatching.js +3 -3
  70. package/lib/NoEmitOnErrorsPlugin.js +1 -1
  71. package/lib/NodeStuffPlugin.js +29 -19
  72. package/lib/NormalModule.js +141 -85
  73. package/lib/NormalModuleFactory.js +555 -110
  74. package/lib/NormalModuleReplacementPlugin.js +5 -8
  75. package/lib/NullFactory.js +6 -2
  76. package/lib/OptionsApply.js +7 -3
  77. package/lib/Parser.js +7 -3
  78. package/lib/PlatformPlugin.js +2 -2
  79. package/lib/PrefetchPlugin.js +1 -1
  80. package/lib/ProgressPlugin.js +16 -13
  81. package/lib/ProvidePlugin.js +3 -5
  82. package/lib/RawModule.js +25 -17
  83. package/lib/RecordIdsPlugin.js +3 -3
  84. package/lib/RequestShortener.js +1 -1
  85. package/lib/ResolverFactory.js +2 -2
  86. package/lib/RuntimeGlobals.js +22 -10
  87. package/lib/RuntimeModule.js +29 -19
  88. package/lib/RuntimePlugin.js +332 -169
  89. package/lib/RuntimeTemplate.js +2792 -352
  90. package/lib/SelfModuleFactory.js +7 -3
  91. package/lib/SourceMapDevToolModuleOptionsPlugin.js +6 -2
  92. package/lib/SourceMapDevToolPlugin.js +30 -20
  93. package/lib/Stats.js +3 -4
  94. package/lib/Template.js +32 -22
  95. package/lib/TemplatedPathPlugin.js +96 -14
  96. package/lib/UseStrictPlugin.js +4 -6
  97. package/lib/WarnCaseSensitiveModulesPlugin.js +4 -4
  98. package/lib/WarnDeprecatedOptionPlugin.js +1 -1
  99. package/lib/WarnNoModeSetPlugin.js +1 -1
  100. package/lib/WatchIgnorePlugin.js +8 -6
  101. package/lib/Watching.js +8 -8
  102. package/lib/WebpackIsIncludedPlugin.js +2 -4
  103. package/lib/WebpackOptionsApply.js +308 -18
  104. package/lib/WebpackOptionsDefaulter.js +6 -2
  105. package/lib/asset/AssetBytesGenerator.js +12 -10
  106. package/lib/asset/AssetBytesParser.js +2 -4
  107. package/lib/asset/AssetGenerator.js +188 -95
  108. package/lib/asset/AssetModule.js +7 -3
  109. package/lib/asset/AssetModulesPlugin.js +110 -38
  110. package/lib/asset/AssetParser.js +9 -7
  111. package/lib/asset/AssetSourceGenerator.js +60 -13
  112. package/lib/asset/AssetSourceParser.js +2 -4
  113. package/lib/asset/RawDataUrlModule.js +24 -16
  114. package/lib/asset/WebManifestGenerator.js +8 -10
  115. package/lib/asset/WebManifestParser.js +24 -10
  116. package/lib/async-modules/AsyncModuleHelpers.js +2 -2
  117. package/lib/async-modules/AwaitDependenciesInitFragment.js +2 -2
  118. package/lib/async-modules/InferAsyncModulesPlugin.js +2 -2
  119. package/lib/async-modules/isGeneratorLowered.js +4 -4
  120. package/lib/buildChunkGraph.js +36 -27
  121. package/lib/bun/BunTargetPlugin.js +1 -1
  122. package/lib/cache/AddBuildDependenciesPlugin.js +1 -1
  123. package/lib/cache/AddManagedPathsPlugin.js +1 -1
  124. package/lib/cache/IdleFileCachePlugin.js +2 -2
  125. package/lib/cache/MemoryCachePlugin.js +18 -10
  126. package/lib/cache/MemoryWithGcCachePlugin.js +34 -22
  127. package/lib/cache/PackFileCacheStrategy.js +30 -23
  128. package/lib/cache/ResolverCachePlugin.js +38 -18
  129. package/lib/cache/getLazyHashedEtag.js +1 -2
  130. package/lib/cache/mergeEtags.js +1 -1
  131. package/lib/cli.js +1 -3
  132. package/lib/config/browserslistTargetHandler.js +41 -5
  133. package/lib/config/defaults.js +261 -79
  134. package/lib/config/defineConfig.js +10 -2
  135. package/lib/config/getClaimedAssetTypes.js +65 -0
  136. package/lib/config/normalization.js +36 -16
  137. package/lib/config/target.js +46 -3
  138. package/lib/container/ContainerEntryDependency.js +1 -1
  139. package/lib/container/ContainerEntryModule.js +24 -15
  140. package/lib/container/ContainerEntryModuleFactory.js +7 -3
  141. package/lib/container/ContainerPlugin.js +9 -10
  142. package/lib/container/ContainerReferencePlugin.js +6 -2
  143. package/lib/container/FallbackDependency.js +1 -1
  144. package/lib/container/FallbackModule.js +24 -17
  145. package/lib/container/FallbackModuleFactory.js +7 -3
  146. package/lib/container/HoistContainerReferencesPlugin.js +6 -11
  147. package/lib/container/ModuleFederationPlugin.js +7 -24
  148. package/lib/container/RemoteModule.js +27 -19
  149. package/lib/container/RemoteRuntimeModule.js +10 -8
  150. package/lib/container/moduleFederationHooks.js +32 -0
  151. package/lib/css/CssGenerator.js +171 -43
  152. package/lib/css/CssInjectStyleRuntimeModule.js +7 -5
  153. package/lib/css/CssLoadingRuntimeModule.js +57 -24
  154. package/lib/css/CssModule.js +10 -7
  155. package/lib/css/CssModulesPlugin.js +168 -88
  156. package/lib/css/CssParser.js +1113 -568
  157. package/lib/css/CssServerStylesRuntimeModule.js +54 -0
  158. package/lib/css/cssMinify.js +168 -0
  159. package/lib/css/data.js +5324 -0
  160. package/lib/css/syntax.js +9579 -232
  161. package/lib/debug/ProfilingPlugin.js +14 -9
  162. package/lib/deno/DenoTargetPlugin.js +1 -1
  163. package/lib/dependencies/AMDDefineDependency.js +112 -87
  164. package/lib/dependencies/AMDDefineDependencyParserPlugin.js +30 -17
  165. package/lib/dependencies/AMDPlugin.js +9 -7
  166. package/lib/dependencies/AMDRequireArrayDependency.js +5 -5
  167. package/lib/dependencies/AMDRequireContextDependency.js +2 -2
  168. package/lib/dependencies/AMDRequireDependenciesBlock.js +1 -1
  169. package/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js +25 -14
  170. package/lib/dependencies/AMDRequireDependency.js +8 -7
  171. package/lib/dependencies/AMDRequireItemDependency.js +1 -1
  172. package/lib/dependencies/AMDRuntimeModules.js +21 -1
  173. package/lib/dependencies/BuildTimeConstDependency.js +102 -0
  174. package/lib/dependencies/CachedConstDependency.js +11 -8
  175. package/lib/dependencies/CommonJsDependencyHelpers.js +67 -46
  176. package/lib/dependencies/CommonJsExportRequireDependency.js +121 -45
  177. package/lib/dependencies/CommonJsExportsDependency.js +53 -49
  178. package/lib/dependencies/CommonJsExportsParserPlugin.js +207 -25
  179. package/lib/dependencies/CommonJsFullRequireDependency.js +119 -34
  180. package/lib/dependencies/CommonJsImportsParserPlugin.js +100 -50
  181. package/lib/dependencies/CommonJsObjectExportDependency.js +188 -0
  182. package/lib/dependencies/CommonJsPlugin.js +35 -6
  183. package/lib/dependencies/CommonJsRequireContextDependency.js +5 -6
  184. package/lib/dependencies/CommonJsRequireDependency.js +156 -27
  185. package/lib/dependencies/CommonJsSelfReferenceDependency.js +63 -38
  186. package/lib/dependencies/ConstDependency.js +8 -9
  187. package/lib/dependencies/ContextDependency.js +12 -8
  188. package/lib/dependencies/ContextDependencyHelpers.js +14 -9
  189. package/lib/dependencies/ContextDependencyTemplateAsId.js +4 -4
  190. package/lib/dependencies/ContextDependencyTemplateAsRequireCall.js +4 -4
  191. package/lib/dependencies/ContextElementDependency.js +31 -12
  192. package/lib/dependencies/CreateRequireParserPlugin.js +12 -7
  193. package/lib/dependencies/CreateScriptUrlDependency.js +4 -4
  194. package/lib/dependencies/CssIcssExportDependency.js +56 -28
  195. package/lib/dependencies/CssIcssImportDependency.js +17 -13
  196. package/lib/dependencies/CssIcssSymbolDependency.js +9 -10
  197. package/lib/dependencies/CssImportDependency.js +18 -9
  198. package/lib/dependencies/CssUrlDependency.js +17 -13
  199. package/lib/dependencies/DllEntryDependency.js +1 -1
  200. package/lib/dependencies/DynamicExports.js +2 -2
  201. package/lib/dependencies/ExportBindingInitFragment.js +36 -9
  202. package/lib/dependencies/ExportsInfoDependency.js +7 -8
  203. package/lib/dependencies/ExternalModuleDependency.js +9 -5
  204. package/lib/dependencies/ExternalModuleInitFragment.js +2 -2
  205. package/lib/dependencies/ExternalModuleInitFragmentDependency.js +8 -5
  206. package/lib/dependencies/HarmonyAcceptDependency.js +5 -5
  207. package/lib/dependencies/HarmonyCompatibilityDependency.js +52 -17
  208. package/lib/dependencies/HarmonyDetectionParserPlugin.js +11 -7
  209. package/lib/dependencies/HarmonyEvaluatedImportSpecifierDependency.js +13 -10
  210. package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +78 -12
  211. package/lib/dependencies/HarmonyExportExpressionDependency.js +23 -18
  212. package/lib/dependencies/HarmonyExportHeaderDependency.js +7 -7
  213. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +143 -63
  214. package/lib/dependencies/HarmonyExportInitFragment.js +18 -6
  215. package/lib/dependencies/HarmonyExportSpecifierDependency.js +51 -14
  216. package/lib/dependencies/HarmonyExports.js +7 -4
  217. package/lib/dependencies/HarmonyImportDependency.js +27 -19
  218. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +31 -24
  219. package/lib/dependencies/HarmonyImportGuard.js +20 -30
  220. package/lib/dependencies/HarmonyImportSideEffectDependency.js +38 -9
  221. package/lib/dependencies/HarmonyImportSpecifierDependency.js +97 -49
  222. package/lib/dependencies/HarmonyModulesPlugin.js +7 -3
  223. package/lib/dependencies/HarmonyTopLevelThisParserPlugin.js +1 -3
  224. package/lib/dependencies/HtmlEntryDependency.js +37 -29
  225. package/lib/dependencies/HtmlInlineHtmlDependency.js +7 -8
  226. package/lib/dependencies/HtmlInlineScriptDependency.js +11 -8
  227. package/lib/dependencies/HtmlInlineStyleDependency.js +7 -10
  228. package/lib/dependencies/HtmlSourceDependency.js +22 -14
  229. package/lib/dependencies/ImportContextDependency.js +2 -2
  230. package/lib/dependencies/ImportDependency.js +24 -20
  231. package/lib/dependencies/ImportEagerDependency.js +6 -9
  232. package/lib/dependencies/ImportMetaContextDependency.js +2 -2
  233. package/lib/dependencies/ImportMetaContextDependencyParserPlugin.js +14 -13
  234. package/lib/dependencies/ImportMetaContextPlugin.js +7 -3
  235. package/lib/dependencies/ImportMetaGlobDependency.js +2 -2
  236. package/lib/dependencies/ImportMetaGlobDependencyParserPlugin.js +2 -3
  237. package/lib/dependencies/ImportMetaGlobHelpers.js +19 -22
  238. package/lib/dependencies/ImportMetaHotAcceptDependency.js +1 -1
  239. package/lib/dependencies/ImportMetaHotDeclineDependency.js +1 -1
  240. package/lib/dependencies/ImportMetaPlugin.js +154 -71
  241. package/lib/dependencies/ImportMetaResolveDependency.js +3 -4
  242. package/lib/dependencies/ImportParserPlugin.js +49 -35
  243. package/lib/dependencies/ImportPhase.js +12 -5
  244. package/lib/dependencies/ImportPlugin.js +7 -3
  245. package/lib/dependencies/ImportWeakDependency.js +6 -9
  246. package/lib/dependencies/JsonExportsDependency.js +11 -7
  247. package/lib/dependencies/LoaderDependency.js +2 -2
  248. package/lib/dependencies/LoaderImportDependency.js +2 -2
  249. package/lib/dependencies/LoaderPlugin.js +11 -7
  250. package/lib/dependencies/LocalModuleDependency.js +5 -5
  251. package/lib/dependencies/LocalModulesHelpers.js +1 -1
  252. package/lib/dependencies/ModuleDecoratorDependency.js +6 -7
  253. package/lib/dependencies/ModuleDependency.js +9 -6
  254. package/lib/dependencies/ModuleDependencyTemplateAsId.js +4 -4
  255. package/lib/dependencies/ModuleDependencyTemplateAsRequireId.js +3 -3
  256. package/lib/dependencies/ModuleHotAcceptDependency.js +1 -1
  257. package/lib/dependencies/ModuleHotDeclineDependency.js +1 -1
  258. package/lib/dependencies/ModuleInitFragmentDependency.js +24 -10
  259. package/lib/dependencies/NullDependency.js +3 -3
  260. package/lib/dependencies/ProvidedDependency.js +14 -10
  261. package/lib/dependencies/PureExpressionDependency.js +9 -10
  262. package/lib/dependencies/RequireContextDependency.js +2 -2
  263. package/lib/dependencies/RequireContextDependencyParserPlugin.js +2 -4
  264. package/lib/dependencies/RequireContextPlugin.js +8 -4
  265. package/lib/dependencies/RequireEnsureDependenciesBlock.js +2 -2
  266. package/lib/dependencies/RequireEnsureDependenciesBlockParserPlugin.js +5 -8
  267. package/lib/dependencies/RequireEnsureDependency.js +8 -7
  268. package/lib/dependencies/RequireEnsurePlugin.js +7 -3
  269. package/lib/dependencies/RequireHeaderDependency.js +51 -12
  270. package/lib/dependencies/RequireIncludeDependency.js +6 -6
  271. package/lib/dependencies/RequireIncludeDependencyParserPlugin.js +2 -3
  272. package/lib/dependencies/RequireIncludePlugin.js +7 -3
  273. package/lib/dependencies/RequireJsStuffPlugin.js +7 -3
  274. package/lib/dependencies/RequireResolveContextDependency.js +2 -2
  275. package/lib/dependencies/RequireResolveDependency.js +4 -4
  276. package/lib/dependencies/RequireResolveHeaderDependency.js +4 -4
  277. package/lib/dependencies/RuntimeRequirementsDependency.js +5 -6
  278. package/lib/dependencies/StaticExportsDependency.js +2 -2
  279. package/lib/dependencies/SystemPlugin.js +10 -6
  280. package/lib/dependencies/SystemRuntimeModule.js +10 -0
  281. package/lib/dependencies/TopLevelAwaitDependency.js +11 -7
  282. package/lib/dependencies/URLContextDependency.js +2 -2
  283. package/lib/dependencies/URLDependency.js +110 -64
  284. package/lib/dependencies/URLPlugin.js +7 -3
  285. package/lib/dependencies/UnsupportedDependency.js +4 -4
  286. package/lib/dependencies/WebAssemblyExportImportedDependency.js +3 -4
  287. package/lib/dependencies/WebAssemblyImportDependency.js +5 -5
  288. package/lib/dependencies/WebpackIsIncludedDependency.js +6 -6
  289. package/lib/dependencies/WorkerAndWorkletPlugin.js +46 -28
  290. package/lib/dependencies/WorkerDependency.js +28 -22
  291. package/lib/dependencies/WorkletDependency.js +15 -14
  292. package/lib/dependencies/getFunctionExpression.js +8 -4
  293. package/lib/dependencies/processExportInfo.js +5 -5
  294. package/lib/dll/DelegatedModule.js +34 -22
  295. package/lib/dll/DelegatedModuleFactoryPlugin.js +15 -7
  296. package/lib/dll/DelegatedPlugin.js +2 -2
  297. package/lib/dll/DllEntryPlugin.js +2 -2
  298. package/lib/dll/DllModule.js +22 -15
  299. package/lib/dll/DllModuleFactory.js +7 -3
  300. package/lib/dll/DllPlugin.js +7 -5
  301. package/lib/dll/DllReferencePlugin.js +10 -7
  302. package/lib/dll/LibManifestPlugin.js +5 -5
  303. package/lib/electron/ElectronTargetPlugin.js +53 -49
  304. package/lib/errors/AsyncChunkWaterfallWarning.js +36 -0
  305. package/lib/errors/AsyncDependencyToInitialChunkError.js +2 -2
  306. package/lib/errors/BroadContextsWarning.js +43 -0
  307. package/lib/errors/BuildCycleError.js +1 -1
  308. package/lib/errors/CacheEffectivenessWarning.js +55 -0
  309. package/lib/errors/ChunkRenderError.js +1 -1
  310. package/lib/errors/CircularDependenciesWarning.js +38 -0
  311. package/lib/errors/CodeGenerationError.js +1 -1
  312. package/lib/errors/CommentCompilationWarning.js +1 -1
  313. package/lib/errors/ConflictingResourceHintsWarning.js +35 -0
  314. package/lib/errors/DuplicateModulesWarning.js +45 -0
  315. package/lib/errors/DynamicExportsWarning.js +30 -0
  316. package/lib/errors/EmbeddedSourceMapsWarning.js +25 -0
  317. package/lib/errors/EntrypointOverlapWarning.js +45 -0
  318. package/lib/errors/EnvironmentNotSupportAsyncWarning.js +2 -2
  319. package/lib/errors/EvalUsageWarning.js +28 -0
  320. package/lib/errors/HookWebpackError.js +5 -5
  321. package/lib/errors/HotspotsWarning.js +57 -0
  322. package/lib/errors/IgnoreErrorModuleFactory.js +7 -3
  323. package/lib/errors/InlinedAssetsWarning.js +36 -0
  324. package/lib/errors/InvalidDependenciesModuleWarning.js +1 -1
  325. package/lib/errors/LargeModulesWarning.js +45 -0
  326. package/lib/errors/LegacyJavascriptWarning.js +48 -0
  327. package/lib/errors/MissingSideEffectsWarning.js +36 -0
  328. package/lib/errors/MixedExportsWarning.js +41 -0
  329. package/lib/errors/ModuleDependencyError.js +13 -16
  330. package/lib/errors/ModuleDependencyWarning.js +5 -15
  331. package/lib/errors/ModuleHashingError.js +1 -1
  332. package/lib/errors/ModuleNotFoundError.js +2 -2
  333. package/lib/errors/ModuleParseError.js +1 -2
  334. package/lib/errors/ModuleRestoreError.js +1 -1
  335. package/lib/errors/ModuleStoreError.js +1 -1
  336. package/lib/errors/NodeStuffInWebError.js +1 -1
  337. package/lib/errors/OsDependentRuleWarning.js +31 -0
  338. package/lib/errors/PureAnnotationsWarning.js +36 -0
  339. package/lib/errors/RedundantDynamicImportWarning.js +31 -0
  340. package/lib/errors/ScopeHoistingBailoutsWarning.js +41 -0
  341. package/lib/errors/SplitChunksCappedWarning.js +41 -0
  342. package/lib/errors/TinyChunksWarning.js +40 -0
  343. package/lib/errors/TopLevelThisWarning.js +34 -0
  344. package/lib/errors/UnsplitVendorsWarning.js +42 -0
  345. package/lib/errors/UnsupportedFeatureWarning.js +1 -1
  346. package/lib/errors/UnusedAliasesWarning.js +29 -0
  347. package/lib/errors/UnusedDefinesWarning.js +29 -0
  348. package/lib/errors/UnusedExternalsWarning.js +29 -0
  349. package/lib/errors/UnusedReexportsWarning.js +42 -0
  350. package/lib/errors/UnusedRuleWarning.js +29 -0
  351. package/lib/errors/WebpackError.js +9 -5
  352. package/lib/errors/deriveStackFromNestedError.js +90 -0
  353. package/lib/esm/ExportWebpackRequireRuntimeModule.js +2 -0
  354. package/lib/esm/ModuleChunkFormatPlugin.js +37 -19
  355. package/lib/esm/ModuleChunkLoadingPlugin.js +89 -51
  356. package/lib/esm/ModuleChunkLoadingRuntimeModule.js +155 -62
  357. package/lib/hmr/HotModuleReplacement.runtime.js +24 -5
  358. package/lib/hmr/HotModuleReplacementRuntimeModule.js +1 -1
  359. package/lib/hmr/LazyCompilationPlugin.js +45 -24
  360. package/lib/hmr/lazyCompilationBackend.js +9 -6
  361. package/lib/hmr/parserHooks.js +56 -0
  362. package/lib/html/HtmlGenerator.js +277 -77
  363. package/lib/html/HtmlModule.js +7 -3
  364. package/lib/html/HtmlModulesPlugin.js +282 -162
  365. package/lib/html/HtmlParser.js +31 -86
  366. package/lib/html/data.js +1928 -0
  367. package/lib/html/htmlMinify.js +288 -0
  368. package/lib/html/syntax.js +5557 -1155
  369. package/lib/ids/ChunkModuleIdRangePlugin.js +3 -3
  370. package/lib/ids/DeterministicChunkIdsPlugin.js +1 -1
  371. package/lib/ids/DeterministicModuleIdsPlugin.js +2 -2
  372. package/lib/ids/HashedModuleIdsPlugin.js +6 -2
  373. package/lib/ids/IdHelpers.js +7 -8
  374. package/lib/ids/NamedChunkIdsPlugin.js +1 -1
  375. package/lib/ids/NamedModuleIdsPlugin.js +1 -1
  376. package/lib/ids/NaturalChunkIdsPlugin.js +2 -2
  377. package/lib/ids/NaturalModuleIdsPlugin.js +1 -1
  378. package/lib/ids/OccurrenceChunkIdsPlugin.js +7 -3
  379. package/lib/ids/OccurrenceModuleIdsPlugin.js +7 -3
  380. package/lib/ids/SyncModuleIdsPlugin.js +4 -4
  381. package/lib/index.js +10 -0
  382. package/lib/javascript/ArrayPushCallbackChunkFormatPlugin.js +3 -3
  383. package/lib/javascript/BasicEvaluatedExpression.js +18 -14
  384. package/lib/javascript/ChunkFormatHelpers.js +6 -6
  385. package/lib/javascript/ChunkHelpers.js +1 -1
  386. package/lib/javascript/CommonJsChunkFormatPlugin.js +11 -5
  387. package/lib/javascript/EnableChunkLoadingPlugin.js +2 -2
  388. package/lib/javascript/JavascriptGenerator.js +65 -165
  389. package/lib/javascript/JavascriptModule.js +9 -3
  390. package/lib/javascript/JavascriptModulesPlugin.js +98 -113
  391. package/lib/javascript/JavascriptParser.js +242 -99
  392. package/lib/javascript/JavascriptParserHelpers.js +10 -7
  393. package/lib/javascript/ScopeAnalyzer.js +1094 -0
  394. package/lib/javascript/StartupHelpers.js +55 -9
  395. package/lib/javascript/syntax.js +2678 -232
  396. package/lib/json/JsonData.js +8 -4
  397. package/lib/json/JsonGenerator.js +38 -16
  398. package/lib/json/JsonModule.js +7 -3
  399. package/lib/json/JsonModulesPlugin.js +1 -1
  400. package/lib/json/JsonParser.js +5 -6
  401. package/lib/library/AbstractLibraryPlugin.js +20 -14
  402. package/lib/library/AmdLibraryPlugin.js +11 -7
  403. package/lib/library/AssignLibraryPlugin.js +19 -13
  404. package/lib/library/EnableLibraryPlugin.js +2 -2
  405. package/lib/library/ExportPropertyLibraryPlugin.js +15 -8
  406. package/lib/library/JsonpLibraryPlugin.js +11 -7
  407. package/lib/library/ModuleLibraryPlugin.js +256 -64
  408. package/lib/library/SystemLibraryPlugin.js +12 -8
  409. package/lib/library/UmdLibraryPlugin.js +62 -25
  410. package/lib/loaders/LoaderRunner.js +14 -1
  411. package/lib/loaders/loadLoader.js +8 -4
  412. package/lib/logging/createConsoleLogger.js +7 -4
  413. package/lib/node/CommonJsChunkLoadingPlugin.js +36 -22
  414. package/lib/node/NodeEnvironmentPlugin.js +17 -3
  415. package/lib/node/NodeSourcePlugin.js +1 -1
  416. package/lib/node/NodeTargetPlugin.js +4 -3
  417. package/lib/node/NodeTemplatePlugin.js +1 -1
  418. package/lib/node/NodeWatchFileSystem.js +70 -9
  419. package/lib/node/ReadFileChunkLoadingRuntimeModule.js +35 -38
  420. package/lib/node/ReadFileCompileAsyncWasmPlugin.js +72 -19
  421. package/lib/node/ReadFileCompileWasmPlugin.js +28 -16
  422. package/lib/node/RequireChunkLoadingRuntimeModule.js +35 -38
  423. package/lib/node/nodeConsole.js +7 -3
  424. package/lib/optimize/AggressiveMergingPlugin.js +2 -2
  425. package/lib/optimize/AggressiveSplittingPlugin.js +9 -6
  426. package/lib/optimize/ConcatenatedModule.js +985 -470
  427. package/lib/optimize/ConstExportsPlugin.js +11 -7
  428. package/lib/optimize/EnsureChunkConditionsPlugin.js +3 -3
  429. package/lib/optimize/FlagIncludedChunksPlugin.js +3 -4
  430. package/lib/optimize/InlineExports.js +9 -5
  431. package/lib/optimize/InnerGraph.js +28 -12
  432. package/lib/optimize/InnerGraphPlugin.js +23 -18
  433. package/lib/optimize/LimitChunkCountPlugin.js +7 -3
  434. package/lib/optimize/MangleExportsPlugin.js +7 -8
  435. package/lib/optimize/MergeDuplicateChunksPlugin.js +7 -3
  436. package/lib/optimize/MinChunkSizePlugin.js +7 -3
  437. package/lib/optimize/ModuleConcatenationPlugin.js +51 -35
  438. package/lib/optimize/RealContentHashPlugin.js +10 -6
  439. package/lib/optimize/RemoveEmptyChunksPlugin.js +2 -2
  440. package/lib/optimize/RemoveParentModulesPlugin.js +4 -4
  441. package/lib/optimize/RuntimeChunkPlugin.js +2 -2
  442. package/lib/optimize/SideEffectsFlagPlugin.js +262 -39
  443. package/lib/optimize/SplitChunksPlugin.js +86 -24
  444. package/lib/performance/AssetsOverSizeLimitWarning.js +10 -2
  445. package/lib/performance/AsyncChunkWaterfallsPlugin.js +136 -0
  446. package/lib/performance/BroadContextsPlugin.js +142 -0
  447. package/lib/performance/CacheEffectivenessPlugin.js +125 -0
  448. package/lib/performance/ConflictingResourceHintsPlugin.js +99 -0
  449. package/lib/performance/DuplicateModulesPlugin.js +93 -0
  450. package/lib/performance/DuplicatePackagesPlugin.js +119 -0
  451. package/lib/performance/DuplicatePackagesWarning.js +84 -0
  452. package/lib/performance/DynamicExportsPlugin.js +120 -0
  453. package/lib/performance/EmbeddedSourceMapsPlugin.js +71 -0
  454. package/lib/performance/EntrypointOverlapPlugin.js +122 -0
  455. package/lib/performance/EntrypointsOverSizeLimitWarning.js +1 -1
  456. package/lib/performance/EvalUsagePlugin.js +115 -0
  457. package/lib/performance/HotspotsPlugin.js +296 -0
  458. package/lib/performance/InlinedAssetsPlugin.js +99 -0
  459. package/lib/performance/LargeModulesPlugin.js +126 -0
  460. package/lib/performance/LegacyJavascriptPlugin.js +139 -0
  461. package/lib/performance/MissingSideEffectsPlugin.js +138 -0
  462. package/lib/performance/MixedExportsPlugin.js +136 -0
  463. package/lib/performance/OsDependentRuleWarningPlugin.js +178 -0
  464. package/lib/performance/PureAnnotationsPlugin.js +219 -0
  465. package/lib/performance/RedundantDynamicImportsPlugin.js +225 -0
  466. package/lib/performance/RuntimeInLargeChunkWarning.js +27 -0
  467. package/lib/performance/ScopeHoistingBailoutsPlugin.js +164 -0
  468. package/lib/performance/SizeLimitsPlugin.js +139 -7
  469. package/lib/performance/SplitChunksCappedPlugin.js +99 -0
  470. package/lib/performance/TinyChunksPlugin.js +128 -0
  471. package/lib/performance/TopLevelThisPlugin.js +208 -0
  472. package/lib/performance/UnsplitVendorsPlugin.js +112 -0
  473. package/lib/performance/UnusedAliasesPlugin.js +253 -0
  474. package/lib/performance/UnusedDefinesPlugin.js +87 -0
  475. package/lib/performance/UnusedExternalsPlugin.js +110 -0
  476. package/lib/performance/UnusedReexportsPlugin.js +159 -0
  477. package/lib/performance/UnusedRuleWarningPlugin.js +105 -0
  478. package/lib/performance/getModuleSize.js +22 -0
  479. package/lib/performance/getSourceModules.js +22 -0
  480. package/lib/performance/hasOnlyUnusedExports.js +40 -0
  481. package/lib/prefetch/ChunkPrefetchFunctionRuntimeModule.js +24 -10
  482. package/lib/prefetch/ChunkPrefetchPreloadPlugin.js +63 -46
  483. package/lib/prefetch/ChunkPrefetchStartupRuntimeModule.js +2 -3
  484. package/lib/prefetch/ChunkPrefetchTriggerRuntimeModule.js +2 -2
  485. package/lib/prefetch/ChunkPreloadTriggerRuntimeModule.js +2 -2
  486. package/lib/prefetch/ResourceHintPlugin.js +295 -78
  487. package/lib/prefetch/ResourceHintRuntimeModule.js +1 -21
  488. package/lib/prefetch/StartupAssetHintRuntimeModule.js +10 -133
  489. package/lib/prefetch/parseResourceHintOptions.js +31 -4
  490. package/lib/rules/BasicEffectRulePlugin.js +2 -2
  491. package/lib/rules/BasicMatcherRulePlugin.js +8 -4
  492. package/lib/rules/GlobMatcherRulePlugin.js +68 -0
  493. package/lib/rules/ObjectMatcherRulePlugin.js +12 -5
  494. package/lib/rules/RuleSetCompiler.js +146 -12
  495. package/lib/rules/UseEffectRulePlugin.js +18 -11
  496. package/lib/runtime/AsyncModuleGeneratorRuntimeModule.js +11 -1
  497. package/lib/runtime/AsyncModuleRuntimeModule.js +1 -1
  498. package/lib/runtime/AutoPublicPathRuntimeModule.js +15 -20
  499. package/lib/runtime/BaseUriRuntimeModule.js +33 -7
  500. package/lib/runtime/ChunkNameRuntimeModule.js +10 -0
  501. package/lib/runtime/CompatGetDefaultExportRuntimeModule.js +11 -1
  502. package/lib/runtime/CompatRuntimeModule.js +5 -3
  503. package/lib/runtime/ConcatenationWrapRuntimeModule.js +90 -0
  504. package/lib/runtime/ConstructRequireRuntimeModule.js +52 -0
  505. package/lib/runtime/CreateFakeNamespaceObjectRuntimeModule.js +8 -6
  506. package/lib/runtime/CreateScriptRuntimeModule.js +11 -1
  507. package/lib/runtime/CreateScriptUrlRuntimeModule.js +11 -1
  508. package/lib/runtime/DefinePropertyGettersRuntimeModule.js +56 -38
  509. package/lib/runtime/EnsureChunkRuntimeModule.js +18 -2
  510. package/lib/runtime/GetChunkFilenameRuntimeModule.js +62 -37
  511. package/lib/runtime/GetFullHashRuntimeModule.js +12 -2
  512. package/lib/runtime/GetMainFilenameRuntimeModule.js +12 -2
  513. package/lib/runtime/GetTrustedTypesPolicyRuntimeModule.js +2 -2
  514. package/lib/runtime/GetWorkletBootstrapRuntimeModule.js +16 -3
  515. package/lib/runtime/GlobalRuntimeModule.js +18 -0
  516. package/lib/runtime/HasOwnPropertyRuntimeModule.js +12 -2
  517. package/lib/runtime/LoadScriptRuntimeModule.js +2 -2
  518. package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +23 -6
  519. package/lib/runtime/MakeNamespaceObjectRuntimeModule.js +22 -6
  520. package/lib/runtime/NonceRuntimeModule.js +10 -0
  521. package/lib/runtime/OnChunksLoadedRuntimeModule.js +5 -3
  522. package/lib/runtime/PublicPathRuntimeModule.js +12 -2
  523. package/lib/runtime/RelativeUrlRuntimeModule.js +11 -1
  524. package/lib/runtime/RuntimeIdRuntimeModule.js +12 -2
  525. package/lib/runtime/SetAnonymousDefaultNameRuntimeModule.js +11 -1
  526. package/lib/runtime/StartupChunkDependenciesPlugin.js +18 -9
  527. package/lib/runtime/StartupChunkDependenciesRuntimeModule.js +3 -3
  528. package/lib/runtime/StartupEntrypointRuntimeModule.js +21 -4
  529. package/lib/runtime/SystemContextRuntimeModule.js +10 -0
  530. package/lib/runtime/ToBinaryRuntimeModule.js +1 -1
  531. package/lib/runtime/WorkerRuntimeModule.js +11 -1
  532. package/lib/runtime/baseUri.js +63 -0
  533. package/lib/schemes/DataUriPlugin.js +1 -1
  534. package/lib/schemes/FileUriPlugin.js +1 -1
  535. package/lib/schemes/HttpUriPlugin.js +24 -15
  536. package/lib/schemes/VirtualUrlPlugin.js +13 -7
  537. package/lib/serialization/AggregateErrorSerializer.js +1 -1
  538. package/lib/serialization/BinaryMiddleware.js +4 -4
  539. package/lib/serialization/ErrorObjectSerializer.js +1 -1
  540. package/lib/serialization/FileMiddleware.js +7 -7
  541. package/lib/serialization/ObjectMiddleware.js +139 -114
  542. package/lib/serialization/PlainObjectSerializer.js +19 -16
  543. package/lib/sharing/ConsumeSharedModule.js +30 -21
  544. package/lib/sharing/ConsumeSharedPlugin.js +18 -10
  545. package/lib/sharing/ConsumeSharedRuntimeModule.js +6 -9
  546. package/lib/sharing/ProvideSharedModule.js +25 -16
  547. package/lib/sharing/ProvideSharedModuleFactory.js +7 -3
  548. package/lib/sharing/ProvideSharedPlugin.js +8 -4
  549. package/lib/sharing/SharePlugin.js +17 -5
  550. package/lib/sharing/ShareRuntimeModule.js +4 -4
  551. package/lib/sharing/resolveMatchedConfigs.js +9 -6
  552. package/lib/sharing/utils.js +1 -3
  553. package/lib/stats/DefaultStatsFactoryPlugin.js +50 -29
  554. package/lib/stats/DefaultStatsPresetPlugin.js +17 -8
  555. package/lib/stats/DefaultStatsPrinterPlugin.js +36 -26
  556. package/lib/stats/StatsFactory.js +25 -26
  557. package/lib/stats/StatsPrinter.js +16 -12
  558. package/lib/typescript/TypeScriptPlugin.js +12 -14
  559. package/lib/url/URLParserPlugin.js +26 -13
  560. package/lib/util/AsyncQueue.js +4 -3
  561. package/lib/util/Hash.js +5 -1
  562. package/lib/util/LazySet.js +35 -22
  563. package/lib/util/LocConverter.js +36 -13
  564. package/lib/util/SourceProcessor.js +1050 -24
  565. package/lib/util/StringXor.js +1 -1
  566. package/lib/util/chainedImports.js +9 -5
  567. package/lib/util/cleverMerge.js +1 -1
  568. package/lib/util/comparators.js +45 -14
  569. package/lib/util/concatenate.js +203 -77
  570. package/lib/util/conventions.js +5 -1
  571. package/lib/util/createHash.js +2 -2
  572. package/lib/util/createHooksRegistry.js +8 -10
  573. package/lib/util/dataURL.js +225 -1
  574. package/lib/util/extractSourceMap.js +4 -3
  575. package/lib/util/findCaseMismatch.js +139 -0
  576. package/lib/util/formatLocation.js +1 -2
  577. package/lib/util/fs.js +22 -5
  578. package/lib/util/globUtils.js +298 -24
  579. package/lib/util/hash/BatchedHash.js +5 -1
  580. package/lib/util/hash/BulkUpdateHash.js +5 -1
  581. package/lib/util/hash/DebugHash.js +5 -1
  582. package/lib/util/hash/hash-digest.js +6 -2
  583. package/lib/util/identifier.js +4 -0
  584. package/lib/util/implicitTypeLoaderFallback.js +1 -1
  585. package/lib/util/internalSerializables.js +6 -0
  586. package/lib/util/lazyModule.js +56 -0
  587. package/lib/util/makeSerializable.js +7 -3
  588. package/lib/util/matchAlias.js +25 -0
  589. package/lib/util/mimeTypes.js +11 -5
  590. package/lib/util/nonNumericOnlyHash.js +4 -3
  591. package/lib/util/parseJson.js +5 -3
  592. package/lib/util/preloadModuleType.js +32 -0
  593. package/lib/util/registerExternalSerializer.js +7 -5
  594. package/lib/util/runtime.js +2 -2
  595. package/lib/util/semver.js +1 -1
  596. package/lib/util/serialization.js +28 -28
  597. package/lib/util/source.js +2 -2
  598. package/lib/util/traverseDestructuringAssignmentProperties.js +6 -2
  599. package/lib/wasm/EnableWasmLoadingPlugin.js +10 -8
  600. package/lib/wasm/wasmModuleFilename.js +54 -0
  601. package/lib/wasm-async/AsyncWasmCompileRuntimeModule.js +41 -21
  602. package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +43 -21
  603. package/lib/wasm-async/AsyncWasmModule.js +3 -3
  604. package/lib/wasm-async/AsyncWebAssemblyGenerator.js +4 -5
  605. package/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js +57 -17
  606. package/lib/wasm-async/AsyncWebAssemblyModulesPlugin.js +34 -18
  607. package/lib/wasm-async/AsyncWebAssemblyParser.js +9 -8
  608. package/lib/wasm-async/UniversalCompileAsyncWasmPlugin.js +34 -8
  609. package/lib/wasm-sync/SyncWasmModule.js +2 -2
  610. package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +18 -13
  611. package/lib/wasm-sync/WasmFinalizeExportsPlugin.js +4 -5
  612. package/lib/wasm-sync/WebAssemblyGenerator.js +18 -17
  613. package/lib/wasm-sync/WebAssemblyInInitialChunkError.js +4 -4
  614. package/lib/wasm-sync/WebAssemblyJavascriptGenerator.js +7 -7
  615. package/lib/wasm-sync/WebAssemblyModulesPlugin.js +24 -11
  616. package/lib/wasm-sync/WebAssemblyParser.js +4 -6
  617. package/lib/wasm-sync/WebAssemblyUtils.js +2 -2
  618. package/lib/web/FetchCompileAsyncWasmPlugin.js +101 -19
  619. package/lib/web/FetchCompileWasmPlugin.js +46 -16
  620. package/lib/web/JsonpChunkLoadingPlugin.js +47 -23
  621. package/lib/web/JsonpChunkLoadingRuntimeModule.js +50 -20
  622. package/lib/web/JsonpTemplatePlugin.js +2 -2
  623. package/lib/webpack.js +22 -11
  624. package/lib/webworker/ImportScriptsChunkLoadingPlugin.js +60 -26
  625. package/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js +30 -32
  626. package/lib/webworker/WebWorkerTemplatePlugin.js +1 -1
  627. package/module.d.ts +1 -0
  628. package/package.json +32 -25
  629. package/schemas/WebpackOptions.check.js +1 -1
  630. package/schemas/WebpackOptions.json +670 -36
  631. package/schemas/plugins/HtmlParserOptions.check.js +1 -1
  632. package/schemas/plugins/container/ContainerPlugin.check.js +1 -1
  633. package/schemas/plugins/container/ContainerPlugin.json +10 -0
  634. package/schemas/plugins/container/ModuleFederationPlugin.check.js +1 -1
  635. package/schemas/plugins/container/ModuleFederationPlugin.json +10 -0
  636. package/schemas/plugins/css/CssAutoOrModuleParserOptions.check.js +1 -1
  637. package/schemas/plugins/css/CssModuleParserOptions.check.js +1 -1
  638. package/schemas/plugins/css/CssParserOptions.check.js +1 -1
  639. package/types.d.ts +3144 -454
  640. package/lib/runtime/CommonJsWrapRuntimeModule.js +0 -37
@@ -4,6 +4,101 @@
4
4
 
5
5
  "use strict";
6
6
 
7
+ // Stands in the output for text only an asynchronous caller can supply, until
8
+ // {@link PrintContext.substitute} puts the answer in its place. A NUL delimits
9
+ // it because both the CSS and the HTML preprocessor turn one in the input into
10
+ // U+FFFD, so printed output never holds one of its own account.
11
+ const DEFERRED_MARKER = "\u0000";
12
+
13
+ // The infix this print marks its writes with, chosen so that `NUL infix` occurs
14
+ // nowhere in the input — a NUL the source carried then spells no write of ours.
15
+ let deferredInfix = "0:";
16
+
17
+ /**
18
+ * The text to print in place of a deferred write.
19
+ * @param {number} id the write's index among this print's deferred writes
20
+ * @returns {string} the marker to emit
21
+ */
22
+ const deferredWrite = (id) =>
23
+ `${DEFERRED_MARKER}${deferredInfix}${id}${DEFERRED_MARKER}`;
24
+
25
+ /**
26
+ * An infix no NUL run in `input` already carries, so only this print can have
27
+ * written one. An RCDATA element (`<textarea>`, `<title>`) and an attribute
28
+ * value both keep the NUL they were written with, so the source can hold one.
29
+ * @param {string} input the source about to be printed
30
+ * @returns {string} the infix to mark this print's writes with
31
+ */
32
+ const chooseDeferredInfix = (input) => {
33
+ let n = 0;
34
+
35
+ while (input.includes(`${DEFERRED_MARKER}${n}:`)) n++;
36
+
37
+ return `${n}:`;
38
+ };
39
+
40
+ const DEFERRED_ID_RE = /^\d+$/;
41
+
42
+ /**
43
+ * Read the deferred write standing at `start`, if one does.
44
+ * @param {string} text the text to read
45
+ * @param {number} start offset of the marker's opening NUL
46
+ * @param {(id: number) => string | undefined} resolve the write's final text, or undefined where it answers for no such write
47
+ * @param {string} infix what this print marked its writes with
48
+ * @returns {{ end: number, replacement: string } | null} where the write ends and what stands in for it, or null where none does
49
+ */
50
+ const readDeferredWrite = (text, start, resolve, infix) => {
51
+ const end = text.indexOf(DEFERRED_MARKER, start + 1);
52
+
53
+ if (end === -1) return null;
54
+
55
+ const body = text.slice(start + 1, end);
56
+
57
+ if (!body.startsWith(infix)) return null;
58
+
59
+ const id = body.slice(infix.length);
60
+
61
+ if (!DEFERRED_ID_RE.test(id)) return null;
62
+
63
+ const replacement = resolve(Number(id));
64
+
65
+ return replacement === undefined ? null : { end, replacement };
66
+ };
67
+
68
+ /**
69
+ * Stand the answers in for every write in one answer: a body offered whole
70
+ * holds the markers of the bodies inside it.
71
+ * @param {string} text one answer
72
+ * @param {(id: number) => string | undefined} resolve the write's final text
73
+ * @param {string} infix what this print marked its writes with
74
+ * @returns {string} the answer with every write inside it resolved
75
+ */
76
+ const expandDeferredWrites = (text, resolve, infix) => {
77
+ let at = text.indexOf(DEFERRED_MARKER);
78
+
79
+ if (at === -1) return text;
80
+
81
+ let out = "";
82
+ let from = 0;
83
+
84
+ while (at !== -1) {
85
+ const write = readDeferredWrite(text, at, resolve, infix);
86
+
87
+ if (write === null) {
88
+ at = text.indexOf(DEFERRED_MARKER, at + 1);
89
+ continue;
90
+ }
91
+
92
+ out +=
93
+ text.slice(from, at) +
94
+ expandDeferredWrites(write.replacement, resolve, infix);
95
+ from = write.end + 1;
96
+ at = text.indexOf(DEFERRED_MARKER, from);
97
+ }
98
+
99
+ return out + text.slice(from);
100
+ };
101
+
7
102
  /**
8
103
  * Babel-style visitor map keyed by a numeric node-type discriminator; a bucket
9
104
  * is a function (enter-only) or `{ enter?, exit? }`.
@@ -35,45 +130,818 @@
35
130
  * @typedef {CompiledVisitorBucket<TPath>[]} CompiledVisitorMap a sparse array indexed by node type
36
131
  */
37
132
  /**
38
- * A language grammar: parse `input` and fire the compiled visitors in source
39
- * order (the grammar owns tokenizing, parsing, walking — and the `path`
40
- * object each visitor receives).
133
+ * What every language's print options carry, read by the node printer via
134
+ * `writer.options`. Only `mode` is here: what else a printer may be told is the
135
+ * language's own business, and a language names it by instantiating
136
+ * {@link PrintContext} with its own type — nothing CSS reads belongs in a
137
+ * typedef HTML also depends on.
138
+ * @typedef {{ mode: "minify" | "beautify" }} PrintOptions
139
+ */
140
+ /**
141
+ * One write the print left a marker for, collected into the `deferEmbeddedSource`
142
+ * print option by whichever grammar offered it — the other half of
143
+ * {@link deferredWrite}. `source` is the text offered and `build` spells what is
144
+ * printed around the answer, an untapped run's spelling where there is none. A
145
+ * grammar carries whatever else describes the offer (`type`, `hostType`, `as`,
146
+ * …) on the same object.
147
+ * @typedef {{ source: string, build: (answer: string | undefined) => string }} DeferredWrite
148
+ */
149
+ /**
150
+ * A version-3 source map. Written structurally (with the `3` literal) so it
151
+ * satisfies both `webpack-sources` and the minimizer plugin's map types without
152
+ * depending on either.
153
+ * @typedef {{ version: 3, file: string, sources: string[], sourcesContent?: string[], names: string[], mappings: string }} SourceMap
154
+ */
155
+ /**
156
+ * The `process` source-map option: turns map collection on and names the input
157
+ * (`sources[0]` / optional `sourcesContent[0]`). Present => `process` returns
158
+ * `{ code, map }` instead of a bare string.
159
+ * @typedef {{ source: string, content?: string }} SourceMapOptions
160
+ */
161
+
162
+ /**
163
+ * @param {SourceMapOptions} options the input's name / content
164
+ * @param {string} mappings the VLQ `mappings` field
165
+ * @returns {SourceMap} a version-3 source map
166
+ */
167
+ const _makeMap = (options, mappings) => ({
168
+ version: 3,
169
+ file: options.source,
170
+ sources: [options.source],
171
+ sourcesContent: options.content === undefined ? undefined : [options.content],
172
+ names: [],
173
+ mappings
174
+ });
175
+
176
+ // How much output accumulates before it is cut off and forced flat (see
177
+ // `PrintContext._emit`). Large enough that the flattening copy is amortized away,
178
+ // small enough that the un-flattened fragments behind it stay bounded.
179
+ const FLATTEN_BLOCK = 64 * 1024;
180
+
181
+ // Base64 VLQ, the source-map `mappings` encoding. Hand-rolled so producing a map
182
+ // pulls in no dependency (`source-map` is not a webpack dep).
183
+ const _B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
184
+
185
+ /**
186
+ * @param {number} n a signed integer
187
+ * @returns {string} its Base64 VLQ encoding
188
+ */
189
+ const _vlq = (n) => {
190
+ let v = n < 0 ? (-n << 1) | 1 : n << 1;
191
+ let out = "";
192
+ do {
193
+ let digit = v & 31;
194
+ v >>>= 5;
195
+ if (v > 0) digit |= 32;
196
+ out += _B64[digit];
197
+ } while (v > 0);
198
+ return out;
199
+ };
200
+ /**
201
+ * A language node printer, fired for one node once all its visitors have run and
202
+ * its children are printed. It takes the same `path` a visitor gets plus the
203
+ * print context as its `writer`; it switches on `path.type()` and **returns** the
204
+ * node's serialized text, reading its children's text from `writer.get` — knowing
205
+ * nothing of the walk. Returning (rather than writing to a buffer) is what lets a
206
+ * parent compose / transform its text from its finished children.
207
+ * @template TPath
208
+ * @template TNode
209
+ * @template [TPrintOptions=object]
210
+ * @typedef {(path: TPath, writer: PrintContext<TPath, TNode, TPrintOptions>) => string} NodePrinter
211
+ */
212
+ /**
213
+ * A language grammar: parse `input` once and fire the compiled visitors in
214
+ * source order. When `writer` is given it is also printing — after each node's
215
+ * visitors have run and its children are printed, the grammar fires the node
216
+ * printer into `writer`; a single parse with no re-tokenizing.
41
217
  * @template TPath
218
+ * @template TNode
42
219
  * @template TProcessOptions
43
- * @typedef {(input: string, visitors: CompiledVisitorMap<TPath>, options: TProcessOptions) => void} Grammar
220
+ * @template [TPrintOptions=object]
221
+ * @typedef {(input: string, visitors: CompiledVisitorMap<TPath>, writer: PrintContext<TPath, TNode, TPrintOptions> | undefined, options: TProcessOptions) => void} Grammar
44
222
  */
45
223
 
224
+ /**
225
+ * The per-node output store handed to a language node printer as its `writer`. It
226
+ * carries the print `options` (today just `mode`) and one map: a finished node ->
227
+ * its printed text. A printer *returns* its text (`printNode` stores it) and reads
228
+ * a child's with `get`, so a parent composes its own text from its children's —
229
+ * the map is what makes that composition (and the CSS value transforms built on
230
+ * it) possible. `take` flushes a finished top-level node into the output and drops
231
+ * the map, so a streaming grammar never holds more than one top-level subtree.
232
+ * @template TPath
233
+ * @template TNode
234
+ * @template [TPrintOptions=object]
235
+ */
236
+ class PrintContext {
237
+ /**
238
+ * @param {PrintOptions & TPrintOptions} options the print options
239
+ * @param {NodePrinter<TPath, TNode, TPrintOptions>} printer the node printer
240
+ */
241
+ constructor(options, printer) {
242
+ /** @type {PrintOptions & TPrintOptions} */
243
+ this.options = options;
244
+ /** @type {NodePrinter<TPath, TNode, TPrintOptions>} */
245
+ this._printer = printer;
246
+ // Printed text by node handle, in two columns rather than one `Map`: the
247
+ // handles are dense integers, and a stylesheet prints ~300k nodes through
248
+ // a store that never holds more than a few dozen of them at once.
249
+ /** @type {string[]} each finished node's printed text */
250
+ this._storeText = [];
251
+ /** @type {Int32Array} the epoch each slot was written in */
252
+ this._storeGen = new Int32Array(0);
253
+ /** @type {number} current epoch; a slot from an older one reads as absent */
254
+ this._gen = 1;
255
+ // Output accumulates into `_tail`, a plain string append, so printing that
256
+ // never takes anything back costs exactly what appending to one string
257
+ // costs. A piece is cut off into `_chunks` only for text that may still be
258
+ // taken back ({@link emitRetractable}) — that is what lets a printer emit
259
+ // before it knows a later sibling overrides it, without every other emit
260
+ // paying for the ability. The output is `_chunks` joined, then `_tail`.
261
+ /** @type {string[]} pieces already cut off, in output order */
262
+ this._chunks = [];
263
+ /** @type {string} output after the last cut piece */
264
+ this._tail = "";
265
+ /** @type {number} characters in `_tail`, so its length is not read off a rope */
266
+ this._tailLength = 0;
267
+ /** @type {number} scratch for the flattening read in {@link _cutTail} */
268
+ this._flattened = 0;
269
+ /** @type {[number, number, number, number][]} `[chunkIndex, offsetInChunk, srcLine, srcCol]`, output-ordered; a `srcLine` of -1 is one {@link retract} took back with its piece */
270
+ this._mappings = [];
271
+ /** @type {Map<number, number> | null} a retractable piece -> the mapping anchored to it, so taking the piece back takes its mapping too */
272
+ this._retractableMappings = null;
273
+ // A map is built only for a caller that named the input, and that is known
274
+ // before printing — so a print nobody asks a map of collects none.
275
+ /** @type {boolean} whether {@link sourceMap} can still be asked for one */
276
+ this.mapWanted =
277
+ /** @type {{ source?: string }} */ (options).source !== undefined;
278
+ /** @type {[number, string][]} source-anchored literals to keep (comments), source-ordered */
279
+ this._inserts = [];
280
+ /** @type {number} next `_inserts` entry not yet flushed */
281
+ this._insertIdx = 0;
282
+ // Openers of the nodes being printed in pieces, innermost last, held back
283
+ // until one of them turns out to have content: a node whose children all
284
+ // print to nothing can then still be dropped whole, which is the one thing
285
+ // emitting an opener eagerly would give up.
286
+ /** @type {string[]} openers not yet emitted, outermost first */
287
+ this._pending = [];
288
+ /** @type {[number | undefined, number | undefined, number | undefined] | null} anchor for the first pending opener */
289
+ this._pendingAnchor = null;
290
+ }
291
+
292
+ /**
293
+ * Hold `text` back as the opener of a node being printed in pieces. Nothing
294
+ * reaches the output until {@link flushPending}, so {@link dropPending} can
295
+ * still take it back if the node turns out to be empty.
296
+ * @param {string} text the node's opener
297
+ * @returns {number} the opener's depth, for {@link isPending}
298
+ */
299
+ pushPending(text) {
300
+ return this._pending.push(text) - 1;
301
+ }
302
+
303
+ /**
304
+ * Rewrite a held-back opener — an opener whose text depends on what turns out
305
+ * to follow it can only be settled once something does.
306
+ * @param {number} depth the opener's depth, from {@link pushPending}
307
+ * @param {string} text its opener
308
+ */
309
+ setPending(depth, text) {
310
+ this._pending[depth] = text;
311
+ }
312
+
313
+ /**
314
+ * Emit every held-back opener, outermost first — something inside the
315
+ * innermost one has content, so all of them do.
316
+ * @returns {void}
317
+ */
318
+ flushPending() {
319
+ const pending = this._pending;
320
+ if (pending.length === 0) return;
321
+ const anchor = this._pendingAnchor;
322
+ if (anchor !== null) {
323
+ this._pendingAnchor = null;
324
+ this.anchor(anchor[0], anchor[1], anchor[2]);
325
+ }
326
+ for (let i = 0; i < pending.length; i++) this._emit(pending[i]);
327
+ pending.length = 0;
328
+ }
329
+
330
+ /**
331
+ * Anchor the outermost held-back opener, applied when it is flushed. Openers
332
+ * are flushed together, so only the outermost carries one.
333
+ * @param {number=} srcOffset the node's source offset (kept-comment flush boundary)
334
+ * @param {number=} srcLine 0-based source line of the node's start
335
+ * @param {number=} srcCol 0-based source column of the node's start
336
+ */
337
+ anchorPending(srcOffset, srcLine, srcCol) {
338
+ this._pendingAnchor = [srcOffset, srcLine, srcCol];
339
+ }
340
+
341
+ /**
342
+ * @param {number} depth an opener's depth, from {@link pushPending}
343
+ * @returns {boolean} whether it is still held back (nothing inside it printed)
344
+ */
345
+ isPending(depth) {
346
+ return this._pending.length > depth;
347
+ }
348
+
349
+ /**
350
+ * Drop the innermost held-back opener — its node printed to nothing.
351
+ * @returns {void}
352
+ */
353
+ dropPending() {
354
+ this._pending.pop();
355
+ const anchor = this._pendingAnchor;
356
+ if (this._pending.length !== 0 || anchor === null) return;
357
+ // The node printed to nothing, but it was still a node here: {@link take}
358
+ // anchors before it can know the text is empty, and the map has to read the
359
+ // same either way. The kept comments before it are due for the same reason.
360
+ this._pendingAnchor = null;
361
+ this.anchor(anchor[0], anchor[1], anchor[2]);
362
+ }
363
+
364
+ /**
365
+ * Close off what has been emitted so far and return the index the next piece
366
+ * will take. Cutting is the point: a caller bounding a later edit by this
367
+ * (see {@link dropTrailing}) must not be able to reach output from before it,
368
+ * which a mark taken while the tail was still open would sit in the middle of.
369
+ * @returns {number} the index the next emitted piece will get
370
+ */
371
+ markCut() {
372
+ this._cutTail();
373
+ return this._chunks.length;
374
+ }
375
+
376
+ /**
377
+ * Append a piece of a node that is being printed in pieces. Nothing takes it
378
+ * back, so it only extends the output.
379
+ * @param {string} text output text
380
+ */
381
+ emitStreamed(text) {
382
+ this._emit(text);
383
+ }
384
+
385
+ /**
386
+ * Widen both columns to hold `need` handles, keeping what they already hold.
387
+ * @param {number} need required capacity
388
+ */
389
+ _growStore(need) {
390
+ // From empty: a context that prints one inline `style=""` must not pay for
391
+ // a stylesheet's worth of columns.
392
+ const size = Math.max(need, this._storeText.length * 2, 16);
393
+ // Appended, which keeps the column packed for the read every composed child
394
+ // makes, and carries what it already holds across in the same pass.
395
+ const held = this._storeText;
396
+ const text = [];
397
+ for (let i = 0; i < held.length; i++) text.push(held[i]);
398
+ for (let i = held.length; i < size; i++) text.push("");
399
+ const gen = new Int32Array(size);
400
+ gen.set(this._storeGen);
401
+ this._storeText = text;
402
+ this._storeGen = gen;
403
+ }
404
+
405
+ /**
406
+ * Forget every node's printed text. A node printed in pieces does this once
407
+ * each child is emitted, so the store never holds more than one of them —
408
+ * which is also what keeps a recycled node id from reading as an earlier
409
+ * node's text.
410
+ */
411
+ dropStore() {
412
+ // Bumping the epoch invalidates every slot at once, so this stays O(1) —
413
+ // it runs per node, and clearing a column by length would not.
414
+ this._gen++;
415
+ }
416
+
417
+ /**
418
+ * Drop trailing `charCode`s from the end of the output at or after `from` —
419
+ * the separator the piece before a terminator no longer needs. Walks back over
420
+ * pieces emptied by {@link retract}, so it sees what the output reads as.
421
+ * @param {number} from earliest piece index this may touch
422
+ * @param {number} charCode the character to drop
423
+ */
424
+ dropTrailing(from, charCode) {
425
+ const chunks = this._chunks;
426
+ for (let i = chunks.length; i >= from; i--) {
427
+ let text = i === chunks.length ? this._tail : chunks[i];
428
+ if (text.length === 0) continue;
429
+ while (
430
+ text.length !== 0 &&
431
+ text.charCodeAt(text.length - 1) === charCode
432
+ ) {
433
+ text = text.slice(0, -1);
434
+ }
435
+ if (i === chunks.length) {
436
+ this._tail = text;
437
+ this._tailLength = text.length;
438
+ } else {
439
+ chunks[i] = text;
440
+ }
441
+ if (text.length !== 0) return;
442
+ }
443
+ }
444
+
445
+ /**
446
+ * Run the node printer for `node` and store what it returns (the grammar calls
447
+ * this once the node's visitors and children are done). `path` is on `node`.
448
+ * @param {TNode} node the finished node
449
+ * @param {TPath} path the language accessor, positioned on `node`
450
+ */
451
+ printNode(node, path) {
452
+ const text = this._printer(path, this);
453
+ const n = /** @type {EXPECTED_ANY} */ (node);
454
+ if (n >= this._storeText.length) this._growStore(n + 1);
455
+ this._storeText[n] = text;
456
+ this._storeGen[n] = this._gen;
457
+ }
458
+
459
+ /**
460
+ * Print one node and hand its text straight back — for a node inside one being
461
+ * printed in pieces, whose text is emitted as it is printed, so the store
462
+ * would only ever be written and read once.
463
+ * @param {TPath} path path positioned on the node
464
+ * @returns {string} its printed text
465
+ */
466
+ printPiece(path) {
467
+ return this._printer(path, this);
468
+ }
469
+
470
+ /**
471
+ * @param {TNode} node a child node whose printer already ran
472
+ * @returns {string} its printed text
473
+ */
474
+ get(node) {
475
+ const n = /** @type {EXPECTED_ANY} */ (node);
476
+ return /** @type {string} */ (
477
+ this._storeGen[n] === this._gen ? this._storeText[n] : undefined
478
+ );
479
+ }
480
+
481
+ /**
482
+ * Append `text` to the output. Where in the output that lands is worked out
483
+ * only if a source map is asked for (see {@link sourceMap}), so printing
484
+ * without one never walks the text looking for newlines.
485
+ * @param {string} text output text
486
+ */
487
+ _emit(text) {
488
+ this._tail += text;
489
+ this._tailLength += text.length;
490
+ // A printer returns its text as a rope of its children's pieces, and
491
+ // appending a rope onto a rope keeps every fragment of every node reachable
492
+ // until the output is finally flattened — on a stylesheet of many top-level
493
+ // rules, a second copy of the whole output. So cut the tail off once it has
494
+ // grown past a block and force that block flat, which drops every fragment
495
+ // behind it. Per block rather than per piece: the flattening copy is one
496
+ // the result would have paid for anyway, but paying it per piece means an
497
+ // allocation for each, and the pieces are small.
498
+ if (this._tailLength >= FLATTEN_BLOCK) this._cutTail();
499
+ }
500
+
501
+ /**
502
+ * Move the accumulated tail into the finished pieces, flattened.
503
+ */
504
+ _cutTail() {
505
+ // A run of retractable pieces cuts after each; an empty piece would only pad
506
+ // the output, and an anchor into an empty tail already points past it.
507
+ if (this._tailLength === 0) return;
508
+ // Reading a character is what forces it flat; the value is not wanted, and
509
+ // it is kept only so the read cannot be optimized away.
510
+ this._flattened = this._tail.charCodeAt(0);
511
+ this._chunks.push(this._tail);
512
+ this._tail = "";
513
+ this._tailLength = 0;
514
+ }
515
+
516
+ /**
517
+ * Append `text` as a piece of its own, so {@link retract} can still take it
518
+ * back once a later sibling turns out to override it. Cuts the accumulating
519
+ * tail off in front of it, so it is for the text that may actually be taken
520
+ * back and not for output at large.
521
+ * @param {string} text output text
522
+ * @returns {number} the piece's index, for {@link retract}
523
+ */
524
+ emitRetractable(text) {
525
+ this._cutTail();
526
+ return this._chunks.push(text) - 1;
527
+ }
528
+
529
+ /**
530
+ * Take back an already-emitted piece — the printer has since found that a
531
+ * later one overrides it. Pieces after it keep their place. A piece emitted by
532
+ * {@link takeRetractable} takes the mapping anchored to it back as well; any
533
+ * other anchor into the piece would be left pointing at what follows it, so
534
+ * this must not be used on one (see {@link take}).
535
+ * @param {number} index the piece's index, from {@link emitRetractable}
536
+ */
537
+ retract(index) {
538
+ this._chunks[index] = "";
539
+ if (this._retractableMappings === null) return;
540
+ const mapping = this._retractableMappings.get(index);
541
+ if (mapping !== undefined) this._mappings[mapping][2] = -1;
542
+ }
543
+
544
+ /**
545
+ * Fold `text` into an already-emitted piece, in front of the character it ends
546
+ * with — a later sibling whose body belongs inside that piece, as a repeated
547
+ * named `@layer` block's does. Mappings are piece-relative and this only grows
548
+ * the piece past everything already anchored in it, so they keep their
549
+ * positions; the folded text carries none of its own.
550
+ * @param {number} index the piece's index, from {@link emitRetractable}
551
+ * @param {string} text what to fold in, its own closer included
552
+ */
553
+ foldIntoRetractable(index, text) {
554
+ const piece = this._chunks[index];
555
+ this._chunks[index] = `${piece.slice(0, -1)}${text}`;
556
+ }
557
+
558
+ /**
559
+ * Write an already-emitted piece again, shorter — a rule inside it a later
560
+ * copy makes dead. Mappings anchored in the piece keep the offsets they were
561
+ * given, so one inside what was cut names what now follows it.
562
+ * @param {number} index the piece's index, from {@link emitRetractable}
563
+ * @param {string} text what the piece says now
564
+ */
565
+ rewriteRetractable(index, text) {
566
+ this._chunks[index] = text;
567
+ }
568
+
569
+ /**
570
+ * {@link take} for a top-level node a later sibling may still make dead — the
571
+ * unprefixed twin of a vendor-prefixed rule, which can stand anywhere after
572
+ * it. The node is emitted as a piece of its own, with its mapping recorded
573
+ * against that piece, so {@link retract} takes both back.
574
+ * @param {TNode} node the top-level node
575
+ * @param {number=} srcOffset the node's source offset (kept-comment flush boundary)
576
+ * @param {number=} srcLine 0-based source line of the node's start
577
+ * @param {number=} srcCol 0-based source column of the node's start
578
+ * @param {string=} text what to emit instead of the node's own printed text
579
+ * @returns {number} the piece's index, for {@link retract}
580
+ */
581
+ takeRetractable(node, srcOffset, srcLine, srcCol, text) {
582
+ const before = this._mappings.length;
583
+ this.anchor(srcOffset, srcLine, srcCol);
584
+ const mapping = this._mappings.length > before ? before : -1;
585
+ const at = this.emitRetractable(text === undefined ? this.get(node) : text);
586
+ this._gen++;
587
+ if (mapping !== -1) {
588
+ if (this._retractableMappings === null) {
589
+ this._retractableMappings = new Map();
590
+ }
591
+ this._retractableMappings.set(at, mapping);
592
+ }
593
+ return at;
594
+ }
595
+
596
+ /**
597
+ * Emit one finished top-level node: first any kept comments that precede it,
598
+ * then a source mapping anchoring its output start to `[srcLine, srcCol]`, then
599
+ * its text — and drop the per-node store so the next top-level node starts
600
+ * clean. `srcOffset` / `srcLine` / `srcCol` are the node's source position; a
601
+ * grammar that doesn't map positions (e.g. HTML) omits them (no comments, no
602
+ * mapping — the map ends up empty).
603
+ * @param {TNode | undefined} node the top-level node, or undefined where `text` is given and no node is the whole of it
604
+ * @param {number=} srcOffset the node's source offset (kept-comment flush boundary)
605
+ * @param {number=} srcLine 0-based source line of the node's start
606
+ * @param {number=} srcCol 0-based source column of the node's start
607
+ * @param {string=} text what to emit instead of the node's own printed text,
608
+ * for a printer that folded a later node into this one
609
+ */
610
+ take(node, srcOffset, srcLine, srcCol, text) {
611
+ this.anchor(srcOffset, srcLine, srcCol);
612
+ this._emit(
613
+ text === undefined ? this.get(/** @type {TNode} */ (node)) : text
614
+ );
615
+ this._gen++;
616
+ }
617
+
618
+ /**
619
+ * Tie whatever is emitted next to a source position: flush the kept comments
620
+ * that precede it, then record the mapping. Split out of {@link take} for a
621
+ * node printed in pieces, whose first piece is emitted well after the printer
622
+ * for it began.
623
+ * @param {number=} srcOffset the node's source offset (kept-comment flush boundary)
624
+ * @param {number=} srcLine 0-based source line of the node's start
625
+ * @param {number=} srcCol 0-based source column of the node's start
626
+ */
627
+ anchor(srcOffset, srcLine, srcCol) {
628
+ if (srcOffset !== undefined && this._insertIdx < this._inserts.length) {
629
+ this._flushBefore(srcOffset);
630
+ }
631
+ if (srcLine !== undefined && this.mapWanted) {
632
+ // `_chunks.length` is where the tail will land once it is cut off, so
633
+ // this stays right whether or not a piece is cut after it.
634
+ this._mappings.push([
635
+ this._chunks.length,
636
+ this._tailLength,
637
+ srcLine,
638
+ /** @type {number} */ (srcCol)
639
+ ]);
640
+ }
641
+ }
642
+
643
+ /**
644
+ * Whether a kept literal is queued to land before `pos`. A printer folding two
645
+ * top-level nodes together asks first: the literal belongs between them, so
646
+ * the fold would move it past what it was written above.
647
+ * @param {number} pos source offset
648
+ * @returns {boolean} true if a kept literal lands before `pos`
649
+ */
650
+ hasInsertBefore(pos) {
651
+ return (
652
+ this._insertIdx < this._inserts.length &&
653
+ this._inserts[this._insertIdx][0] < pos
654
+ );
655
+ }
656
+
657
+ /**
658
+ * Emit the kept literals landing before `pos`. A printer holding a node back
659
+ * calls this at hold time, so what was written above it is still emitted
660
+ * above it — and {@link hasInsertBefore} then answers about the gap to the
661
+ * next node rather than the whole span since the last node taken.
662
+ * @param {number} pos source offset to flush up to
663
+ * @returns {void}
664
+ */
665
+ flushInsertsBefore(pos) {
666
+ if (this._insertIdx < this._inserts.length) this._flushBefore(pos);
667
+ }
668
+
669
+ /**
670
+ * Queue a literal to carry through to the output at source offset `pos` — a
671
+ * comment the printer chose to keep (e.g. a `/*!` license banner). Calls
672
+ * arrive in source order; each lands just before the first top-level node
673
+ * starting after `pos` (or at the end, via {@link result}).
674
+ * @param {number} pos source offset the literal sits before
675
+ * @param {string} text the literal text
676
+ */
677
+ insert(pos, text) {
678
+ this._inserts.push([pos, text]);
679
+ }
680
+
681
+ /**
682
+ * Take the queued inserts sitting in `[start, end)` — a printer that writes
683
+ * that source range out itself places them, so the writer must not flush
684
+ * them ahead of the next top-level node as well.
685
+ * @param {number} start first source offset of the range
686
+ * @param {number} end offset past its last
687
+ * @returns {string} their text, in source order
688
+ */
689
+ takeInserts(start, end) {
690
+ const inserts = this._inserts;
691
+ // `_insertIdx` only moves on a flush, so walking from it would scan every
692
+ // insert the enclosing rule queued before this range again — quadratic over
693
+ // a rule's declarations. They arrive in source order, so binary search in.
694
+ let low = this._insertIdx;
695
+ let high = inserts.length;
696
+ while (low < high) {
697
+ const middle = (low + high) >> 1;
698
+ if (inserts[middle][0] < start) low = middle + 1;
699
+ else high = middle;
700
+ }
701
+ let out = "";
702
+ for (let i = low; i < inserts.length && inserts[i][0] < end; i++) {
703
+ out += inserts[i][1];
704
+ inserts[i][1] = "";
705
+ }
706
+ return out;
707
+ }
708
+
709
+ /**
710
+ * Emit every queued insert positioned before source offset `pos` (all of them
711
+ * for `Infinity`), in source order, so kept comments keep their place relative
712
+ * to the rules.
713
+ * @param {number} pos source offset to flush up to
714
+ */
715
+ _flushBefore(pos) {
716
+ const inserts = this._inserts;
717
+ let i = this._insertIdx;
718
+ while (i < inserts.length && inserts[i][0] < pos) {
719
+ if (inserts[i][1] !== "") this._emit(inserts[i][1]);
720
+ i++;
721
+ }
722
+ this._insertIdx = i;
723
+ }
724
+
725
+ /**
726
+ * @param {SourceMapOptions} options the input's name / content
727
+ * @returns {SourceMap} the input->output source map
728
+ */
729
+ sourceMap(options) {
730
+ let out = "";
731
+ let genLine = 0;
732
+ let genCol = 0;
733
+ let srcLine = 0;
734
+ let srcCol = 0;
735
+ let atLineStart = true;
736
+ // Where each anchor landed, walked once alongside the mappings — both are
737
+ // in output order, so this is one pass over the output, not a position
738
+ // recomputed per mapping. An anchor can sit inside a piece rather than at
739
+ // its start, since output accumulates into the piece it is appending to.
740
+ const chunks = this._chunks;
741
+ const tail = this._tail;
742
+ /**
743
+ * @param {number} i piece index, `chunks.length` being the tail
744
+ * @returns {string} that piece
745
+ */
746
+ const pieceAt = (i) => (i === chunks.length ? tail : chunks[i]);
747
+ let atChunk = 0;
748
+ let atOffset = 0;
749
+ let atLine = 0;
750
+ let atCol = 0;
751
+ // Offset of the next newline at or after the cursor, `-1` for none left in
752
+ // this piece. Carried rather than searched for per mapping: `indexOf` has no
753
+ // end bound, so asking it again for each of a piece's mappings scans again to
754
+ // the end of the piece every time — and minified output, the case with no
755
+ // newlines at all, is the one where that is the whole piece.
756
+ let nextNewline = pieceAt(0).indexOf("\n");
757
+ /**
758
+ * @param {string} text the piece to walk
759
+ * @param {number} to offset to walk to
760
+ */
761
+ const advanceOver = (text, to) => {
762
+ while (nextNewline !== -1 && nextNewline < to) {
763
+ atLine++;
764
+ atCol = 0;
765
+ atOffset = nextNewline + 1;
766
+ nextNewline = text.indexOf("\n", atOffset);
767
+ }
768
+ atCol += to - atOffset;
769
+ atOffset = to;
770
+ };
771
+ /**
772
+ * @param {number} chunk piece index to advance to
773
+ * @param {number} offset offset within it
774
+ */
775
+ const advanceTo = (chunk, offset) => {
776
+ while (atChunk < chunk) {
777
+ const text = pieceAt(atChunk);
778
+ advanceOver(text, text.length);
779
+ atChunk++;
780
+ atOffset = 0;
781
+ nextNewline = pieceAt(atChunk).indexOf("\n");
782
+ }
783
+ if (offset > atOffset) advanceOver(pieceAt(atChunk), offset);
784
+ };
785
+ for (const [chunkIndex, chunkOffset, sl, sc] of this._mappings) {
786
+ // Its piece was taken back, so there is no output left to anchor.
787
+ if (sl === -1) continue;
788
+ advanceTo(chunkIndex, chunkOffset);
789
+ const gl = atLine;
790
+ const gc = atCol;
791
+ while (genLine < gl) {
792
+ out += ";";
793
+ genLine++;
794
+ genCol = 0;
795
+ atLineStart = true;
796
+ }
797
+ if (!atLineStart) out += ",";
798
+ atLineStart = false;
799
+ // Single source, so the source-index delta is always 0 (`_vlq(0)`).
800
+ out +=
801
+ _vlq(gc - genCol) + _vlq(0) + _vlq(sl - srcLine) + _vlq(sc - srcCol);
802
+ genCol = gc;
803
+ srcLine = sl;
804
+ srcCol = sc;
805
+ }
806
+ return _makeMap(options, out);
807
+ }
808
+
809
+ /**
810
+ * Stand the text `resolve` gives back in place of every deferred write left
811
+ * in the output, and move the mappings that follow one in the same piece by
812
+ * what its text changed in length. Runs before {@link result} and
813
+ * {@link sourceMap}, so both read the substituted output rather than
814
+ * correcting for it.
815
+ *
816
+ * The marker is `NUL id NUL`. A NUL mostly cannot reach printed output on its
817
+ * own account — both preprocessors turn one into U+FFFD — but an RCDATA
818
+ * element and an attribute value keep the one they were written with, so a
819
+ * pair of them is read as a write only where what stands between spells an id
820
+ * this answers for. Anything else is the source's own text and is left alone.
821
+ * @param {(id: number) => string | undefined} resolve the final text for a deferred write, or undefined where it answers for no such write
822
+ * @param {string} infix what this print marked its writes with
823
+ * @returns {void}
824
+ */
825
+ substitute(resolve, infix) {
826
+ const chunks = this._chunks;
827
+ const mappings = this._mappings;
828
+ // Both pieces and mappings are output-ordered, so one cursor walks them
829
+ // together rather than searching the mappings per piece.
830
+ let at = 0;
831
+ for (let i = 0; i <= chunks.length; i++) {
832
+ const text = i === chunks.length ? this._tail : chunks[i];
833
+ while (at < mappings.length && mappings[at][0] < i) at++;
834
+ let start = text.indexOf(DEFERRED_MARKER);
835
+ if (start === -1) continue;
836
+ let out = "";
837
+ let read = 0;
838
+ let delta = 0;
839
+ /** @type {[number, number][]} `[offset past the marker, delta so far]` */
840
+ const shifts = [];
841
+ while (start !== -1) {
842
+ const write = readDeferredWrite(text, start, resolve, infix);
843
+
844
+ // Not a write of ours — a NUL the source carried. Left where it is,
845
+ // and the scan goes on past it so a real write behind it still lands.
846
+ if (write === null) {
847
+ start = text.indexOf(DEFERRED_MARKER, start + 1);
848
+ continue;
849
+ }
850
+
851
+ const { end } = write;
852
+ const replacement = expandDeferredWrites(
853
+ write.replacement,
854
+ resolve,
855
+ infix
856
+ );
857
+
858
+ out += text.slice(read, start) + replacement;
859
+ read = end + 1;
860
+ delta += replacement.length - (read - start);
861
+ shifts.push([read, delta]);
862
+ start = text.indexOf(DEFERRED_MARKER, read);
863
+ }
864
+ out += text.slice(read);
865
+ if (i === chunks.length) {
866
+ this._tail = out;
867
+ this._tailLength = out.length;
868
+ } else {
869
+ chunks[i] = out;
870
+ }
871
+ let s = 0;
872
+ for (let k = at; k < mappings.length && mappings[k][0] === i; k++) {
873
+ while (s < shifts.length && shifts[s][0] <= mappings[k][1]) s++;
874
+ if (s !== 0) mappings[k][1] += shifts[s - 1][1];
875
+ }
876
+ }
877
+ }
878
+
879
+ /**
880
+ * @returns {string} the printed output
881
+ */
882
+ /**
883
+ * Throw away everything printed and stand `text` in its place. For the one
884
+ * caller that can only tell its output is wrong once it has all of it.
885
+ * @param {string} text the output to keep instead
886
+ */
887
+ replaceAll(text) {
888
+ this._chunks.length = 0;
889
+ this._tail = text;
890
+ this._tailLength = text.length;
891
+ this._mappings.length = 0;
892
+ this._inserts.length = 0;
893
+ this._insertIdx = 0;
894
+ this._pending.length = 0;
895
+ this._pendingAnchor = null;
896
+ }
897
+
898
+ result() {
899
+ // Trailing kept comments (after the last top-level node) flush here.
900
+ if (this._insertIdx < this._inserts.length) this._flushBefore(Infinity);
901
+ // Nothing was ever cut into its own piece, so there is nothing to join.
902
+ const chunks = this._chunks;
903
+ return chunks.length === 0 ? this._tail : chunks.join("") + this._tail;
904
+ }
905
+ }
906
+
46
907
  /**
47
908
  * Visitor coordinator: owns the visitor registry and drives a language
48
909
  * `grammar` over the source. Language-agnostic — each syntax (CSS, HTML, …)
49
- * binds its own grammar and node-type enum. Babel-style usage:
910
+ * binds its own grammar, node-type enum and (optionally) node printer.
911
+ * Babel-style usage:
50
912
  *
51
913
  * ```
52
914
  * processor.use({ [NodeType.X]: (path) => {}, [NodeType.Y]: { enter, exit } });
53
915
  * processor.process(source);
54
916
  * ```
55
917
  * @template TPath
918
+ * @template TNode
56
919
  * @template [TProcessOptions=object]
920
+ * @template [TPrintOptions=object]
57
921
  */
58
922
  class SourceProcessor {
59
923
  /**
60
- * @param {Grammar<TPath, TProcessOptions>} grammar the grammar to drive over the source
61
- * @param {TProcessOptions=} options default process options (e.g. `skip`) merged under each `process` call's own options
924
+ * @param {Grammar<TPath, TNode, TProcessOptions, TPrintOptions>} grammar the grammar to drive over the source
925
+ * @param {NodePrinter<TPath, TNode, TPrintOptions>=} printer the node printer, fired per node once its visitors and children are done; the same `path` a visitor gets plus the print context as its writer. Required to print (e.g. `mode`); a future API can let a developer supply their own
62
926
  */
63
- constructor(grammar, options) {
64
- /** @type {Grammar<TPath, TProcessOptions>} */
927
+ constructor(grammar, printer) {
928
+ /** @type {Grammar<TPath, TNode, TProcessOptions, TPrintOptions>} */
65
929
  this._grammar = grammar;
66
930
  /** @type {CompiledVisitorMap<TPath>} */
67
931
  this._visitors = [];
68
- /** @type {TProcessOptions | undefined} */
69
- this._options = options;
932
+ /** @type {NodePrinter<TPath, TNode, TPrintOptions> | undefined} */
933
+ this._printer = printer;
934
+ // Set for the one print {@link processDeferred} holds open, so `process`
935
+ // hands it the context instead of building the output straight away.
936
+ /** @type {((ctx: PrintContext<TPath, TNode, TPrintOptions>, build: () => { code: string, map: SourceMap | undefined }) => void) | null} */
937
+ this._deferred = null;
70
938
  }
71
939
 
72
940
  /**
73
941
  * Register a Babel-style visitor map; calls accumulate per node type.
74
942
  * A bucket is a function (= `{ enter }`) or `{ enter?, exit? }`.
75
943
  * @param {VisitorMap<TPath>} map visitor map keyed by node type
76
- * @returns {SourceProcessor<TPath, TProcessOptions>} `this`, for chaining
944
+ * @returns {SourceProcessor<TPath, TNode, TProcessOptions, TPrintOptions>} `this`, for chaining
77
945
  */
78
946
  use(map) {
79
947
  // `map`'s keys are node-type enum members; `Object.keys` stringifies them,
@@ -97,23 +965,181 @@ class SourceProcessor {
97
965
  }
98
966
 
99
967
  /**
100
- * Run the grammar over `input`, firing visitors in source order. No
101
- * AST retained. Per-call `options` override the instance defaults.
968
+ * Parse `input` once and fire the visitors in source order. Asking for output
969
+ * — `mode`, the one thing that names it — makes the same walk print, given a
970
+ * printer supplied at construction: a
971
+ * {@link PrintContext} is created, each node's printer fires into it as the node
972
+ * finishes, and the result is returned as `{ code, map }`: the serialized output
973
+ * and, for a caller that named its input with `source` / `content`, the
974
+ * input->output source map — `map` is `undefined` without one. Asking for
975
+ * none of it only walks and returns `undefined`. A single parse — printing
976
+ * never re-parses; all configuration is per-call.
977
+ * @overload
978
+ * @param {string} input the source
979
+ * @param {TProcessOptions & { mode: PrintOptions["mode"] } & { source: string, content?: string }} options process options, naming the input so a map is built
980
+ * @returns {{ code: string, map: SourceMap }} the output and its map
981
+ */
982
+ /**
983
+ * @overload
984
+ * @param {string} input the source
985
+ * @param {TProcessOptions & { mode: PrintOptions["mode"] }} options process options, asking for output but no map
986
+ * @returns {{ code: string, map: undefined }} the output alone
987
+ */
988
+ /**
989
+ * @overload
990
+ * @param {string} input the source
991
+ * @param {TProcessOptions=} options process options, asking for no output
992
+ * @returns {undefined} nothing — the walk alone
993
+ */
994
+ /**
102
995
  * @param {string} input source text
103
- * @param {TProcessOptions=} options grammar-specific options
996
+ * @param {TProcessOptions=} options grammar-specific options (`skip`, …) plus `mode` and, for the map, `source` / `content`
997
+ * @returns {EXPECTED_ANY} `{ code, map }` when printing, else `undefined` — see the overloads
104
998
  */
105
999
  process(input, options) {
106
- const defaults = this._options;
107
- this._grammar(
108
- input,
109
- this._visitors,
110
- defaults
111
- ? options
112
- ? { ...defaults, ...options }
113
- : defaults
114
- : options || /** @type {TProcessOptions} */ ({})
1000
+ const opts = options || /** @type {TProcessOptions} */ ({});
1001
+ const asked = /** @type {{ mode?: PrintOptions["mode"] }} */ (opts).mode;
1002
+ if (this._printer === undefined || asked === undefined) {
1003
+ this._grammar(input, this._visitors, undefined, opts);
1004
+ return undefined;
1005
+ }
1006
+ // Handed over whole rather than copied entry by entry: which of them are
1007
+ // print options is the language's to say, and listing them here is what
1008
+ // made every new one an edit to this file. A grammar-only entry riding
1009
+ // along is inert — a printer reads only what its own type declares.
1010
+ const ctx = new PrintContext(
1011
+ /** @type {PrintOptions & TPrintOptions} */ (
1012
+ /** @type {unknown} */ ({ ...opts, mode: asked })
1013
+ ),
1014
+ /** @type {NodePrinter<TPath, TNode, TPrintOptions>} */ (this._printer)
1015
+ );
1016
+ this._grammar(input, this._visitors, ctx, opts);
1017
+ const name = /** @type {{ source?: string, content?: string }} */ (opts);
1018
+ const build = () => ({
1019
+ code: ctx.result(),
1020
+ // Built only for a caller that named the input: building one walks the
1021
+ // whole output for its line breaks, and the minifier prints an inline
1022
+ // `style=""` — which asks for no map — thousands of times a document.
1023
+ map:
1024
+ name.source === undefined
1025
+ ? undefined
1026
+ : ctx.sourceMap({ source: name.source, content: name.content })
1027
+ });
1028
+ if (this._deferred !== null) {
1029
+ const finish = this._deferred;
1030
+
1031
+ this._deferred = null;
1032
+ finish(ctx, build);
1033
+ return undefined;
1034
+ }
1035
+ return build();
1036
+ }
1037
+
1038
+ /**
1039
+ * {@link process}, for a caller whose renderer answers asynchronously. Code
1040
+ * generation is synchronous — a printer returns its node's text, it cannot
1041
+ * await one — so the walk leaves a marker where each answer goes, they are
1042
+ * asked for together, and {@link PrintContext.substitute} stands each in its
1043
+ * place before the output and its map are built. One parse either way, and
1044
+ * the async boundary stays at the top rather than on every node.
1045
+ *
1046
+ * This is the shape `process` itself takes once it is async: how the answers
1047
+ * are waited for is this method's business, so nothing above it changes.
1048
+ * @param {string} input the source
1049
+ * @param {Omit<TProcessOptions, "renderEmbeddedSource"> & { mode: PrintOptions["mode"] } & { source?: string, content?: string, renderEmbeddedSource?: (source: string, hole: EXPECTED_ANY) => Promise<string | undefined> | string | undefined }} options process options; a print, so `mode` names which one, and naming the input builds a map. `renderEmbeddedSource` is the grammar's own option with a wider answer — it may answer asynchronously, and is handed each {@link DeferredWrite} whole. Absent, this is `process` with a promise around it
1050
+ * @returns {Promise<{ code: string, map: SourceMap | undefined }>} the output and its map
1051
+ */
1052
+ async processAsync(input, options) {
1053
+ const render = options.renderEmbeddedSource;
1054
+
1055
+ // The cast, twice below: `options` is the grammar's own type with only the
1056
+ // renderer's answer widened, which `Omit` cannot say and nothing reads.
1057
+ const opts =
1058
+ /** @type {TProcessOptions & { mode: PrintOptions["mode"] }} */
1059
+ (/** @type {unknown} */ (options));
1060
+
1061
+ if (render === undefined) {
1062
+ return /** @type {{ code: string, map: SourceMap | undefined }} */ (
1063
+ this.process(input, opts)
1064
+ );
1065
+ }
1066
+
1067
+ /** @type {DeferredWrite[]} */
1068
+ const deferred = [];
1069
+ const { finish } = this._processDeferred(input, {
1070
+ ...opts,
1071
+ // The grammar collects into this rather than asking, and it takes
1072
+ // precedence over a synchronous renderer — which is not passed on.
1073
+ renderEmbeddedSource: undefined,
1074
+ deferEmbeddedSource: deferred
1075
+ });
1076
+ // Asked together rather than one after another: they are independent, and
1077
+ // a renderer that goes out to a worker pool would otherwise serialize.
1078
+ const answers = await Promise.all(
1079
+ deferred.map((hole) => render(hole.source, hole))
115
1080
  );
1081
+
1082
+ return finish((id) => {
1083
+ const hole = deferred[id];
1084
+
1085
+ return hole === undefined ? undefined : hole.build(answers[id]);
1086
+ });
1087
+ }
1088
+
1089
+ /**
1090
+ * Print `input` holding the deferred writes open: `finish` puts the answers
1091
+ * in their place and only then builds the output and its map, so neither has
1092
+ * to be corrected for what an answer changed in length. The one mechanism
1093
+ * {@link processAsync} is built on, and private for that reason: a caller
1094
+ * asks for an asynchronous print, not for the way one is arranged.
1095
+ * @param {string} input the source
1096
+ * @param {TProcessOptions & { mode: PrintOptions["mode"] } & { source?: string, content?: string }} options process options; a print, so `mode` names which one, and naming the input builds a map
1097
+ * @returns {{ finish: (resolve: (id: number) => string | undefined) => { code: string, map: SourceMap | undefined } }} the deferred print
1098
+ */
1099
+ _processDeferred(input, options) {
1100
+ /** @type {PrintContext<TPath, TNode, TPrintOptions> | undefined} */
1101
+ let held;
1102
+ /** @type {(() => { code: string, map: SourceMap | undefined }) | undefined} */
1103
+ let heldBuild;
1104
+
1105
+ /** @type {NonNullable<typeof this._deferred>} */
1106
+ const deferred = (ctx, build) => {
1107
+ held = ctx;
1108
+ heldBuild = build;
1109
+ };
1110
+
1111
+ this._deferred = deferred;
1112
+
1113
+ const infix = chooseDeferredInfix(input);
1114
+ // Restored rather than cleared: a nested print runs inside this one's
1115
+ // `finish`, and the writes it left are still marked with this infix.
1116
+ const outer = deferredInfix;
1117
+
1118
+ deferredInfix = infix;
1119
+
1120
+ try {
1121
+ this.process(input, options);
1122
+ } finally {
1123
+ deferredInfix = outer;
1124
+ // A throw never reaches where `process` clears this, and the next print
1125
+ // on this processor would take it for its own. Only ours: a nested print
1126
+ // during the walk may have left a newer one.
1127
+ if (this._deferred === deferred) this._deferred = null;
1128
+ }
1129
+
1130
+ return {
1131
+ finish: (resolve) => {
1132
+ /** @type {PrintContext<TPath, TNode, TPrintOptions>} */
1133
+ (held).substitute(resolve, infix);
1134
+ return /** @type {() => { code: string, map: SourceMap | undefined }} */ (
1135
+ heldBuild
1136
+ )();
1137
+ }
1138
+ };
116
1139
  }
117
1140
  }
118
1141
 
1142
+ SourceProcessor.PrintContext = PrintContext;
1143
+
119
1144
  module.exports = SourceProcessor;
1145
+ module.exports.deferredWrite = deferredWrite;