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

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