@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
@@ -15,9 +15,6 @@ const CssIcssSymbolDependency = require("../dependencies/CssIcssSymbolDependency
15
15
  const CssImportDependency = require("../dependencies/CssImportDependency");
16
16
  const CssUrlDependency = require("../dependencies/CssUrlDependency");
17
17
  const StaticExportsDependency = require("../dependencies/StaticExportsDependency");
18
- const CommentCompilationWarning = require("../errors/CommentCompilationWarning");
19
- const ModuleDependencyWarning = require("../errors/ModuleDependencyWarning");
20
- const UnsupportedFeatureWarning = require("../errors/UnsupportedFeatureWarning");
21
18
  const WebpackError = require("../errors/WebpackError");
22
19
  const ResourceHintPlugin = require("../prefetch/ResourceHintPlugin");
23
20
  const LocConverter = require("../util/LocConverter");
@@ -26,7 +23,9 @@ const {
26
23
  createMagicCommentContext,
27
24
  parseCommentOptionsInRange
28
25
  } = require("../util/magicComment");
26
+ const memoize = require("../util/memoize");
29
27
  const topologicalSort = require("../util/topologicalSort");
28
+ const { CSS_MODULES_KEYWORDS, CSS_MODULES_KEYWORD_OPTIONS } = require("./data");
30
29
  const {
31
30
  A,
32
31
  NodeType,
@@ -38,40 +37,83 @@ const {
38
37
  normalizeUrl,
39
38
  rangeEquals,
40
39
  rangeEqualsLowerCase,
40
+ skipEscape,
41
41
  toLowerCaseIfNeeded,
42
42
  unescapeIdentifier
43
43
  } = require("./syntax");
44
44
 
45
+ const getUnsupportedFeatureWarning = memoize(() =>
46
+ require("../errors/UnsupportedFeatureWarning")
47
+ );
48
+
49
+ const getModuleDependencyWarning = memoize(() =>
50
+ require("../errors/ModuleDependencyWarning")
51
+ );
52
+
53
+ const getCommentCompilationWarning = memoize(() =>
54
+ require("../errors/CommentCompilationWarning")
55
+ );
56
+
45
57
  // `SourceProcessor` drives the parse and hands already-built AST nodes to the visitors; positions are read from those nodes' ranges rather than re-scanning the source.
46
58
 
47
- /** @typedef {import("../Module").BuildInfo} BuildInfo */
48
- /** @typedef {import("../Module").BuildMeta} BuildMeta */
49
- /** @typedef {import("./CssModule").CssModuleBuildInfo} CssModuleBuildInfo */
50
- /** @typedef {import("./CssModule").CssModuleBuildMeta} CssModuleBuildMeta */
51
- /** @typedef {import("../Parser").ParserState} ParserState */
52
- /** @typedef {import("../Parser").PreparsedAst} PreparsedAst */
53
- /** @typedef {import("./syntax").AtRule} AtRule */
54
- /** @typedef {import("./syntax").Declaration} Declaration */
55
- /** @typedef {import("./syntax").FunctionNode} FunctionNode */
56
- /** @typedef {import("./syntax").Node} AstNode */
57
- /** @typedef {import("./syntax").QualifiedRule} QualifiedRule */
58
- /** @typedef {import("./syntax").Rule} Rule */
59
- /** @typedef {import("./syntax").SimpleBlock} SimpleBlock */
60
- /** @typedef {import("./syntax").Token} Token */
61
- /** @typedef {import("./syntax").UrlToken} UrlToken */
62
- /** @typedef {import("./syntax").HashToken} HashToken */
63
- /** @typedef {import("./syntax").VisitorMap} VisitorMap */
64
- /** @typedef {import("../../declarations/WebpackOptions").CssAutoOrModuleParserOptions} CssAutoOrModuleParserOptions */
65
- /** @typedef {import("../../declarations/WebpackOptions").CssModuleParserOptions} CssModuleParserOptions */
66
- /** @typedef {import("./CssModule")} CssModule */
67
- /** @typedef {import("./CssModule").Inheritance} Inheritance */
59
+ /** @import { BuildInfo, BuildMeta } from "../Module" */
60
+ /**
61
+ * @import CssModule, {
62
+ * CssModuleBuildInfo,
63
+ * CssModuleBuildMeta,
64
+ * Inheritance
65
+ * } from "./CssModule"
66
+ */
67
+ /** @import { ParserState, PreparsedAst } from "../Parser" */
68
+ /**
69
+ * @import {
70
+ * AtRule,
71
+ * Declaration,
72
+ * FunctionNode,
73
+ * Node as AstNode,
74
+ * QualifiedRule,
75
+ * Rule,
76
+ * SimpleBlock,
77
+ * Token,
78
+ * UrlToken,
79
+ * VisitorMap
80
+ * } from "./syntax"
81
+ */
82
+ /**
83
+ * @import {
84
+ * CssAutoOrModuleParserOptions
85
+ * } from "../../declarations/WebpackOptions"
86
+ */
68
87
 
69
88
  /** @typedef {[number, number]} Range */
70
89
  /** @typedef {{ line: number, column: number }} Position */
71
90
  /** @typedef {{ from: string, items: ({ localName: string, importName: string })[] }} ValueAtRuleImport */
72
91
  /** @typedef {{ localName: string, value: string }} ValueAtRuleValue */
92
+ /**
93
+ * What a `@custom-media` name resolves to. `condition` substitutes into any
94
+ * `<media-in-parens>` slot, `type` only at the start of a query, `boolean` is the
95
+ * spec's `true` / `false` (folded into the enclosing query rather than written
96
+ * out — no `<media-in-parens>` is unconditionally true on every engine).
97
+ * @typedef {{ kind: "condition" | "type", text: string } | { kind: "boolean", value: boolean } | { kind: "unsupported" }} CustomMediaValue
98
+ */
99
+ /** @typedef {CustomMediaValue | { kind: "alias", name: string } | { kind: "or", parts: ({ text: string } | { alias: string })[] }} CustomMediaDefinition */
100
+ /** @typedef {{ name: string, start: number, end: number, invalid: boolean, leading: boolean }} CustomMediaUse */
101
+ /**
102
+ * A `@media` prelude captured as its boolean shape, so a `true` / `false`
103
+ * definition found later can be folded into it. Node ids are recycled per
104
+ * top-level rule, so this holds text and offsets rather than AST nodes.
105
+ * @typedef {{ kind: "text", text: string } | { kind: "ref", text: string, use: CustomMediaUse } | { kind: "group", operand: MediaNode } | { kind: "not", operand: MediaNode } | { kind: "chain", isOr: boolean, terms: MediaNode[] } | { kind: "typed", text: string, rest: MediaNode | null }} MediaNode
106
+ */
107
+
108
+ /** @type {CustomMediaValue} */
109
+ const CUSTOM_MEDIA_UNSUPPORTED = { kind: "unsupported" };
110
+ /** @type {CustomMediaValue} */
111
+ const CUSTOM_MEDIA_TRUE = { kind: "boolean", value: true };
112
+ /** @type {CustomMediaValue} */
113
+ const CUSTOM_MEDIA_FALSE = { kind: "boolean", value: false };
73
114
 
74
115
  const CC_COLON = ":".charCodeAt(0);
116
+ const CC_FULL_STOP = ".".charCodeAt(0);
75
117
  const CC_HYPHEN_MINUS = "-".charCodeAt(0);
76
118
  const CC_SEMICOLON = ";".charCodeAt(0);
77
119
  const CC_TAB = "\t".charCodeAt(0);
@@ -103,22 +145,23 @@ const VIEW_TRANSITION_PART_PSEUDO =
103
145
  /^view-transition-(?:group|image-pair|old|new)$/i;
104
146
  const IS_MODULES = /\.modules?\.[^.]+$/i;
105
147
 
106
- // `@font-face` src extension → preload `type`; the emission guesses `as="font"`.
107
- const FONT_MIME_TYPES = new Map([
108
- ["woff2", "font/woff2"],
109
- ["woff", "font/woff"],
110
- ["ttf", "font/ttf"],
111
- ["otf", "font/otf"],
112
- ["eot", "application/vnd.ms-fontobject"]
113
- ]);
148
+ // Which formats get a preload hint is webpack's call; what each one *is* comes
149
+ // from `mime-db`, not a second copy of the mapping.
150
+ const FONT_EXTENSIONS = new Set(["woff2", "woff", "ttf", "otf", "eot"]);
151
+
152
+ // mime-db is heavy — only load it once a font src actually needs a `type`.
153
+ const getMimeTypes = memoize(() => require("../util/mimeTypes"));
114
154
 
115
155
  /**
116
156
  * @param {string} request font url (may carry a query/hash)
117
157
  * @returns {string | undefined} preload `type` for a known font extension
118
158
  */
119
159
  const fontMimeType = (request) => {
120
- const match = /\.([a-z0-9]+)(?:[?#]|$)/i.exec(request);
121
- return match ? FONT_MIME_TYPES.get(match[1].toLowerCase()) : undefined;
160
+ // Off the path only: `font?fallback=.woff2` names no font.
161
+ const resourcePath = parseResource(request).path;
162
+ const extension = path.extname(resourcePath).slice(1).toLowerCase();
163
+ if (!FONT_EXTENSIONS.has(extension)) return undefined;
164
+ return getMimeTypes().lookup(resourcePath);
122
165
  };
123
166
 
124
167
  // Skip options for a non-CSS-Modules parse: drop the selector prelude (never
@@ -167,37 +210,18 @@ const ONLY_WHITESPACE = /^\s+$/;
167
210
  // Relative request prefix (`./` or `../`) — `isSelfReferenceRequest` per `from`.
168
211
  const RELATIVE_REQUEST = /^\.{1,2}\//;
169
212
 
170
- /**
171
- * Returns matches.
172
- * @param {RegExp} regexp a regexp
173
- * @param {string} str a string
174
- * @returns {RegExpExecArray[]} matches
175
- */
176
- const matchAll = (regexp, str) => {
177
- /** @type {RegExpExecArray[]} */
178
- const result = [];
179
-
180
- /** @type {null | RegExpExecArray} */
181
- let match;
182
-
183
- while ((match = regexp.exec(str)) !== null) {
184
- result.push(match);
185
- }
186
- return result;
187
- };
188
-
189
213
  /**
190
214
  * Range-keyed index over a known-properties table: ASCII-case-folded 31-hash
191
215
  * of the name bytes → canonical key(s). Lets the Declaration visitor answer
192
216
  * "is this a known property" (and get the canonical lowercase name) without
193
217
  * slicing the property name out of the source per declaration.
194
- * @type {WeakMap<Map<string, Record<string, number>>, Map<number, string | string[]>>}
218
+ * @type {WeakMap<Map<string, Map<string, number>>, Map<number, string | string[]>>}
195
219
  */
196
220
  const KNOWN_PROPERTY_INDEX_CACHE = new WeakMap();
197
221
 
198
222
  /**
199
223
  * Gets (or builds) the hash index for a known-properties table.
200
- * @param {Map<string, Record<string, number>>} knownProperties known properties table
224
+ * @param {Map<string, Map<string, number>>} knownProperties known properties table
201
225
  * @returns {Map<number, string | string[]>} hash → canonical name(s)
202
226
  */
203
227
  const getKnownPropertyIndex = (knownProperties) => {
@@ -231,6 +255,12 @@ const knownPropertyForRange = (index, input, start, end) => {
231
255
  let h = end - start;
232
256
  for (let i = start; i < end; i++) {
233
257
  let c = input.charCodeAt(i);
258
+ // The table holds no raw-byte spelling, so re-read the unescaped one.
259
+ // Each pass shortens the name, so an escaped `\` cannot recurse forever.
260
+ if (c === CC_REVERSE_SOLIDUS) {
261
+ const name = unescapeIdentifier(input.slice(start, end));
262
+ return knownPropertyForRange(index, name, 0, name.length);
263
+ }
234
264
  if (c >= 65 && c <= 90) c |= 0x20;
235
265
  h = ((h << 5) - h + c) | 0;
236
266
  }
@@ -245,291 +275,84 @@ const knownPropertyForRange = (index, input, start, end) => {
245
275
  return undefined;
246
276
  };
247
277
 
248
- /** @type {Record<string, number>} */
249
- const PREDEFINED_COUNTER_STYLES = {
250
- decimal: 1,
251
- "decimal-leading-zero": 1,
252
- "arabic-indic": 1,
253
- armenian: 1,
254
- "upper-armenian": 1,
255
- "lower-armenian": 1,
256
- bengali: 1,
257
- cambodian: 1,
258
- khmer: 1,
259
- "cjk-decimal": 1,
260
- devanagari: 1,
261
- georgian: 1,
262
- gujarati: 1,
263
- /* cspell:disable-next-line */
264
- gurmukhi: 1,
265
- hebrew: 1,
266
- kannada: 1,
267
- lao: 1,
268
- malayalam: 1,
269
- mongolian: 1,
270
- myanmar: 1,
271
- oriya: 1,
272
- persian: 1,
273
- "lower-roman": 1,
274
- "upper-roman": 1,
275
- tamil: 1,
276
- telugu: 1,
277
- thai: 1,
278
- tibetan: 1,
279
-
280
- "lower-alpha": 1,
281
- "lower-latin": 1,
282
- "upper-alpha": 1,
283
- "upper-latin": 1,
284
- "lower-greek": 1,
285
- hiragana: 1,
286
- /* cspell:disable-next-line */
287
- "hiragana-iroha": 1,
288
- katakana: 1,
289
- /* cspell:disable-next-line */
290
- "katakana-iroha": 1,
291
-
292
- disc: 1,
293
- circle: 1,
294
- square: 1,
295
- "disclosure-open": 1,
296
- "disclosure-closed": 1,
297
-
298
- "cjk-earthly-branch": 1,
299
- "cjk-heavenly-stem": 1,
300
-
301
- "japanese-informal": 1,
302
- "japanese-formal": 1,
303
-
304
- "korean-hangul-formal": 1,
305
- /* cspell:disable-next-line */
306
- "korean-hanja-informal": 1,
307
- /* cspell:disable-next-line */
308
- "korean-hanja-formal": 1,
309
-
310
- "simp-chinese-informal": 1,
311
- "simp-chinese-formal": 1,
312
- "trad-chinese-informal": 1,
313
- "trad-chinese-formal": 1,
314
- "cjk-ideographic": 1,
315
-
316
- "ethiopic-numeric": 1
317
- };
318
-
319
- /** @type {Record<string, number>} */
320
- const GLOBAL_VALUES = {
321
- // Global values
322
- initial: Infinity,
323
- inherit: Infinity,
324
- unset: Infinity,
325
- revert: Infinity,
326
- "revert-layer": Infinity
327
- };
328
-
329
- /** @type {Record<string, number>} */
330
- const GRID_AREA_OR_COLUMN_OR_ROW = {
331
- auto: Infinity,
332
- span: Infinity,
333
- ...GLOBAL_VALUES
334
- };
335
-
336
- /** @type {Record<string, number>} */
337
- const GRID_AUTO_COLUMNS_OR_ROW = {
338
- "min-content": Infinity,
339
- "max-content": Infinity,
340
- auto: Infinity,
341
- ...GLOBAL_VALUES
342
- };
343
-
344
- /** @type {Record<string, number>} */
345
- const GRID_AUTO_FLOW = {
346
- row: 1,
347
- column: 1,
348
- dense: 1,
349
- ...GLOBAL_VALUES
350
- };
351
-
352
- /** @type {Record<string, number>} */
353
- const GRID_TEMPLATE_AREAS = {
354
- // Special
355
- none: 1,
356
- ...GLOBAL_VALUES
357
- };
358
-
359
- /** @type {Record<string, number>} */
360
- const GRID_TEMPLATE_COLUMNS_OR_ROWS = {
361
- none: 1,
362
- subgrid: 1,
363
- masonry: 1,
364
- "max-content": Infinity,
365
- "min-content": Infinity,
366
- auto: Infinity,
367
- ...GLOBAL_VALUES
368
- };
369
-
370
- /** @type {Record<string, number>} */
371
- const GRID_TEMPLATE = {
372
- ...GRID_TEMPLATE_AREAS,
373
- ...GRID_TEMPLATE_COLUMNS_OR_ROWS
374
- };
375
-
376
- /** @type {Record<string, number>} */
377
- const GRID = {
378
- "auto-flow": 1,
379
- dense: 1,
380
- ...GRID_AUTO_COLUMNS_OR_ROW,
381
- ...GRID_AUTO_FLOW,
382
- ...GRID_TEMPLATE_AREAS,
383
- ...GRID_TEMPLATE_COLUMNS_OR_ROWS
278
+ /**
279
+ * Comma-separated index of the counter-name argument in a counter-reading function, or `-1` when the name isn't one. The name is matched over the raw byte range like the other function-name probes; only an escaped name (rare) pays the unescaped slice.
280
+ * @param {string} input source
281
+ * @param {number} start name start offset
282
+ * @param {number} end name end offset
283
+ * @param {string=} escapedName unescaped name, when the raw range carries an escape
284
+ * @returns {number} argument index of the counter name, or `-1`
285
+ */
286
+ const counterFunctionNameIndex = (input, start, end, escapedName) => {
287
+ // The `target-counter(url, name, style?)` cross-reference forms (Generated Content for Paged Media) name the counter second; print engines read them.
288
+ if (escapedName !== undefined) {
289
+ if (
290
+ equalsLowerCase(escapedName, "counter") ||
291
+ equalsLowerCase(escapedName, "counters")
292
+ ) {
293
+ return 0;
294
+ }
295
+ if (
296
+ equalsLowerCase(escapedName, "target-counter") ||
297
+ equalsLowerCase(escapedName, "target-counters")
298
+ ) {
299
+ return 1;
300
+ }
301
+ return -1;
302
+ }
303
+ switch (end - start) {
304
+ case 7:
305
+ return rangeEqualsLowerCase(input, start, end, "counter") ? 0 : -1;
306
+ case 8:
307
+ return rangeEqualsLowerCase(input, start, end, "counters") ? 0 : -1;
308
+ case 14:
309
+ return rangeEqualsLowerCase(input, start, end, "target-counter") ? 1 : -1;
310
+ case 15:
311
+ return rangeEqualsLowerCase(input, start, end, "target-counters")
312
+ ? 1
313
+ : -1;
314
+ default:
315
+ return -1;
316
+ }
384
317
  };
385
318
 
386
319
  /**
387
- * Gets known properties.
320
+ * Gets the known-properties table for the enabled scoping options: the
321
+ * properties a `css/module` reads a scoped name out of, each with the keywords
322
+ * of its own grammar (see `tooling/generate-css-data.js`).
388
323
  * @param {{ animation?: boolean, container?: boolean, customIdents?: boolean, grid?: boolean }=} options options
389
- * @returns {Map<string, Record<string, number>>} list of known properties
324
+ * @returns {Map<string, Map<string, number>>} list of known properties
390
325
  */
391
326
  const buildKnownProperties = (options = {}) => {
392
- /** @type {Map<string, Record<string, number>>} */
327
+ /** @type {Map<string, Map<string, number>>} */
393
328
  const knownProperties = new Map();
394
-
395
- if (options.animation) {
396
- knownProperties.set("animation", {
397
- // animation-direction
398
- normal: 1,
399
- reverse: 1,
400
- alternate: 1,
401
- "alternate-reverse": 1,
402
- // animation-fill-mode
403
- forwards: 1,
404
- backwards: 1,
405
- both: 1,
406
- // animation-iteration-count
407
- infinite: 1,
408
- // animation-play-state
409
- paused: 1,
410
- running: 1,
411
- // animation-timing-function
412
- ease: 1,
413
- "ease-in": 1,
414
- "ease-out": 1,
415
- "ease-in-out": 1,
416
- linear: 1,
417
- "step-end": 1,
418
- "step-start": 1,
419
- // Special
420
- none: Infinity, // No matter how many times you write none, it will never be an animation name
421
- ...GLOBAL_VALUES
422
- });
423
- knownProperties.set("animation-name", {
424
- // Special
425
- none: Infinity, // No matter how many times you write none, it will never be an animation name
426
- ...GLOBAL_VALUES
427
- });
428
- }
429
-
430
- if (options.container) {
431
- knownProperties.set("container", {
432
- // container-type
433
- normal: 1,
434
- size: 1,
435
- "inline-size": 1,
436
- "scroll-state": 1,
437
- // Special
438
- none: Infinity,
439
- ...GLOBAL_VALUES
440
- });
441
- knownProperties.set("container-name", {
442
- // Special
443
- none: Infinity,
444
- ...GLOBAL_VALUES
445
- });
446
- }
447
-
448
- if (options.customIdents) {
449
- knownProperties.set("list-style", {
450
- // list-style-position
451
- inside: 1,
452
- outside: 1,
453
- // list-style-type
454
- ...PREDEFINED_COUNTER_STYLES,
455
- // Special
456
- none: Infinity,
457
- ...GLOBAL_VALUES
458
- });
459
- knownProperties.set("list-style-type", {
460
- // list-style-type
461
- ...PREDEFINED_COUNTER_STYLES,
462
- // Special
463
- none: Infinity,
464
- ...GLOBAL_VALUES
465
- });
466
- knownProperties.set("system", {
467
- cyclic: 1,
468
- numeric: 1,
469
- alphabetic: 1,
470
- symbolic: 1,
471
- additive: 1,
472
- fixed: 1,
473
- extends: 1,
474
- ...PREDEFINED_COUNTER_STYLES
475
- });
476
- knownProperties.set("fallback", {
477
- ...PREDEFINED_COUNTER_STYLES
478
- });
479
- knownProperties.set("speak-as", {
480
- auto: 1,
481
- bullets: 1,
482
- numbers: 1,
483
- words: 1,
484
- "spell-out": 1,
485
- ...PREDEFINED_COUNTER_STYLES
486
- });
487
- knownProperties.set("view-transition-name", {
488
- none: Infinity,
489
- auto: Infinity,
490
- "match-element": Infinity,
491
- ...GLOBAL_VALUES
492
- });
493
- knownProperties.set("view-transition-group", {
494
- normal: Infinity,
495
- contain: Infinity,
496
- nearest: Infinity,
497
- ...GLOBAL_VALUES
498
- });
499
- knownProperties.set("view-transition-class", {
500
- none: Infinity,
501
- ...GLOBAL_VALUES
502
- });
503
- }
504
-
505
- if (options.grid) {
506
- knownProperties.set("grid", GRID);
507
- knownProperties.set("grid-area", GRID_AREA_OR_COLUMN_OR_ROW);
508
- knownProperties.set("grid-column", GRID_AREA_OR_COLUMN_OR_ROW);
509
- knownProperties.set("grid-column-end", GRID_AREA_OR_COLUMN_OR_ROW);
510
- knownProperties.set("grid-column-start", GRID_AREA_OR_COLUMN_OR_ROW);
511
- knownProperties.set("grid-row", GRID_AREA_OR_COLUMN_OR_ROW);
512
- knownProperties.set("grid-row-end", GRID_AREA_OR_COLUMN_OR_ROW);
513
- knownProperties.set("grid-row-start", GRID_AREA_OR_COLUMN_OR_ROW);
514
- knownProperties.set("grid-template", GRID_TEMPLATE);
515
- knownProperties.set("grid-template-areas", GRID_TEMPLATE_AREAS);
516
- knownProperties.set("grid-template-columns", GRID_TEMPLATE_COLUMNS_OR_ROWS);
517
- knownProperties.set("grid-template-rows", GRID_TEMPLATE_COLUMNS_OR_ROWS);
329
+ for (const [property, option] of CSS_MODULES_KEYWORD_OPTIONS) {
330
+ if (
331
+ options[
332
+ /** @type {"animation" | "container" | "customIdents" | "grid"} */
333
+ (option)
334
+ ]
335
+ ) {
336
+ knownProperties.set(
337
+ property,
338
+ /** @type {Map<string, number>} */
339
+ (CSS_MODULES_KEYWORDS.get(property))
340
+ );
341
+ }
518
342
  }
519
-
520
343
  return knownProperties;
521
344
  };
522
345
 
523
- /** @type {Map<number, Map<string, Record<string, number>>>} */
346
+ /** @type {Map<number, Map<string, Map<string, number>>>} */
524
347
  const KNOWN_PROPERTIES_CACHE = new Map();
525
348
 
526
349
  /**
527
350
  * Memoized {@link buildKnownProperties}: the table depends only on the four
528
- * boolean options (≤16 combinations) and is read-only, while the same parser is
351
+ * boolean options (≤ 16 combinations) and is read-only, while the same parser is
529
352
  * reused across modules — so build each combination once and share it instead
530
- * of rebuilding the Map (and its value objects) per parsed module.
353
+ * of rebuilding the Map per parsed module.
531
354
  * @param {{ animation?: boolean, container?: boolean, customIdents?: boolean, grid?: boolean }=} options options
532
- * @returns {Map<string, Record<string, number>>} known properties table
355
+ * @returns {Map<string, Map<string, number>>} known properties table
533
356
  */
534
357
  const getKnownProperties = (options = {}) => {
535
358
  const key =
@@ -610,6 +433,60 @@ const rangeHasEscape = (input, start, end) => {
610
433
  return false;
611
434
  };
612
435
 
436
+ /**
437
+ * Whether a raw ident range names a custom property — `\2d\2d x` is `--x` too,
438
+ * so a name opening with a dash or a backslash pays the unescape.
439
+ * @param {string} input source
440
+ * @param {number} start ident start offset
441
+ * @param {number} end ident end offset (exclusive)
442
+ * @returns {boolean} true when the ident names a custom property
443
+ */
444
+ const rangeIsDashedIdentifier = (input, start, end) => {
445
+ // `--x` is the shortest spelling; an escaped one is longer still.
446
+ if (end - start < 3) return false;
447
+ const first = input.charCodeAt(start);
448
+ if (first === CC_HYPHEN_MINUS) {
449
+ if (input.charCodeAt(start + 1) === CC_HYPHEN_MINUS) return true;
450
+ if (input.charCodeAt(start + 1) !== CC_REVERSE_SOLIDUS) return false;
451
+ } else if (first !== CC_REVERSE_SOLIDUS) {
452
+ return false;
453
+ }
454
+ return isDashedIdentifier(unescapeIdentifier(input.slice(start, end)));
455
+ };
456
+
457
+ /**
458
+ * The named cell tokens of a `grid-template-areas` string, in source offsets.
459
+ * A whitespace closing a hex escape does not separate; a `.` run names nothing.
460
+ * @param {string} input source
461
+ * @param {number} start content start offset (inside the quote)
462
+ * @param {number} end content end offset (exclusive)
463
+ * @returns {[number, number][]} one `[start, end]` per named cell
464
+ */
465
+ const gridAreaNames = (input, start, end) => {
466
+ /** @type {[number, number][]} */
467
+ const names = [];
468
+ let i = start;
469
+ while (i < end) {
470
+ while (i < end && isWhitespace(input.charCodeAt(i))) i++;
471
+ if (i >= end) break;
472
+ const nameStart = i;
473
+ let nullCell = true;
474
+ while (i < end) {
475
+ const cc = input.charCodeAt(i);
476
+ if (isWhitespace(cc)) break;
477
+ if (cc === CC_REVERSE_SOLIDUS) {
478
+ i = Math.min(skipEscape(input, i), end);
479
+ nullCell = false;
480
+ continue;
481
+ }
482
+ if (cc !== CC_FULL_STOP) nullCell = false;
483
+ i++;
484
+ }
485
+ if (!nullCell) names.push([nameStart, i]);
486
+ }
487
+ return names;
488
+ };
489
+
613
490
  /**
614
491
  * @param {string} input source
615
492
  * @param {number} pos position
@@ -903,10 +780,14 @@ class CssParser extends Parser {
903
780
  const { line: el, column: ec } = locConverter.get(end);
904
781
 
905
782
  state.current.addWarning(
906
- new ModuleDependencyWarning(state.module, new WebpackError(message), {
907
- start: { line: sl, column: sc },
908
- end: { line: el, column: ec }
909
- })
783
+ new (getModuleDependencyWarning())(
784
+ state.module,
785
+ new WebpackError(message),
786
+ {
787
+ start: { line: sl, column: sc },
788
+ end: { line: el, column: ec }
789
+ }
790
+ )
910
791
  );
911
792
  }
912
793
 
@@ -931,6 +812,92 @@ class CssParser extends Parser {
931
812
  state.module.addError(err);
932
813
  }
933
814
 
815
+ /**
816
+ * Arbitrate cross-kind CSS-Modules export collisions collected during
817
+ * parsing. A class always wins the shared JS export key over the
818
+ * CSS-only kinds (`@keyframes`, `@counter-style`, `@container`, custom
819
+ * property, grid identifier) — matching css-loader / lightning css /
820
+ * postcss-modules; the loser's `EXPORT_MODE` is demoted to `NONE` so
821
+ * the CSS-side rewrite is preserved but the entry no longer contributes
822
+ * to `styles.<name>`. Other pairs (`class` ↔ `id`,
823
+ * `class` ↔ `:export`, `class` ↔ `@value`, kind-vs-kind without a
824
+ * class present, …) surface as a warning so the user resolves the name
825
+ * themselves. Same-kind redeclarations are silent.
826
+ * @param {ParserState} state parser state
827
+ * @param {Map<string, { kind: string, line: number, column: number, entries: number[] }[]>} declaredExports collected declarations grouped by (name, kind)
828
+ * @param {import("../dependencies/CssIcssExportDependency").CssExportEntry[]} cssExportEntries all export entries — losers are demoted in place
829
+ * @returns {void}
830
+ */
831
+ _resolveAmbiguousExports(state, declaredExports, cssExportEntries) {
832
+ const NONE = CssIcssExportDependency.EXPORT_MODE.NONE;
833
+ for (const [name, decls] of declaredExports) {
834
+ if (decls.length <= 1) continue;
835
+ // Prefer `class` as the winner (matches css-loader / lightning css / postcss-modules); otherwise the first-declared kind wins de facto.
836
+ let winner;
837
+ for (const d of decls) {
838
+ if (d.kind === "class") {
839
+ winner = d;
840
+ break;
841
+ }
842
+ }
843
+ const reference = winner !== undefined ? winner : decls[0];
844
+ for (const loser of decls) {
845
+ if (loser === reference) continue;
846
+ const anchor = cssExportEntries[loser.entries[0]];
847
+ if (
848
+ winner !== undefined &&
849
+ (loser.kind === "custom property" ||
850
+ loser.kind === "@keyframes" ||
851
+ loser.kind === "@counter-style" ||
852
+ loser.kind === "@container" ||
853
+ loser.kind === "grid identifier")
854
+ ) {
855
+ for (const idx of loser.entries) {
856
+ cssExportEntries[idx].exportMode = NONE;
857
+ }
858
+ state.current.addWarning(
859
+ new (getModuleDependencyWarning())(
860
+ state.module,
861
+ new WebpackError(
862
+ `CSS module export "${name}" is shadowed by ${winner.kind} at line ${winner.line}:${winner.column}: the ${loser.kind} "${name}" is still scoped in the emitted CSS but is not accessible from the JavaScript export — rename one of them if both are needed`
863
+ ),
864
+ {
865
+ start: {
866
+ line: anchor.locStartLine,
867
+ column: anchor.locStartColumn
868
+ },
869
+ end: {
870
+ line: anchor.locEndLine,
871
+ column: anchor.locEndColumn
872
+ }
873
+ }
874
+ )
875
+ );
876
+ } else {
877
+ // Other collision — warn without changing behavior.
878
+ state.current.addWarning(
879
+ new (getModuleDependencyWarning())(
880
+ state.module,
881
+ new WebpackError(
882
+ `Conflicting CSS module export "${name}": already declared as ${reference.kind} at line ${reference.line}:${reference.column}, redeclared as ${loser.kind}`
883
+ ),
884
+ {
885
+ start: {
886
+ line: anchor.locStartLine,
887
+ column: anchor.locStartColumn
888
+ },
889
+ end: {
890
+ line: anchor.locEndLine,
891
+ column: anchor.locEndColumn
892
+ }
893
+ }
894
+ )
895
+ );
896
+ }
897
+ }
898
+ }
899
+ }
900
+
934
901
  /**
935
902
  * Parses the provided source and updates the parser state.
936
903
  * @param {string | Buffer | PreparsedAst} source the source to parse
@@ -990,6 +957,43 @@ class CssParser extends Parser {
990
957
 
991
958
  const module = state.module;
992
959
 
960
+ // Every CSS Modules export declaration is tracked here so `_resolveAmbiguousExports` can arbitrate cross-kind collisions in one pass at end-of-parse: a class silently wins over CSS-scoped kinds (`@keyframes`, `@counter-style`, `@container`, custom property, grid identifier) — matching css-loader / lightning css / postcss-modules — while other pairs (`class` ↔ `id`, `class` ↔ `:export`, `class` ↔ `@value`, …) surface as a warning so the user can resolve them.
961
+ /** @typedef {{ kind: string, line: number, column: number, entries: number[] }} DeclarationOfKind */
962
+ /** @type {Map<string, DeclarationOfKind[]>} */
963
+ const declaredExports = new Map();
964
+
965
+ /**
966
+ * Track a declaration site for later ambiguity resolution. Pointer
967
+ * into `cssExportEntries` is captured now because the entry is
968
+ * pushed immediately after by the calling `addCssExport(…)`.
969
+ * Property-value references (`animation: foo`) are not declarations
970
+ * and skip this hook.
971
+ * @param {string} name export name
972
+ * @param {string} kind human-readable declaration kind
973
+ * @param {number} line start line (1-based) of the declaration
974
+ * @param {number} column start column (0-based) of the declaration
975
+ * @returns {void}
976
+ */
977
+ const recordDeclaration = (name, kind, line, column) => {
978
+ let decls = declaredExports.get(name);
979
+ if (decls === undefined) {
980
+ decls = [];
981
+ declaredExports.set(name, decls);
982
+ }
983
+ let d;
984
+ for (const existing of decls) {
985
+ if (existing.kind === kind) {
986
+ d = existing;
987
+ break;
988
+ }
989
+ }
990
+ if (d === undefined) {
991
+ d = { kind, line, column, entries: [] };
992
+ decls.push(d);
993
+ }
994
+ d.entries.push(cssExportEntries.length);
995
+ };
996
+
993
997
  // All `:export`-style exports are collected into a single
994
998
  // `CssIcssExportDependency` per module (emitted at parse end) instead of one
995
999
  // `Dependency` per export — far fewer retained objects on CSS-heavy builds.
@@ -1156,7 +1160,7 @@ class CssParser extends Parser {
1156
1160
  if (errors) {
1157
1161
  for (const e of errors) {
1158
1162
  state.module.addWarning(
1159
- new CommentCompilationWarning(
1163
+ new (getCommentCompilationWarning())(
1160
1164
  `Compilation error while processing magic comment(-s): /*${e.comment.value}*/: ${e.message}`,
1161
1165
  rangeLoc(e.comment.range[0], e.comment.range[1])
1162
1166
  )
@@ -1169,7 +1173,7 @@ class CssParser extends Parser {
1169
1173
  // Loc is computed lazily here — it's only needed for this rare
1170
1174
  // warning, not on every checked `url()` / `@import`.
1171
1175
  state.module.addWarning(
1172
- new UnsupportedFeatureWarning(
1176
+ new (getUnsupportedFeatureWarning())(
1173
1177
  `\`webpackIgnore\` expected a boolean, but received: ${options.webpackIgnore}.`,
1174
1178
  rangeLoc(warnStart, warnEnd)
1175
1179
  )
@@ -1198,10 +1202,12 @@ class CssParser extends Parser {
1198
1202
  this.options.customMedia && input.includes("@custom-media");
1199
1203
  const mayHaveCustomSelectors =
1200
1204
  this.options.customSelectors && input.includes("@custom-selector");
1201
- /** @type {Map<string, { text: string, kind: ("condition" | "type" | "unsupported") }> | undefined} */
1205
+ /** @type {Map<string, CustomMediaDefinition> | undefined} */
1202
1206
  let customMediaDefs;
1203
- /** @type {{ name: string, start: number, end: number, invalid: boolean, leading: boolean }[] | undefined} */
1204
- let customMediaUses;
1207
+ /** @type {Map<string, CustomMediaValue> | undefined} */
1208
+ let customMediaValues;
1209
+ /** @type {{ queries: MediaNode[], start: number, end: number, uses: CustomMediaUse[] }[] | undefined} */
1210
+ let customMediaQueries;
1205
1211
  /** @type {Map<string, string> | undefined} */
1206
1212
  let customSelectorDefs;
1207
1213
  /** @type {{ name: string, start: number, end: number }[] | undefined} */
@@ -1525,6 +1531,7 @@ class CssParser extends Parser {
1525
1531
  } else if (type === 1) {
1526
1532
  const { line: sl, column: sc } = locConverter.get(start);
1527
1533
  const { line: el, column: ec } = locConverter.get(end);
1534
+ recordDeclaration(name, ":export", sl, sc);
1528
1535
  addCssExport(sl, sc, el, ec, name, getReexport(value));
1529
1536
  }
1530
1537
  };
@@ -1577,8 +1584,9 @@ class CssParser extends Parser {
1577
1584
  * Process a `local(...)` / `global(...)` pseudo-function: strip the call (and a leading legacy `:`) via a presentational dep, then emit `local()`'s inner top-level idents as ICSS exports.
1578
1585
  * @param {FunctionNode} fn parsed local/global function node
1579
1586
  * @param {1 | 2} type 1 = local, 2 = global
1587
+ * @param {string=} declarationKind human-readable export kind to use for conflict tracking when the caller is a declaration site (selector or at-rule prelude). Undefined for property-value references, which are not tracked.
1580
1588
  */
1581
- const processLocalOrGlobalFunction = (fn, type) => {
1589
+ const processLocalOrGlobalFunction = (fn, type, declarationKind) => {
1582
1590
  // Replace `local(` / `global(` (and a leading `:` for the `:local(`/`:global(` selector form) with empty.
1583
1591
  const fnStart = A.start(fn);
1584
1592
  const isColon = input.charCodeAt(fnStart - 1) === CC_COLON;
@@ -1596,6 +1604,14 @@ class CssParser extends Parser {
1596
1604
  const { line: el, column: ec } = locConverter.get(A.end(cv));
1597
1605
  const isDashedIdent = isDashedIdentifier(identifier);
1598
1606
  if (isDashedIdent) identifier = identifier.slice(2);
1607
+ if (declarationKind !== undefined) {
1608
+ recordDeclaration(
1609
+ identifier,
1610
+ isDashedIdent ? "custom property" : declarationKind,
1611
+ sl,
1612
+ sc
1613
+ );
1614
+ }
1599
1615
  addCssExport(
1600
1616
  sl,
1601
1617
  sc,
@@ -1623,9 +1639,10 @@ class CssParser extends Parser {
1623
1639
  * Localize the prelude name of `@keyframes` / `@counter-style` / `@container`: `options.string` takes the first string, `options.identifier` the first ident (a `RegExp` skips matching keywords), `:local()`/`:global()` count as found; top-level `var()`/`style()` dashed idents are always ICSS-processed.
1624
1640
  * @param {AtRule} atRule parsed at-rule
1625
1641
  * @param {{ string?: boolean, identifier?: boolean | RegExp }} options which prelude value kinds count as the local name
1642
+ * @param {string} kind human-readable export kind for the surrounding at-rule (`"@keyframes"`, `"@counter-style"`, `"@container"`)
1626
1643
  * @returns {number} position after handling
1627
1644
  */
1628
- const processLocalAtRule = (atRule, options) => {
1645
+ const processLocalAtRule = (atRule, options, kind) => {
1629
1646
  let found = false;
1630
1647
  for (const cv of A.prelude(atRule)) {
1631
1648
  const cvType = A.type(cv);
@@ -1636,6 +1653,7 @@ class CssParser extends Parser {
1636
1653
  const value = A.unescaped(cv);
1637
1654
  const { line: sl, column: sc } = locConverter.get(A.start(cv));
1638
1655
  const { line: el, column: ec } = locConverter.get(A.end(cv));
1656
+ recordDeclaration(value, kind, sl, sc);
1639
1657
  addCssExport(
1640
1658
  sl,
1641
1659
  sc,
@@ -1664,6 +1682,7 @@ class CssParser extends Parser {
1664
1682
  }
1665
1683
  const { line: sl, column: sc } = locConverter.get(A.start(cv));
1666
1684
  const { line: el, column: ec } = locConverter.get(A.end(cv));
1685
+ recordDeclaration(identifier, kind, sl, sc);
1667
1686
  addCssExport(
1668
1687
  sl,
1669
1688
  sc,
@@ -1693,7 +1712,7 @@ class CssParser extends Parser {
1693
1712
  if (!found && type) {
1694
1713
  found = true;
1695
1714
  if (type === 1) pure.markLocal();
1696
- processLocalOrGlobalFunction(fn, type);
1715
+ processLocalOrGlobalFunction(fn, type, kind);
1697
1716
  continue;
1698
1717
  }
1699
1718
  if (
@@ -1707,15 +1726,29 @@ class CssParser extends Parser {
1707
1726
  }
1708
1727
  return A.end(atRule);
1709
1728
  };
1729
+ /**
1730
+ * The custom property's name, without its `--`. An escaped dash makes the
1731
+ * prefix longer than two bytes, so it comes off the unescaped value.
1732
+ * @param {number} identStart start of the `--<name>` ident
1733
+ * @param {number} identEnd end of the ident
1734
+ * @returns {string} the name after `--`
1735
+ */
1736
+ const dashedIdentName = (identStart, identEnd) =>
1737
+ source.charCodeAt(identStart) === CC_HYPHEN_MINUS &&
1738
+ source.charCodeAt(identStart + 1) === CC_HYPHEN_MINUS
1739
+ ? unescapeRange(identStart + 2, identEnd)
1740
+ : unescapeRange(identStart, identEnd).slice(2);
1741
+
1710
1742
  /**
1711
1743
  * Emit the ICSS export declaring this module exports the given custom property.
1712
1744
  * @param {number} identStart start of the `--<name>` ident
1713
1745
  * @param {number} identEnd end of the ident (exclusive)
1714
1746
  */
1715
1747
  const emitDashedIdentExport = (identStart, identEnd) => {
1716
- const identifier = unescapeRange(identStart + 2, identEnd);
1748
+ const identifier = dashedIdentName(identStart, identEnd);
1717
1749
  const { line: sl, column: sc } = locConverter.get(identStart);
1718
1750
  const { line: el, column: ec } = locConverter.get(identEnd);
1751
+ recordDeclaration(identifier, "custom property", sl, sc);
1719
1752
  addCssExport(
1720
1753
  sl,
1721
1754
  sc,
@@ -1745,7 +1778,7 @@ class CssParser extends Parser {
1745
1778
  sourceEnd,
1746
1779
  pathContent
1747
1780
  ) => {
1748
- const identifier = unescapeRange(identStart + 2, identEnd);
1781
+ const identifier = dashedIdentName(identStart, identEnd);
1749
1782
  const { line: sl, column: sc } = locConverter.get(identStart);
1750
1783
  const { line: el, column: ec } = locConverter.get(sourceEnd - 1);
1751
1784
  const localName = nextIcssImportName();
@@ -1760,6 +1793,7 @@ class CssParser extends Parser {
1760
1793
  importDep.setLoc(sl, sc, el, ec);
1761
1794
  module.addDependency(importDep);
1762
1795
 
1796
+ recordDeclaration(identifier, "custom property", sl, sc);
1763
1797
  addCssExport(
1764
1798
  sl,
1765
1799
  sc,
@@ -1812,16 +1846,7 @@ class CssParser extends Parser {
1812
1846
 
1813
1847
  const identStart = A.start(identNode);
1814
1848
  const identEnd = A.end(identNode);
1815
- // `isDashedIdentifier` on the value without slicing it: a literal `--`
1816
- // prefix of length >= 3 (escaped dashes don't match, same as the string
1817
- // form, since the raw bytes aren't `--`).
1818
- if (
1819
- identEnd - identStart < 3 ||
1820
- input.charCodeAt(identStart) !== CC_HYPHEN_MINUS ||
1821
- input.charCodeAt(identStart + 1) !== CC_HYPHEN_MINUS
1822
- ) {
1823
- return;
1824
- }
1849
+ if (!rangeIsDashedIdentifier(input, identStart, identEnd)) return;
1825
1850
 
1826
1851
  let j = identIdx + 1;
1827
1852
  while (j < fv.length && A.type(fv[j]) === NodeType.Whitespace) {
@@ -1877,18 +1902,25 @@ class CssParser extends Parser {
1877
1902
  active: false,
1878
1903
  /** Should top-level dashed-ident exports be emitted at this nesting level? */
1879
1904
  emit: false,
1880
- /** LIFO save/restore of `active` + `emit` across function nesting, bit-packed (bit 0 = active, bit 1 = emit) to avoid a per-function-token object allocation. */
1905
+ /** Directly inside a `counter()`-family call whose arguments were already rewritten — suppresses the generic ICSS ident rewrite over the same ranges. */
1906
+ counterArgs: false,
1907
+ /** LIFO save/restore of `active` + `emit` + `counterArgs` across function nesting, bit-packed (bit 0 = active, bit 1 = emit, bit 2 = counterArgs) to avoid a per-function-token object allocation. */
1881
1908
  /** @type {number[]} */
1882
1909
  stack: [],
1883
1910
  /** Push the current scope; call before descending into a `Function` body. */
1884
1911
  push() {
1885
- this.stack.push((this.active ? 1 : 0) | (this.emit ? 2 : 0));
1912
+ this.stack.push(
1913
+ (this.active ? 1 : 0) |
1914
+ (this.emit ? 2 : 0) |
1915
+ (this.counterArgs ? 4 : 0)
1916
+ );
1886
1917
  },
1887
1918
  /** Pop the saved scope; call when leaving a `Function` body. */
1888
1919
  pop() {
1889
1920
  const s = /** @type {number} */ (this.stack.pop());
1890
1921
  this.active = (s & 1) !== 0;
1891
1922
  this.emit = (s & 2) !== 0;
1923
+ this.counterArgs = (s & 4) !== 0;
1892
1924
  }
1893
1925
  };
1894
1926
  // Nearest enclosing declaration / at-rule / qualified-rule, set by each structural enter; the Url / Function / Ident / Comma visitors read it (via `urlActive` / `localGlobalActive` / `icssActive`) to decide value handling from the node hierarchy instead of carrying precomputed flags.
@@ -1902,10 +1934,12 @@ class CssParser extends Parser {
1902
1934
  let currentDeclIsKnownProperty = false;
1903
1935
  /** Whether the current `composes:` declaration owns the whole value (suppresses value rewrites). */
1904
1936
  let currentDeclComposesSkip = false;
1937
+ /** Whether `counter()`-family arguments are scoped in the current declaration's value. */
1938
+ let currentDeclCounterActive = false;
1905
1939
 
1906
1940
  /**
1907
1941
  * Per-at-rule scope frames; `exit` reads `hasBlock` to pick the block-cleanup vs `suppressNextRulePrelude` branch.
1908
- * @type {{ savedAnchor: boolean, savedLocalIdentifiers: string[], name: string, hasBlock: boolean, endsWithSemicolon: boolean, fontPreloaded: boolean }[]}
1942
+ * @type {{ savedAnchor: boolean, savedLocalIdentifierCount: number, name: string, hasBlock: boolean, endsWithSemicolon: boolean, fontPreloaded: boolean }[]}
1909
1943
  */
1910
1944
  const atRuleStateStack = [];
1911
1945
 
@@ -2074,6 +2108,71 @@ class CssParser extends Parser {
2074
2108
  }
2075
2109
  };
2076
2110
 
2111
+ /**
2112
+ * Emit the ICSS export for one ident argument of a `counter()`-family call. Dashed names are left to the blanket dashed-ident scanner, and reserved names (UA counters, predefined counter styles, CSS-wide keywords) stay global.
2113
+ * @param {AstNode} node the ident node
2114
+ * @param {string} reservedFrom property whose keywords must not be localized here
2115
+ * @returns {void}
2116
+ */
2117
+ const emitCounterIdent = (node, reservedFrom) => {
2118
+ const name = A.unescaped(node);
2119
+ if (isDashedIdentifier(name)) return;
2120
+ const reserved =
2121
+ /** @type {Map<string, number>} */
2122
+ (CSS_MODULES_KEYWORDS.get(reservedFrom));
2123
+ if (reserved.has(toLowerCaseIfNeeded(name))) return;
2124
+ const start = A.start(node);
2125
+ const end = A.end(node);
2126
+ const { line: sl, column: sc } = locConverter.get(start);
2127
+ const { line: el, column: ec } = locConverter.get(end);
2128
+ addCssExport(
2129
+ sl,
2130
+ sc,
2131
+ el,
2132
+ ec,
2133
+ name,
2134
+ getReexport(name),
2135
+ [start, end],
2136
+ true,
2137
+ CssIcssExportDependency.EXPORT_MODE.ONCE
2138
+ );
2139
+ };
2140
+
2141
+ /**
2142
+ * Scope a `counter()` / `counters()` / `target-counter()` / `target-counters()` call: the counter-name argument localizes like a `counter-reset` value and a trailing `<counter-style>` ident like a `list-style-type` value, so both keep naming the scoped `counter-*` declaration / `@counter-style` rule.
2143
+ * @param {AstNode[]} cvs the call's argument component values
2144
+ * @param {number} nameIndex comma-separated index of the counter-name argument
2145
+ * @returns {void}
2146
+ */
2147
+ const walkCounterFunction = (cvs, nameIndex) => {
2148
+ let group = 0;
2149
+ let groupNodes = 0;
2150
+ /** Sole ident of the current argument, or undefined when the argument isn't a lone ident. */
2151
+ let lastIdent;
2152
+ for (const cv of cvs) {
2153
+ const type = A.type(cv);
2154
+ if (type === NodeType.Whitespace) continue;
2155
+ if (type === NodeType.Comma) {
2156
+ group++;
2157
+ groupNodes = 0;
2158
+ lastIdent = undefined;
2159
+ continue;
2160
+ }
2161
+ groupNodes++;
2162
+ const loneIdent = groupNodes === 1 && type === NodeType.Ident;
2163
+ if (group === nameIndex) {
2164
+ if (loneIdent) emitCounterIdent(cv, "counter-reset");
2165
+ lastIdent = undefined;
2166
+ } else {
2167
+ lastIdent = loneIdent ? cv : undefined;
2168
+ }
2169
+ }
2170
+ // The counter style is the last argument when it's a lone ident (`counter(n, style)` / `counters(n, sep, style)`).
2171
+ if (lastIdent !== undefined && group > nameIndex) {
2172
+ emitCounterIdent(lastIdent, "list-style-type");
2173
+ }
2174
+ };
2175
+
2077
2176
  /**
2078
2177
  * Walk component values as a selector list, emitting ID / attribute deps and recursing into `:not()`/`:is()`/`:local()`/`:global()` wrappers; `localMode` is the sub-tree mode and `topLevel` controls whether commas reset it (only outside parentheses).
2079
2178
  * @param {AstNode[]} values component values to walk
@@ -2182,6 +2281,7 @@ class CssParser extends Parser {
2182
2281
  const idName = A.unescaped(v);
2183
2282
  const { line: idSl, column: idSc } = locConverter.get(A.start(v));
2184
2283
  const { line: idEl, column: idEc } = locConverter.get(A.end(v));
2284
+ recordDeclaration(idName, "id", idSl, idSc);
2185
2285
  addCssExport(
2186
2286
  idSl,
2187
2287
  idSc,
@@ -2224,6 +2324,7 @@ class CssParser extends Parser {
2224
2324
  // Cursor reads instead of `A.loc` — this is the hottest export site.
2225
2325
  const { line: sl, column: sc } = locConverter.get(A.start(next));
2226
2326
  const { line: el, column: ec } = locConverter.get(A.end(next));
2327
+ recordDeclaration(name, "class", sl, sc);
2227
2328
  addCssExport(
2228
2329
  sl,
2229
2330
  sc,
@@ -2267,18 +2368,20 @@ class CssParser extends Parser {
2267
2368
  };
2268
2369
  /**
2269
2370
  * Per-qualified-rule scope frames; `{ bailed: true }` for inline-handled `:import` / `:export` pseudo-rules.
2270
- * @type {({ bailed: true } | { bailed: false, savedAnchor: boolean, savedLocalIdentifiers: string[], savedPrevComposesFile: string | undefined, savedComposesFiles: Set<string> | null })[]}
2371
+ * @type {({ bailed: true } | { bailed: false, savedAnchor: boolean, savedLocalIdentifierCount: number, savedPrevComposesFile: string | undefined, savedComposesFiles: Set<string> | null })[]}
2271
2372
  */
2272
2373
  const qualifiedRuleStateStack = [];
2273
2374
 
2274
2375
  /**
2275
- * Whether url() deps are emitted here (from `currentStructural`): false outside `options.url` and inside an `@import` prelude (the import target, unless url recovery is on).
2376
+ * Whether url() deps are emitted here (from `currentStructural`): off in an `@import`
2377
+ * prelude (the import target, unless recovering) and in `@namespace` (an opaque identifier).
2276
2378
  * @returns {boolean} true when url() deps should be emitted
2277
2379
  */
2278
2380
  const urlActive = () => {
2279
2381
  if (!this.options.url || !currentStructural) return false;
2280
2382
  if (A.type(currentStructural) === NodeType.AtRule) {
2281
2383
  // `currentAtRuleName` is cached on at-rule enter — no per-value slice.
2384
+ if (currentAtRuleName === "@namespace") return false;
2282
2385
  return currentAtRuleName !== "@import" || currentUrlRecovery;
2283
2386
  }
2284
2387
  return true;
@@ -3007,6 +3110,7 @@ class CssParser extends Parser {
3007
3110
  {
3008
3111
  const { line: sl, column: sc } = locConverter.get(start);
3009
3112
  const { line: el, column: ec } = locConverter.get(nameEnd);
3113
+ recordDeclaration(localName, "@value", sl, sc);
3010
3114
  addCssExport(
3011
3115
  sl,
3012
3116
  sc,
@@ -3048,10 +3152,12 @@ class CssParser extends Parser {
3048
3152
 
3049
3153
  icssDefinitions.set(localName, def);
3050
3154
 
3155
+ recordDeclaration(localName, "@value", sl, sc);
3051
3156
  addCssExport(sl, sc, el, ec, localName, getReexport(value));
3052
3157
  } else {
3053
3158
  icssDefinitions.set(localName, { value });
3054
3159
 
3160
+ recordDeclaration(localName, "@value", sl, sc);
3055
3161
  addCssExport(sl, sc, el, ec, localName, value);
3056
3162
  }
3057
3163
  }
@@ -3084,7 +3190,10 @@ class CssParser extends Parser {
3084
3190
  };
3085
3191
 
3086
3192
  /**
3087
- * Collect one `@custom-media --name <value>` definition (last-wins) and drop the rule. Classifies the value: `"condition"` (a media-in-parens, or comma list → `(a or b)`) inlines anywhere; `"type"` (a media type like `screen` / `not all` / `screen and (…)`) inlines only at a query's start; `true` / `false` / nested custom-media values are `"unsupported"` (warned on use — the ecosystem disagrees on these).
3193
+ * Collect one `@custom-media --name <value>` definition (last-wins) and drop
3194
+ * the rule. A value naming another custom media is kept as an `alias` — the
3195
+ * name it points at may be defined further down the file, and node ids are
3196
+ * recycled per top-level rule, so nothing AST-shaped can outlive the walk.
3088
3197
  * @param {AtRule} at the `@custom-media` at-rule
3089
3198
  */
3090
3199
  const collectCustomMedia = (at) => {
@@ -3105,27 +3214,27 @@ class CssParser extends Parser {
3105
3214
  if (!isDashedIdentifier(name)) return;
3106
3215
  i++;
3107
3216
 
3108
- /**
3109
- * @param {string} text resolved text
3110
- * @param {"condition" | "type" | "unsupported"} kind value kind
3111
- */
3112
- const store = (text, kind) => {
3113
- (customMediaDefs || (customMediaDefs = new Map())).set(name, {
3114
- text,
3115
- kind
3116
- });
3117
- };
3118
- const extra = { hasExtra: false };
3119
-
3120
3217
  // Value span after the name, trimmed.
3121
3218
  let vs = i;
3122
3219
  let ve = prelude.length;
3123
3220
  while (vs < ve && A.type(prelude[vs]) === NodeType.Whitespace) vs++;
3124
3221
  while (ve > vs && A.type(prelude[ve - 1]) === NodeType.Whitespace) ve--;
3125
- if (vs >= ve) {
3126
- store("", "unsupported");
3127
- return;
3128
- }
3222
+ (customMediaDefs || (customMediaDefs = new Map())).set(
3223
+ name,
3224
+ classifyCustomMedia(prelude, vs, ve)
3225
+ );
3226
+ };
3227
+
3228
+ /**
3229
+ * Classify one `@custom-media` value against the live AST.
3230
+ * @param {readonly AstNode[]} prelude the defining at-rule's prelude
3231
+ * @param {number} vs first value token
3232
+ * @param {number} ve one past the last value token
3233
+ * @returns {CustomMediaDefinition} what the value is, aliases unresolved
3234
+ */
3235
+ const classifyCustomMedia = (prelude, vs, ve) => {
3236
+ if (vs >= ve) return CUSTOM_MEDIA_UNSUPPORTED;
3237
+ const extra = { hasExtra: false };
3129
3238
 
3130
3239
  let hasComma = false;
3131
3240
  for (let k = vs; k < ve; k++) {
@@ -3138,46 +3247,52 @@ class CssParser extends Parser {
3138
3247
  if (!hasComma) {
3139
3248
  const first = prelude[vs];
3140
3249
  const valueText = input.slice(A.start(first), A.end(prelude[ve - 1]));
3141
- if (A.type(first) === NodeType.SimpleBlock) {
3142
- // A lone `(--x)` is an unresolved nested custom media; anything else is a media-in-parens.
3143
- const nested =
3144
- loneDashedIdentOfBlock(
3145
- /** @type {SimpleBlock} */ (first),
3146
- extra
3147
- ) !== undefined;
3148
- store(nested ? "" : valueText, nested ? "unsupported" : "condition");
3149
- return;
3250
+ // A `(--x)` standing alone is this value spelled as another name.
3251
+ if (ve - vs === 1 && A.type(first) === NodeType.SimpleBlock) {
3252
+ const nested = loneDashedIdentOfBlock(
3253
+ /** @type {SimpleBlock} */ (first),
3254
+ extra
3255
+ );
3256
+ if (nested !== undefined && !extra.hasExtra) {
3257
+ return { kind: "alias", name: nested };
3258
+ }
3150
3259
  }
3151
- if (A.type(first) !== NodeType.Ident) {
3152
- store("", "unsupported");
3153
- return;
3260
+ // A reference anywhere else in the value has no resolution step of its
3261
+ // own — only a `@media` prelude's uses are scanned — so writing this
3262
+ // value out would emit the reference unresolved.
3263
+ if (hasCustomMediaRef(prelude, vs, ve)) return CUSTOM_MEDIA_UNSUPPORTED;
3264
+ if (A.type(first) === NodeType.SimpleBlock) {
3265
+ return { kind: "condition", text: valueText };
3154
3266
  }
3155
- if (
3156
- rangeEqualsLowerCase(input, A.start(first), A.end(first), "true") ||
3157
- rangeEqualsLowerCase(input, A.start(first), A.end(first), "false")
3158
- ) {
3159
- store("", "unsupported");
3160
- return;
3267
+ if (A.type(first) !== NodeType.Ident) return CUSTOM_MEDIA_UNSUPPORTED;
3268
+ const s = A.start(first);
3269
+ const e = A.end(first);
3270
+ if (ve - vs === 1) {
3271
+ if (rangeEqualsLowerCase(input, s, e, "true")) {
3272
+ return CUSTOM_MEDIA_TRUE;
3273
+ }
3274
+ if (rangeEqualsLowerCase(input, s, e, "false")) {
3275
+ return CUSTOM_MEDIA_FALSE;
3276
+ }
3161
3277
  }
3162
- if (rangeEqualsLowerCase(input, A.start(first), A.end(first), "not")) {
3163
- // `not (…)` is a media condition (wrap so it stays a media-in-parens); `not <type>` is a media type.
3278
+ if (rangeEqualsLowerCase(input, s, e, "not")) {
3279
+ // `not (…)` is a media condition (wrap so it stays a media-in-parens);
3280
+ // `not <type>` is a media type.
3164
3281
  let j = vs + 1;
3165
3282
  while (j < ve && A.type(prelude[j]) === NodeType.Whitespace) j++;
3166
3283
  if (j < ve && A.type(prelude[j]) === NodeType.SimpleBlock) {
3167
- store(`(${valueText})`, "condition");
3168
- } else {
3169
- store(valueText, "type");
3284
+ return { kind: "condition", text: `(${valueText})` };
3170
3285
  }
3171
- return;
3286
+ return { kind: "type", text: valueText };
3172
3287
  }
3173
3288
  // `screen`, `only screen`, `screen and (…)`, …
3174
- store(valueText, "type");
3175
- return;
3289
+ return { kind: "type", text: valueText };
3176
3290
  }
3177
3291
 
3178
- // Comma list → `(seg1 or seg2 …)`; supported only when every segment is a media-in-parens.
3179
- /** @type {string[]} */
3180
- const segments = [];
3292
+ // Comma list → `(seg1 or seg2 …)`; supported only when every segment is a
3293
+ // media-in-parens (or a name standing for one).
3294
+ /** @type {({ text: string } | { alias: string })[]} */
3295
+ const parts = [];
3181
3296
  let ok = true;
3182
3297
  /** @type {AstNode[]} */
3183
3298
  let seg = [];
@@ -3192,21 +3307,25 @@ class CssParser extends Parser {
3192
3307
  }
3193
3308
  const f = seg[a];
3194
3309
  const text = input.slice(A.start(f), A.end(seg[b - 1]));
3310
+ if (b - a === 1 && A.type(f) === NodeType.SimpleBlock) {
3311
+ const nested = loneDashedIdentOfBlock(
3312
+ /** @type {SimpleBlock} */ (f),
3313
+ extra
3314
+ );
3315
+ if (extra.hasExtra) ok = false;
3316
+ else if (nested === undefined) parts.push({ text });
3317
+ else parts.push({ alias: nested });
3318
+ return;
3319
+ }
3195
3320
  if (
3196
- b - a === 1 &&
3197
- A.type(f) === NodeType.SimpleBlock &&
3198
- loneDashedIdentOfBlock(/** @type {SimpleBlock} */ (f), extra) ===
3199
- undefined
3200
- ) {
3201
- segments.push(text);
3202
- } else if (
3203
3321
  A.type(f) === NodeType.Ident &&
3204
- rangeEqualsLowerCase(input, A.start(f), A.end(f), "not")
3322
+ rangeEqualsLowerCase(input, A.start(f), A.end(f), "not") &&
3323
+ !hasCustomMediaRef(seg, a, b)
3205
3324
  ) {
3206
- segments.push(`(${text})`);
3207
- } else {
3208
- ok = false;
3325
+ parts.push({ text: `(${text})` });
3326
+ return;
3209
3327
  }
3328
+ ok = false;
3210
3329
  };
3211
3330
  for (let k = vs; k < ve; k++) {
3212
3331
  if (A.type(prelude[k]) === NodeType.Comma) {
@@ -3217,54 +3336,386 @@ class CssParser extends Parser {
3217
3336
  }
3218
3337
  }
3219
3338
  flush();
3220
- if (ok && segments.length > 0) {
3221
- store(
3222
- segments.length === 1 ? segments[0] : `(${segments.join(" or ")})`,
3223
- "condition"
3224
- );
3339
+ return ok ? { kind: "or", parts } : CUSTOM_MEDIA_UNSUPPORTED;
3340
+ };
3341
+
3342
+ /**
3343
+ * What a `@custom-media` name resolves to, memoized. An undefined name and a
3344
+ * definition cycle both resolve to unsupported (the use site warns).
3345
+ * @param {string} name the dashed ident
3346
+ * @param {Set<string>} resolving names currently being resolved
3347
+ * @returns {CustomMediaValue} what the name resolves to
3348
+ */
3349
+ const resolveCustomMediaValue = (name, resolving) => {
3350
+ const cached = customMediaValues && customMediaValues.get(name);
3351
+ if (cached !== undefined) return cached;
3352
+ const def = customMediaDefs && customMediaDefs.get(name);
3353
+ if (def === undefined || resolving.has(name)) {
3354
+ return CUSTOM_MEDIA_UNSUPPORTED;
3355
+ }
3356
+ resolving.add(name);
3357
+ /** @type {CustomMediaValue} */
3358
+ let value;
3359
+ if (def.kind === "alias") {
3360
+ const inner = resolveCustomMediaValue(def.name, resolving);
3361
+ // A media type cannot sit in parens, so a name standing for one is no value.
3362
+ value = inner.kind === "type" ? CUSTOM_MEDIA_UNSUPPORTED : inner;
3363
+ } else if (def.kind === "or") {
3364
+ /** @type {string[]} */
3365
+ const texts = [];
3366
+ let ok = true;
3367
+ let anyTrue = false;
3368
+ for (const part of def.parts) {
3369
+ if (!("alias" in part)) {
3370
+ texts.push(part.text);
3371
+ continue;
3372
+ }
3373
+ const inner = resolveCustomMediaValue(part.alias, resolving);
3374
+ // A media query list is an `or`, so a constant segment drops out of it.
3375
+ if (inner.kind === "boolean") anyTrue = anyTrue || inner.value;
3376
+ else if (inner.kind === "condition") texts.push(inner.text);
3377
+ else ok = false;
3378
+ }
3379
+ value = !ok
3380
+ ? CUSTOM_MEDIA_UNSUPPORTED
3381
+ : anyTrue
3382
+ ? CUSTOM_MEDIA_TRUE
3383
+ : texts.length === 0
3384
+ ? CUSTOM_MEDIA_FALSE
3385
+ : {
3386
+ kind: "condition",
3387
+ text:
3388
+ texts.length === 1 ? texts[0] : `(${texts.join(" or ")})`
3389
+ };
3225
3390
  } else {
3226
- store("", "unsupported");
3391
+ value = def;
3227
3392
  }
3393
+ resolving.delete(name);
3394
+ (customMediaValues || (customMediaValues = new Map())).set(name, value);
3395
+ return value;
3228
3396
  };
3229
3397
 
3230
3398
  /**
3231
- * Record every `(--name)` custom-media reference in a media prelude (recursing into nested groups/functions) for post-walk resolution; `invalid` flags a non-boolean-context use like `(--name: 1px)`, `leading` marks a reference that is the first term of a top-level query (the only spot a media-type value may be inlined).
3232
- * @param {readonly AstNode[]} tokens prelude (or nested block) tokens
3233
- * @param {boolean} topLevel whether `tokens` is the media prelude itself (vs. a nested group)
3399
+ * Whether a node is the media keyword `word` (media queries are ASCII
3400
+ * case-insensitive).
3401
+ * @param {AstNode} node candidate node
3402
+ * @param {string} word lower-case keyword
3403
+ * @returns {boolean} true on a match
3234
3404
  */
3235
- const scanCustomMediaUses = (tokens, topLevel) => {
3236
- const extra = { hasExtra: false };
3237
- let leading = true;
3238
- for (const t of tokens) {
3239
- const tt = A.type(t);
3240
- if (tt === NodeType.Whitespace) continue;
3241
- if (topLevel && tt === NodeType.Comma) {
3242
- leading = true;
3405
+ const isMediaKeyword = (node, word) =>
3406
+ A.type(node) === NodeType.Ident &&
3407
+ rangeEqualsLowerCase(input, A.start(node), A.end(node), word);
3408
+
3409
+ /**
3410
+ * First significant index in `tokens[from…to)`.
3411
+ * @param {readonly AstNode[]} tokens token list
3412
+ * @param {number} from first index
3413
+ * @param {number} to one past the last index
3414
+ * @returns {number} the trimmed start
3415
+ */
3416
+ const mediaTrimStart = (tokens, from, to) => {
3417
+ let a = from;
3418
+ while (a < to && A.type(tokens[a]) === NodeType.Whitespace) a++;
3419
+ return a;
3420
+ };
3421
+
3422
+ /**
3423
+ * One past the last significant index in `tokens[from…to)`.
3424
+ * @param {readonly AstNode[]} tokens token list
3425
+ * @param {number} from first index
3426
+ * @param {number} to one past the last index
3427
+ * @returns {number} the trimmed end
3428
+ */
3429
+ const mediaTrimEnd = (tokens, from, to) => {
3430
+ let b = to;
3431
+ while (b > from && A.type(tokens[b - 1]) === NodeType.Whitespace) b--;
3432
+ return b;
3433
+ };
3434
+
3435
+ /**
3436
+ * The source text spanned by `tokens[from…to)`.
3437
+ * @param {readonly AstNode[]} tokens token list
3438
+ * @param {number} from first index
3439
+ * @param {number} to one past the last index
3440
+ * @returns {string} the source slice
3441
+ */
3442
+ const mediaText = (tokens, from, to) =>
3443
+ input.slice(A.start(tokens[from]), A.end(tokens[to - 1]));
3444
+
3445
+ // One flag object for the whole parse: `loneDashedIdentOfBlock` writes it and
3446
+ // every caller reads it back before the next call.
3447
+ const mediaExtra = { hasExtra: false };
3448
+
3449
+ /**
3450
+ * Whether any `(--name)` reference is reachable inside `node`. `childAt` walks
3451
+ * the children without materializing the list.
3452
+ * @param {AstNode} node a block or function node
3453
+ * @returns {boolean} true when a reference is present
3454
+ */
3455
+ const hasCustomMediaRefIn = (node) => {
3456
+ const count = A.childCount(node);
3457
+ for (let k = 0; k < count; k++) {
3458
+ const child = A.childAt(node, k);
3459
+ const type = A.type(child);
3460
+ if (type !== NodeType.SimpleBlock && type !== NodeType.Function) {
3243
3461
  continue;
3244
3462
  }
3245
- if (tt === NodeType.SimpleBlock) {
3246
- const name = loneDashedIdentOfBlock(
3247
- /** @type {SimpleBlock} */ (t),
3248
- extra
3249
- );
3250
- if (name !== undefined) {
3251
- (customMediaUses || (customMediaUses = [])).push({
3252
- name,
3253
- start: A.start(t),
3254
- end: A.end(t),
3255
- invalid: extra.hasExtra,
3256
- leading: Boolean(topLevel && leading)
3257
- });
3258
- } else {
3259
- scanCustomMediaUses(A.children(t), false);
3463
+ if (
3464
+ type === NodeType.SimpleBlock &&
3465
+ loneDashedIdentOfBlock(
3466
+ /** @type {SimpleBlock} */ (child),
3467
+ mediaExtra
3468
+ ) !== undefined
3469
+ ) {
3470
+ return true;
3471
+ }
3472
+ if (hasCustomMediaRefIn(child)) return true;
3473
+ }
3474
+ return false;
3475
+ };
3476
+
3477
+ /**
3478
+ * Whether any `(--name)` reference is reachable in `tokens[from…to)`. Cheap
3479
+ * enough to run over every `@media` prelude so one without a reference builds
3480
+ * no tree at all.
3481
+ * @param {readonly AstNode[]} tokens token list
3482
+ * @param {number} from first index
3483
+ * @param {number} to one past the last index
3484
+ * @returns {boolean} true when a reference is present
3485
+ */
3486
+ const hasCustomMediaRef = (tokens, from, to) => {
3487
+ for (let i = from; i < to; i++) {
3488
+ const node = tokens[i];
3489
+ const type = A.type(node);
3490
+ if (type !== NodeType.SimpleBlock && type !== NodeType.Function) {
3491
+ continue;
3492
+ }
3493
+ if (
3494
+ type === NodeType.SimpleBlock &&
3495
+ loneDashedIdentOfBlock(
3496
+ /** @type {SimpleBlock} */ (node),
3497
+ mediaExtra
3498
+ ) !== undefined
3499
+ ) {
3500
+ return true;
3501
+ }
3502
+ if (hasCustomMediaRefIn(node)) return true;
3503
+ }
3504
+ return false;
3505
+ };
3506
+
3507
+ /**
3508
+ * Capture one `<media-in-parens>` — a reference to a custom media name, a
3509
+ * parenthesised sub-condition, or an opaque feature test.
3510
+ * @param {readonly AstNode[]} tokens token list
3511
+ * @param {number} from first index
3512
+ * @param {number} to one past the last index
3513
+ * @param {boolean} leading whether the term starts a top-level query
3514
+ * @param {CustomMediaUse[]} uses the prelude's use list, appended to
3515
+ * @returns {MediaNode} the captured term
3516
+ */
3517
+ const captureMediaInParens = (tokens, from, to, leading, uses) => {
3518
+ const a = mediaTrimStart(tokens, from, to);
3519
+ const b = mediaTrimEnd(tokens, a, to);
3520
+ if (a >= b) return { kind: "text", text: "" };
3521
+ const text = mediaText(tokens, a, b);
3522
+ if (b - a !== 1 || A.type(tokens[a]) !== NodeType.SimpleBlock) {
3523
+ return { kind: "text", text };
3524
+ }
3525
+ const block = /** @type {SimpleBlock} */ (tokens[a]);
3526
+ const name = loneDashedIdentOfBlock(block, mediaExtra);
3527
+ if (name !== undefined) {
3528
+ const use = {
3529
+ name,
3530
+ start: A.start(block),
3531
+ end: A.end(block),
3532
+ invalid: mediaExtra.hasExtra,
3533
+ leading
3534
+ };
3535
+ uses.push(use);
3536
+ return { kind: "ref", text, use };
3537
+ }
3538
+ const children = A.children(block);
3539
+ const inner = captureMediaCondition(children, 0, children.length, uses);
3540
+ return inner.kind === "text"
3541
+ ? { kind: "text", text }
3542
+ : { kind: "group", operand: inner };
3543
+ };
3544
+
3545
+ /**
3546
+ * Capture a `<media-condition>` — `not <in-parens>`, or an `and` / `or` chain
3547
+ * of them (CSS never mixes the two at one level).
3548
+ * @param {readonly AstNode[]} tokens token list
3549
+ * @param {number} from first index
3550
+ * @param {number} to one past the last index
3551
+ * @param {CustomMediaUse[]} uses the prelude's use list, appended to
3552
+ * @returns {MediaNode} the captured condition
3553
+ */
3554
+ const captureMediaCondition = (tokens, from, to, uses) => {
3555
+ const a = mediaTrimStart(tokens, from, to);
3556
+ const b = mediaTrimEnd(tokens, a, to);
3557
+ if (a >= b) return { kind: "text", text: "" };
3558
+ if (isMediaKeyword(tokens[a], "not")) {
3559
+ return {
3560
+ kind: "not",
3561
+ operand: captureMediaInParens(tokens, a + 1, b, false, uses)
3562
+ };
3563
+ }
3564
+ /** @type {MediaNode[]} */
3565
+ const terms = [];
3566
+ let isOr = false;
3567
+ let start = a;
3568
+ for (let i = a; i <= b; i++) {
3569
+ const atEnd = i === b;
3570
+ if (
3571
+ !atEnd &&
3572
+ !isMediaKeyword(tokens[i], "and") &&
3573
+ !isMediaKeyword(tokens[i], "or")
3574
+ ) {
3575
+ continue;
3576
+ }
3577
+ if (!atEnd && isMediaKeyword(tokens[i], "or")) isOr = true;
3578
+ terms.push(captureMediaInParens(tokens, start, i, start === a, uses));
3579
+ start = i + 1;
3580
+ }
3581
+ if (terms.length === 1) return terms[0];
3582
+ return { kind: "chain", isOr, terms };
3583
+ };
3584
+
3585
+ /**
3586
+ * Capture one `<media-query>` — a bare condition, or a media type with an
3587
+ * optional `and` chain after it.
3588
+ * @param {readonly AstNode[]} tokens token list
3589
+ * @param {number} from first index
3590
+ * @param {number} to one past the last index
3591
+ * @param {CustomMediaUse[]} uses the prelude's use list, appended to
3592
+ * @returns {MediaNode} the captured query
3593
+ */
3594
+ const captureMediaQuery = (tokens, from, to, uses) => {
3595
+ const a = mediaTrimStart(tokens, from, to);
3596
+ const b = mediaTrimEnd(tokens, a, to);
3597
+ if (a >= b) return { kind: "text", text: "" };
3598
+ const rest = mediaTrimStart(tokens, a + 1, b);
3599
+ const startsWithType =
3600
+ A.type(tokens[a]) === NodeType.Ident &&
3601
+ (!isMediaKeyword(tokens[a], "not") ||
3602
+ rest >= b ||
3603
+ A.type(tokens[rest]) !== NodeType.SimpleBlock);
3604
+ if (!startsWithType) return captureMediaCondition(tokens, a, b, uses);
3605
+ // `[not | only]? <type> [and <condition-without-or>]?` — the type itself is
3606
+ // never constant, so only the `and` chain after it can fold.
3607
+ let split = b;
3608
+ for (let i = a; i < b; i++) {
3609
+ if (isMediaKeyword(tokens[i], "and")) {
3610
+ split = i;
3611
+ break;
3612
+ }
3613
+ }
3614
+ return {
3615
+ kind: "typed",
3616
+ text: mediaText(tokens, a, mediaTrimEnd(tokens, a, split)),
3617
+ rest:
3618
+ split === b ? null : captureMediaCondition(tokens, split + 1, b, uses)
3619
+ };
3620
+ };
3621
+
3622
+ /**
3623
+ * Record one `@media` prelude, the custom-media references inside it, and the
3624
+ * boolean shape needed to fold it once the references resolve.
3625
+ * @param {AtRule} at the `@media` at-rule
3626
+ */
3627
+ const collectMediaQuery = (at) => {
3628
+ const prelude = A.prelude(at);
3629
+ const start = mediaTrimStart(prelude, 0, prelude.length);
3630
+ const end = mediaTrimEnd(prelude, start, prelude.length);
3631
+ if (start >= end || !hasCustomMediaRef(prelude, start, end)) return;
3632
+ /** @type {CustomMediaUse[]} */
3633
+ const uses = [];
3634
+ /** @type {MediaNode[]} */
3635
+ const queries = [];
3636
+ let queryStart = start;
3637
+ for (let i = start; i <= end; i++) {
3638
+ if (i !== end && A.type(prelude[i]) !== NodeType.Comma) continue;
3639
+ queries.push(captureMediaQuery(prelude, queryStart, i, uses));
3640
+ queryStart = i + 1;
3641
+ }
3642
+ if (uses.length === 0) return;
3643
+ (customMediaQueries || (customMediaQueries = [])).push({
3644
+ queries,
3645
+ start: A.start(prelude[start]),
3646
+ end: A.end(prelude[end - 1]),
3647
+ uses
3648
+ });
3649
+ };
3650
+
3651
+ /**
3652
+ * Fold a captured media node against the resolved definitions. A reference the
3653
+ * resolver could not classify keeps its source text, so it prints as authored.
3654
+ * @param {MediaNode} node the captured node
3655
+ * @param {Set<string>} resolving names currently being resolved
3656
+ * @returns {boolean | string} the constant, or the node's text
3657
+ */
3658
+ const foldMediaNode = (node, resolving) => {
3659
+ switch (node.kind) {
3660
+ case "text":
3661
+ return node.text;
3662
+ case "ref": {
3663
+ const value = resolveCustomMediaValue(node.use.name, resolving);
3664
+ if (node.use.invalid) return node.text;
3665
+ if (value.kind === "boolean") return value.value;
3666
+ if (value.kind === "condition") return value.text;
3667
+ if (value.kind === "type" && node.use.leading) return value.text;
3668
+ return node.text;
3669
+ }
3670
+ case "group": {
3671
+ const inner = foldMediaNode(node.operand, resolving);
3672
+ return typeof inner === "boolean" ? inner : `(${inner})`;
3673
+ }
3674
+ case "not": {
3675
+ const operand = foldMediaNode(node.operand, resolving);
3676
+ return typeof operand === "boolean" ? !operand : `not ${operand}`;
3677
+ }
3678
+ case "chain": {
3679
+ /** @type {string[]} */
3680
+ const kept = [];
3681
+ for (const term of node.terms) {
3682
+ const folded = foldMediaNode(term, resolving);
3683
+ if (folded === node.isOr) return node.isOr;
3684
+ if (typeof folded !== "boolean") kept.push(folded);
3260
3685
  }
3261
- } else if (tt === NodeType.Function) {
3262
- scanCustomMediaUses(A.children(t), false);
3686
+ if (kept.length === 0) return !node.isOr;
3687
+ if (kept.length === 1) return kept[0];
3688
+ return kept.join(node.isOr ? " or " : " and ");
3689
+ }
3690
+ default: {
3691
+ if (node.rest === null) return node.text;
3692
+ const rest = foldMediaNode(node.rest, resolving);
3693
+ if (rest === false) return false;
3694
+ if (rest === true) return node.text;
3695
+ return `${node.text} and ${rest}`;
3263
3696
  }
3264
- if (topLevel) leading = false;
3265
3697
  }
3266
3698
  };
3267
3699
 
3700
+ /**
3701
+ * Fold a whole `@media` prelude. A query that is always false leaves the list;
3702
+ * one that is always true makes the list match everywhere (`all`), and a list
3703
+ * with nothing left matches nowhere (`not all`).
3704
+ * @param {MediaNode[]} queries the prelude's captured queries
3705
+ * @param {Set<string>} resolving names currently being resolved
3706
+ * @returns {string} the folded prelude
3707
+ */
3708
+ const foldMediaPrelude = (queries, resolving) => {
3709
+ /** @type {string[]} */
3710
+ const kept = [];
3711
+ for (const query of queries) {
3712
+ const folded = foldMediaNode(query, resolving);
3713
+ if (folded === true) return "all";
3714
+ if (folded !== false && folded !== "") kept.push(folded);
3715
+ }
3716
+ return kept.length === 0 ? "not all" : kept.join(", ");
3717
+ };
3718
+
3268
3719
  /**
3269
3720
  * Collect one `@custom-selector :--name <selector-list>` definition (last-wins) and drop the rule.
3270
3721
  * @param {AtRule} at the `@custom-selector` at-rule
@@ -3328,55 +3779,71 @@ class CssParser extends Parser {
3328
3779
  };
3329
3780
 
3330
3781
  /**
3331
- * Rewrite the collected `@custom-media` / `@custom-selector` uses now that all (possibly later-defined) definitions are known; warns on invalid, unknown, or unsupported custom-media uses.
3782
+ * Rewrite the collected `@custom-media` / `@custom-selector` uses now that all (possibly later-defined) definitions are known; warns on invalid, unknown, or media-type-in-a-non-leading-position custom-media uses.
3332
3783
  */
3333
3784
  const resolveCustomMediaAndSelectors = () => {
3334
- if (customMediaUses) {
3335
- for (const use of customMediaUses) {
3336
- if (use.invalid) {
3337
- this._emitWarning(
3338
- state,
3339
- `Custom media query '${use.name}' must be used in a boolean context`,
3340
- locConverter,
3341
- use.start,
3342
- use.end
3343
- );
3344
- continue;
3345
- }
3346
- const def = customMediaDefs && customMediaDefs.get(use.name);
3347
- if (!def) {
3348
- this._emitWarning(
3349
- state,
3350
- `Unknown custom media query '${use.name}'`,
3351
- locConverter,
3352
- use.start,
3353
- use.end
3354
- );
3355
- continue;
3785
+ if (customMediaQueries) {
3786
+ /** @type {Set<string>} */
3787
+ const resolving = new Set();
3788
+ for (const query of customMediaQueries) {
3789
+ let hasBoolean = false;
3790
+ for (const use of query.uses) {
3791
+ if (use.invalid) {
3792
+ this._emitWarning(
3793
+ state,
3794
+ `Custom media query '${use.name}' must be used in a boolean context`,
3795
+ locConverter,
3796
+ use.start,
3797
+ use.end
3798
+ );
3799
+ continue;
3800
+ }
3801
+ const value = resolveCustomMediaValue(use.name, resolving);
3802
+ if (value.kind === "unsupported") {
3803
+ this._emitWarning(
3804
+ state,
3805
+ customMediaDefs && customMediaDefs.has(use.name)
3806
+ ? `Custom media query '${use.name}' has a value that cannot be resolved and was left as written`
3807
+ : `Unknown custom media query '${use.name}'`,
3808
+ locConverter,
3809
+ use.start,
3810
+ use.end
3811
+ );
3812
+ } else if (value.kind === "boolean") {
3813
+ hasBoolean = true;
3814
+ } else if (value.kind === "type" && !use.leading) {
3815
+ this._emitWarning(
3816
+ state,
3817
+ `Custom media query '${use.name}' resolves to a media type and can only be used at the start of a media query`,
3818
+ locConverter,
3819
+ use.start,
3820
+ use.end
3821
+ );
3822
+ }
3356
3823
  }
3357
- if (def.kind === "unsupported") {
3358
- this._emitWarning(
3359
- state,
3360
- `Custom media query '${use.name}' uses an unsupported value ('true'/'false' or a nested custom media) and was left unresolved`,
3361
- locConverter,
3362
- use.start,
3363
- use.end
3824
+ // `true` / `false` have no `<media-in-parens>` spelling, so a prelude
3825
+ // holding one is rewritten whole — every other use in it folds with it.
3826
+ if (hasBoolean) {
3827
+ module.addPresentationalDependency(
3828
+ new ConstDependency(foldMediaPrelude(query.queries, resolving), [
3829
+ query.start,
3830
+ query.end
3831
+ ])
3364
3832
  );
3365
3833
  continue;
3366
3834
  }
3367
- if (def.kind === "type" && !use.leading) {
3368
- this._emitWarning(
3369
- state,
3370
- `Custom media query '${use.name}' resolves to a media type and can only be used at the start of a media query`,
3371
- locConverter,
3372
- use.start,
3373
- use.end
3374
- );
3375
- continue;
3835
+ for (const use of query.uses) {
3836
+ if (use.invalid) continue;
3837
+ const value = resolveCustomMediaValue(use.name, resolving);
3838
+ if (
3839
+ value.kind === "condition" ||
3840
+ (value.kind === "type" && use.leading)
3841
+ ) {
3842
+ module.addPresentationalDependency(
3843
+ new ConstDependency(value.text, [use.start, use.end])
3844
+ );
3845
+ }
3376
3846
  }
3377
- module.addPresentationalDependency(
3378
- new ConstDependency(def.text, [use.start, use.end])
3379
- );
3380
3847
  }
3381
3848
  }
3382
3849
  if (customSelectorUses) {
@@ -3400,10 +3867,13 @@ class CssParser extends Parser {
3400
3867
  /** @type {Record<string, number>} */
3401
3868
  let parsedKeywords = Object.create(null);
3402
3869
  const isGridProperty = Boolean(declPropertyName.startsWith("grid"));
3403
- // Only `view-transition-*` legitimately takes a dashed-ident value; other known properties keep the historical plain-ident handling.
3870
+ // Only `view-transition-*` and `counter-*` legitimately take a dashed-ident value; other known properties keep the historical plain-ident handling.
3404
3871
  const isViewTransitionProperty = Boolean(
3405
3872
  declPropertyName.startsWith("view-transition")
3406
3873
  );
3874
+ const isCounterProperty = Boolean(
3875
+ declPropertyName.startsWith("counter-")
3876
+ );
3407
3877
  const isGridTemplate = isGridProperty
3408
3878
  ? Boolean(
3409
3879
  declPropertyName === "grid" ||
@@ -3413,7 +3883,7 @@ class CssParser extends Parser {
3413
3883
  )
3414
3884
  : false;
3415
3885
  const keywords =
3416
- /** @type {Record<string, number>} */
3886
+ /** @type {Map<string, number>} */
3417
3887
  (knownProperties.get(declPropertyName));
3418
3888
  let afterExclamation = false;
3419
3889
  /**
@@ -3430,6 +3900,8 @@ class CssParser extends Parser {
3430
3900
  isString ? start + 1 : start,
3431
3901
  isString ? end - 1 : end
3432
3902
  );
3903
+ // Only grid-line names are declaration sites here; property-value references (`animation: foo`) are usages.
3904
+ if (isGridProperty) recordDeclaration(name, "grid identifier", sl, sc);
3433
3905
  addCssExport(
3434
3906
  sl,
3435
3907
  sc,
@@ -3463,8 +3935,11 @@ class CssParser extends Parser {
3463
3935
  break;
3464
3936
  }
3465
3937
  const identifier = A.value(cv);
3466
- // `view-transition-name: --foo` — a dashed name scopes as a custom property under `dashedIdents`, not as a plain ident export.
3467
- if (isViewTransitionProperty && isDashedIdentifier(identifier)) {
3938
+ // `view-transition-name: --foo` / `counter-reset: --foo` — a dashed name scopes as a custom property under `dashedIdents`, not as a plain ident export.
3939
+ if (
3940
+ (isViewTransitionProperty || isCounterProperty) &&
3941
+ isDashedIdentifier(identifier)
3942
+ ) {
3468
3943
  if (this.options.dashedIdents) {
3469
3944
  emitDashedIdentExport(A.start(cv), A.end(cv));
3470
3945
  }
@@ -3476,10 +3951,8 @@ class CssParser extends Parser {
3476
3951
  typeof parsedKeywords[keyword] !== "undefined"
3477
3952
  ? parsedKeywords[keyword] + 1
3478
3953
  : 0;
3479
- if (
3480
- keywords[keyword] &&
3481
- parsedKeywords[keyword] < keywords[keyword]
3482
- ) {
3954
+ const limit = keywords.get(keyword);
3955
+ if (limit !== undefined && parsedKeywords[keyword] < limit) {
3483
3956
  break;
3484
3957
  }
3485
3958
  emit(A.start(cv), A.end(cv));
@@ -3497,11 +3970,15 @@ class CssParser extends Parser {
3497
3970
  declPropertyName === "grid-template" ||
3498
3971
  declPropertyName === "grid-template-areas"
3499
3972
  ) {
3500
- const areas = A.unescaped(cv);
3501
- const matches = matchAll(/\b\w+\b/g, areas);
3502
- for (const match of matches) {
3503
- const areaStart = A.start(cv) + 1 + match.index;
3504
- emit(areaStart, areaStart + match[0].length, false);
3973
+ // Raw offsets: a match index into the unescaped text would
3974
+ // slide the replaced range past every escape before it.
3975
+ const names = gridAreaNames(
3976
+ source,
3977
+ A.start(cv) + 1,
3978
+ A.end(cv) - 1
3979
+ );
3980
+ for (const [nameStart, nameEnd] of names) {
3981
+ emit(nameStart, nameEnd, false);
3505
3982
  }
3506
3983
  }
3507
3984
  break;
@@ -3521,7 +3998,12 @@ class CssParser extends Parser {
3521
3998
  break;
3522
3999
  }
3523
4000
  case NodeType.Function:
3524
- if (isGridTemplate) {
4001
+ // `repeat(…)` line names, and the `counter-reset: reversed(name)` wrapper — but not `local()`/`global()`, whose idents the value visitors own.
4002
+ if (
4003
+ isGridTemplate ||
4004
+ (isCounterProperty &&
4005
+ equalsLowerCase(A.unescapedName(cv), "reversed"))
4006
+ ) {
3525
4007
  walkExports(A.children(cv));
3526
4008
  }
3527
4009
  break;
@@ -3588,13 +4070,10 @@ class CssParser extends Parser {
3588
4070
  currentUrlRecovery = false;
3589
4071
  advanceCommentCursor(A.start(at));
3590
4072
  const savedAnchor = currentRule.hasLocalAnchor;
3591
- const savedLocalIdentifiers = currentRule.localIdentifiers;
3592
- // Only modules-mode walks mutate `localIdentifiers`; otherwise share
3593
- // the (empty) parent list instead of copying it per rule.
3594
- currentRule.localIdentifiers = isModules
3595
- ? [...savedLocalIdentifiers]
3596
- : savedLocalIdentifiers;
3597
- const name = `@${toLowerCaseIfNeeded(A.name(at))}`;
4073
+ // Rollback point: nested walks append to the shared list; the exit
4074
+ // truncates back to this length (no per-rule copy).
4075
+ const savedLocalIdentifierCount = currentRule.localIdentifiers.length;
4076
+ const name = `@${toLowerCaseIfNeeded(A.unescapedName(at))}`;
3598
4077
  switch (name) {
3599
4078
  case "@namespace": {
3600
4079
  this._emitWarning(
@@ -3638,7 +4117,7 @@ class CssParser extends Parser {
3638
4117
  break;
3639
4118
  }
3640
4119
  case "@media": {
3641
- if (mayHaveCustomMedia) scanCustomMediaUses(A.prelude(at), true);
4120
+ if (mayHaveCustomMedia) collectMediaQuery(at);
3642
4121
  break;
3643
4122
  }
3644
4123
  default: {
@@ -3650,21 +4129,33 @@ class CssParser extends Parser {
3650
4129
  this.options.animation &&
3651
4130
  OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE.test(name)
3652
4131
  ) {
3653
- processLocalAtRule(at, {
3654
- string: mode === "local",
3655
- identifier: mode === "local"
3656
- });
4132
+ processLocalAtRule(
4133
+ at,
4134
+ {
4135
+ string: mode === "local",
4136
+ identifier: mode === "local"
4137
+ },
4138
+ "@keyframes"
4139
+ );
3657
4140
  } else if (
3658
4141
  this.options.customIdents &&
3659
4142
  name === "@counter-style"
3660
4143
  ) {
3661
- processLocalAtRule(at, {
3662
- identifier: mode === "local"
3663
- });
4144
+ processLocalAtRule(
4145
+ at,
4146
+ {
4147
+ identifier: mode === "local"
4148
+ },
4149
+ "@counter-style"
4150
+ );
3664
4151
  } else if (this.options.container && name === "@container") {
3665
- processLocalAtRule(at, {
3666
- identifier: mode === "local" ? /^(none|and|or|not)$/ : false
3667
- });
4152
+ processLocalAtRule(
4153
+ at,
4154
+ {
4155
+ identifier: mode === "local" ? /^(none|and|or|not)$/ : false
4156
+ },
4157
+ "@container"
4158
+ );
3668
4159
  }
3669
4160
  }
3670
4161
  }
@@ -3672,7 +4163,7 @@ class CssParser extends Parser {
3672
4163
  // `@scope (.x) to (.y)` — walk the prelude as a selector list.
3673
4164
  if (
3674
4165
  isModules &&
3675
- equalsLowerCase(A.name(at), "scope") &&
4166
+ equalsLowerCase(A.unescapedName(at), "scope") &&
3676
4167
  A.prelude(at).length > 0
3677
4168
  ) {
3678
4169
  walkSelectorList(
@@ -3688,6 +4179,7 @@ class CssParser extends Parser {
3688
4179
  const isProcessedByLocalAtRule = isLocalHandledAtRule(name);
3689
4180
  currentStructural = at;
3690
4181
  currentAtRuleName = name;
4182
+ currentDeclCounterActive = false;
3691
4183
  dashed.active = false;
3692
4184
  // `@import` url() is the import target — only walk its prelude for url deps on malformed-import recovery.
3693
4185
  if (this.options.url && (name !== "@import" || currentUrlRecovery)) {
@@ -3728,12 +4220,13 @@ class CssParser extends Parser {
3728
4220
  );
3729
4221
  }
3730
4222
 
3731
- // pure.stack push for block-bearing at-rules.
4223
+ // pure.stack push for block-bearing at-rules (pure-off builds skip
4224
+ // the frame object — every consumer inside is a no-op then).
3732
4225
  const atDecls = A.declarations(at);
3733
4226
  const atChildRules = A.childRules(at);
3734
4227
  const atHasBlock = Boolean(atDecls || atChildRules);
3735
4228
  const atBlockStart = A.blockStart(at);
3736
- if (atHasBlock && atBlockStart !== -1) {
4229
+ if (pure.enabled && atHasBlock && atBlockStart !== -1) {
3737
4230
  const isAtRulePrelude = isPureBodyAtRule(name);
3738
4231
  if (isAtRulePrelude) pure.finalizeSelector();
3739
4232
  pure.enterBlock({
@@ -3749,7 +4242,7 @@ class CssParser extends Parser {
3749
4242
 
3750
4243
  atRuleStateStack.push({
3751
4244
  savedAnchor,
3752
- savedLocalIdentifiers,
4245
+ savedLocalIdentifierCount,
3753
4246
  name,
3754
4247
  hasBlock: atHasBlock,
3755
4248
  endsWithSemicolon: source.charCodeAt(A.end(at)) === CC_SEMICOLON,
@@ -3772,7 +4265,7 @@ class CssParser extends Parser {
3772
4265
  suppressNextRulePrelude = true;
3773
4266
  }
3774
4267
  currentRule.hasLocalAnchor = state.savedAnchor;
3775
- currentRule.localIdentifiers = state.savedLocalIdentifiers;
4268
+ currentRule.localIdentifiers.length = state.savedLocalIdentifierCount;
3776
4269
  if (path.parent === null) finishTopLevelRule(node, true);
3777
4270
  }
3778
4271
  },
@@ -3783,11 +4276,16 @@ class CssParser extends Parser {
3783
4276
  const rule = /** @type {QualifiedRule} */ (node);
3784
4277
  const topLevel = path.parent === null;
3785
4278
  advanceCommentCursor(A.start(rule));
4279
+ // One prelude materialization per rule, shared by the scans below
4280
+ // (null in plain mode, which never reads the array).
4281
+ const rulePrelude =
4282
+ isModules || mayHaveCustomSelectors ? A.prelude(rule) : null;
3786
4283
  // `:--name` custom-selector references (dashed idents never collide with the `:import`/`:export` ICSS preludes below).
3787
- if (mayHaveCustomSelectors) scanCustomSelectorUses(A.prelude(rule));
4284
+ if (mayHaveCustomSelectors && rulePrelude !== null) {
4285
+ scanCustomSelectorUses(rulePrelude);
4286
+ }
3788
4287
  // `:import(…) { … }` / `:export { … }` ICSS pseudo-rules are processed inline at top level; nested ones bail out.
3789
- if (isModules) {
3790
- const rulePrelude = A.prelude(rule);
4288
+ if (isModules && rulePrelude !== null) {
3791
4289
  const firstIdx = nextNonWhitespace(rulePrelude, 0);
3792
4290
  if (
3793
4291
  firstIdx + 1 < rulePrelude.length &&
@@ -3828,14 +4326,12 @@ class CssParser extends Parser {
3828
4326
  }
3829
4327
  }
3830
4328
  }
3831
- // Reset the anchor flag for this rule's body, inheriting (copying) the parent's identifier list so nested `composes:` sees both parent and child class names.
4329
+ // Reset the anchor flag for this rule's body; nested `composes:` sees
4330
+ // parent + own class names in the shared identifier list, rolled back
4331
+ // by length on exit (no per-rule copy).
3832
4332
  const savedAnchor = currentRule.hasLocalAnchor;
3833
- const savedLocalIdentifiers = currentRule.localIdentifiers;
4333
+ const savedLocalIdentifierCount = currentRule.localIdentifiers.length;
3834
4334
  currentRule.hasLocalAnchor = false;
3835
- // Only modules-mode walks mutate `localIdentifiers`; otherwise share the (empty) parent list instead of copying it per rule.
3836
- currentRule.localIdentifiers = isModules
3837
- ? [...savedLocalIdentifiers]
3838
- : savedLocalIdentifiers;
3839
4335
  // Composes-state reset between rules (saved / restored around this rule); composesFiles is swapped out and re-created lazily only if this rule composes.
3840
4336
  const savedPrevComposesFile = currentRule.composesPrevFile;
3841
4337
  const savedComposesFiles = currentRule.composesFiles;
@@ -3844,13 +4340,12 @@ class CssParser extends Parser {
3844
4340
  qualifiedRuleStateStack.push({
3845
4341
  bailed: false,
3846
4342
  savedAnchor,
3847
- savedLocalIdentifiers,
4343
+ savedLocalIdentifierCount,
3848
4344
  savedPrevComposesFile,
3849
4345
  savedComposesFiles
3850
4346
  });
3851
4347
  // Selectors are only CSS-Modules-relevant when `isModules` holds.
3852
- const rulePrelude = A.prelude(rule);
3853
- if (isModules) {
4348
+ if (isModules && rulePrelude !== null) {
3854
4349
  walkSelectorList(
3855
4350
  rulePrelude,
3856
4351
  /** @type {"local" | "global"} */ (
@@ -3860,22 +4355,24 @@ class CssParser extends Parser {
3860
4355
  }
3861
4356
  // A malformed declaration can leave orphan `url(...)` in the prelude — let the url visitor pick those up.
3862
4357
  currentStructural = rule;
4358
+ currentDeclCounterActive = false;
3863
4359
  dashed.active = false;
3864
4360
  dashed.emit = false;
3865
- if (this.options.url && rulePrelude.length > 0) {
3866
- lastTokenEndForComments = A.start(rulePrelude[0]);
4361
+ if (this.options.url && A.childCount(rule) > 0) {
4362
+ lastTokenEndForComments = A.start(A.childAt(rule, 0));
3867
4363
  }
3868
4364
  // Dashed-ident scoping for the deprecated `--foo: { … }` custom-property-set syntax (prelude starts with a dashed-ident).
3869
4365
  if (
3870
4366
  this.options.dashedIdents &&
3871
4367
  isModules &&
4368
+ rulePrelude !== null &&
3872
4369
  rulePrelude.length > 0
3873
4370
  ) {
3874
4371
  const first = rulePrelude[nextNonWhitespace(rulePrelude, 0)];
3875
4372
  if (
3876
4373
  first &&
3877
4374
  A.type(first) === NodeType.Ident &&
3878
- isDashedIdentifier(A.value(first))
4375
+ rangeIsDashedIdentifier(source, A.start(first), A.end(first))
3879
4376
  ) {
3880
4377
  const effectiveLocalMode = isEffectivelyLocal();
3881
4378
  if (effectiveLocalMode) {
@@ -3885,6 +4382,7 @@ class CssParser extends Parser {
3885
4382
  }
3886
4383
  }
3887
4384
  // Pure-mode: report an impure prelude (if leaf-ish) and push the inherited-context frame before walking the body.
4385
+ if (!pure.enabled) return;
3888
4386
  const ruleBlockStart = A.blockStart(rule);
3889
4387
  pure.enterBlock({
3890
4388
  isRulePrelude: true,
@@ -3903,7 +4401,7 @@ class CssParser extends Parser {
3903
4401
  if (!state || state.bailed) return;
3904
4402
  pure.exitBlock();
3905
4403
  currentRule.hasLocalAnchor = state.savedAnchor;
3906
- currentRule.localIdentifiers = state.savedLocalIdentifiers;
4404
+ currentRule.localIdentifiers.length = state.savedLocalIdentifierCount;
3907
4405
  currentRule.composesPrevFile = state.savedPrevComposesFile;
3908
4406
  currentRule.composesFiles = state.savedComposesFiles;
3909
4407
  if (path.parent === null) finishTopLevelRule(node, false);
@@ -3928,6 +4426,8 @@ class CssParser extends Parser {
3928
4426
  lastTokenEndForComments = colonPos + 1;
3929
4427
  currentDeclIsKnownProperty = false;
3930
4428
  currentDeclComposesSkip = false;
4429
+ currentDeclCounterActive = false;
4430
+ dashed.counterArgs = false;
3931
4431
  // Property-name analysis and value exports are CSS-Modules-only; a plain
3932
4432
  // stylesheet's declarations need no per-decl name slice / known-property lookup.
3933
4433
  if (!isModules) return;
@@ -3939,13 +4439,23 @@ class CssParser extends Parser {
3939
4439
  let declName;
3940
4440
  /** @type {string | undefined} */
3941
4441
  let declPropertyName;
3942
- if (source.charCodeAt(nameStart) === CC_HYPHEN_MINUS) {
3943
- // Vendor-prefixed or custom property — rare, take the string path.
3944
- declName = A.name(decl);
3945
- declPropertyName = toLowerCaseIfNeeded(
3946
- declName.replace(VENDOR_PREFIX, "")
3947
- );
3948
- currentDeclIsKnownProperty = knownProperties.has(declPropertyName);
4442
+ let declIsDashed = false;
4443
+ if (
4444
+ source.charCodeAt(nameStart) === CC_HYPHEN_MINUS ||
4445
+ source.charCodeAt(nameStart) === CC_REVERSE_SOLIDUS
4446
+ ) {
4447
+ if (rangeIsDashedIdentifier(source, nameStart, nameEnd)) {
4448
+ // Custom property: never vendor-prefixed / known / composes.
4449
+ declIsDashed = true;
4450
+ } else {
4451
+ // Vendor-prefixed, degenerate short, or an escaped name that is
4452
+ // not dashed after all — rare, string path.
4453
+ declName = A.unescapedName(decl);
4454
+ declPropertyName = toLowerCaseIfNeeded(
4455
+ declName.replace(VENDOR_PREFIX, "")
4456
+ );
4457
+ currentDeclIsKnownProperty = knownProperties.has(declPropertyName);
4458
+ }
3949
4459
  } else {
3950
4460
  declPropertyName = knownPropertyForRange(
3951
4461
  knownPropertyIndex,
@@ -3966,6 +4476,11 @@ class CssParser extends Parser {
3966
4476
  rangeEqualsLowerCase(source, nameStart, nameEnd, "compose-with"));
3967
4477
  if (currentDeclComposesSkip) emitComposesWithAnchor(decl);
3968
4478
  const skipForComposes = currentDeclComposesSkip;
4479
+ // `content: counter(name, style)` can name a scoped counter / `@counter-style` from any property, so this isn't driven by the known-property table.
4480
+ currentDeclCounterActive =
4481
+ Boolean(this.options.customIdents) &&
4482
+ effectiveLocalMode &&
4483
+ !skipForComposes;
3969
4484
  // Known-property value localization (`animation-name: foo` exports `foo`).
3970
4485
  if (effectiveLocalMode && currentDeclIsKnownProperty) {
3971
4486
  emitKnownPropertyExports(
@@ -3979,8 +4494,8 @@ class CssParser extends Parser {
3979
4494
  effectiveLocalMode &&
3980
4495
  !skipForComposes
3981
4496
  ) {
3982
- // Only the `-`-prefixed path can carry a dashed ident.
3983
- if (declName !== undefined && isDashedIdentifier(declName)) {
4497
+ // Only the `--`-prefixed path can carry a dashed ident.
4498
+ if (declIsDashed) {
3984
4499
  emitDashedIdentExport(nameStart, nameEnd);
3985
4500
  }
3986
4501
  dashed.active = true;
@@ -3996,7 +4511,7 @@ class CssParser extends Parser {
3996
4511
  declName = source.slice(nameStart, nameEnd);
3997
4512
  }
3998
4513
  if (
3999
- !(dashed.active && isDashedIdentifier(declName)) &&
4514
+ !(dashed.active && declIsDashed) &&
4000
4515
  icssDefinitions.has(declName)
4001
4516
  ) {
4002
4517
  emitICSSSymbol(declName, nameStart, nameEnd);
@@ -4122,8 +4637,22 @@ class CssParser extends Parser {
4122
4637
  emitICSSSymbol(fname, fnNameStart, fnNameEnd);
4123
4638
  }
4124
4639
  }
4640
+ // `counter()` / `counters()` / `target-counter()` / `target-counters()`: rewrite the counter name and any trailing counter-style ident.
4641
+ let counterNameIndex = -1;
4642
+ if (currentDeclCounterActive && !isLocalFn && !isGlobalFn) {
4643
+ counterNameIndex = counterFunctionNameIndex(
4644
+ input,
4645
+ fnNameStart,
4646
+ fnNameEnd,
4647
+ escapedName
4648
+ );
4649
+ if (counterNameIndex !== -1) {
4650
+ walkCounterFunction(A.children(fn), counterNameIndex);
4651
+ }
4652
+ }
4125
4653
  // Dashed-ident scoping: handle this function, then set the child nesting level's state for the walk.
4126
4654
  dashed.push();
4655
+ dashed.counterArgs = counterNameIndex !== -1;
4127
4656
  if (dashed.active) {
4128
4657
  if (isLocalFn || isGlobalFn) {
4129
4658
  // `local()` / `global()` dashed args go through the ICSS path above, not here.
@@ -4171,12 +4700,18 @@ class CssParser extends Parser {
4171
4700
  // and ICSS context (any non-CSS-Modules stylesheet) a bare ident carries
4172
4701
  // no work, and idents are the most common node, so skipping the per-ident
4173
4702
  // `value` slice matters. With no `@value`/`:import` definitions the ICSS
4174
- // probe can never hit, so it doesn't warrant the slice either.
4703
+ // probe can never hit, so it doesn't warrant the slice either. The dashed
4704
+ // probe reads two char codes instead of slicing (escaped dashes don't
4705
+ // match, same as the string form — cf. `processDashedIdentInVarFunction`).
4175
4706
  const dashedActive = dashed.active;
4176
4707
  const icss = icssActive() && icssDefinitions.size !== 0;
4177
4708
  if (!dashedActive && !icss) return;
4178
- const identValue = A.value(node);
4179
- if (dashedActive && isDashedIdentifier(identValue)) {
4709
+ const identStart = A.start(node);
4710
+ const identEnd = A.end(node);
4711
+ if (
4712
+ dashedActive &&
4713
+ rangeIsDashedIdentifier(input, identStart, identEnd)
4714
+ ) {
4180
4715
  // Dashed idents are scoped here, never `@value` ICSS-rewritten.
4181
4716
  if (!dashed.emit) return;
4182
4717
  // Resolve the `--foo from "./x.css"` / `--foo from global` import suffix via sibling lookahead over the parent's child span (`path.index` avoids materializing the sibling list per dashed ident).
@@ -4219,13 +4754,13 @@ class CssParser extends Parser {
4219
4754
  "global"
4220
4755
  )
4221
4756
  ) {
4222
- emitDashedIdentFromGlobal(A.end(node), A.end(sourceNode));
4757
+ emitDashedIdentFromGlobal(identEnd, A.end(sourceNode));
4223
4758
  return;
4224
4759
  }
4225
4760
  if (sourceNode && A.type(sourceNode) === NodeType.String) {
4226
4761
  emitDashedIdentImport(
4227
- A.start(node),
4228
- A.end(node),
4762
+ identStart,
4763
+ identEnd,
4229
4764
  A.start(fromIdent),
4230
4765
  A.end(sourceNode),
4231
4766
  input.slice(A.start(sourceNode) + 1, A.end(sourceNode) - 1)
@@ -4234,12 +4769,16 @@ class CssParser extends Parser {
4234
4769
  }
4235
4770
  }
4236
4771
  }
4237
- emitDashedIdentExport(A.start(node), A.end(node));
4772
+ emitDashedIdentExport(identStart, identEnd);
4238
4773
  return;
4239
4774
  }
4240
4775
  if (!icss) return;
4776
+ // Already rewritten as a counter / counter-style name — a second dep would overlap the same range.
4777
+ if (dashed.counterArgs) return;
4778
+ // Deferred: only the ICSS probe needs the ident's string value.
4779
+ const identValue = A.value(node);
4241
4780
  if (icssDefinitions.has(identValue)) {
4242
- emitICSSSymbol(identValue, A.start(node), A.end(node));
4781
+ emitICSSSymbol(identValue, identStart, identEnd);
4243
4782
  }
4244
4783
  }
4245
4784
  };
@@ -4249,19 +4788,22 @@ class CssParser extends Parser {
4249
4788
  // (per-source) is passed to `process`. One skip set: selector prelude +
4250
4789
  // unread value leaves (non-modules only; CSS Modules needs its selectors
4251
4790
  // and ICSS-captured values).
4252
- new SourceProcessor({
4253
- as: /** @type {"stylesheet" | "block-contents"} */ (this.options.as),
4254
- // Non-modules parses skip selector preludes, but `@custom-selector` expansion needs them, so keep them when the file may use one.
4255
- skip: isModules
4256
- ? undefined
4257
- : mayHaveCustomSelectors
4258
- ? SKIP_NON_MODULES_KEEP_SELECTORS
4259
- : SKIP_NON_MODULES
4260
- })
4791
+ new SourceProcessor()
4261
4792
  .use(/** @type {VisitorMap} */ (visitors))
4262
- .process(source, { locConverter });
4793
+ .process(source, {
4794
+ as: /** @type {"stylesheet" | "block-contents"} */ (this.options.as),
4795
+ // Non-modules parses skip selector preludes, but `@custom-selector` expansion needs them, so keep them when the file may use one.
4796
+ skip: isModules
4797
+ ? undefined
4798
+ : mayHaveCustomSelectors
4799
+ ? SKIP_NON_MODULES_KEEP_SELECTORS
4800
+ : SKIP_NON_MODULES,
4801
+ locConverter
4802
+ });
4263
4803
 
4264
- if (customMediaUses || customSelectorUses) resolveCustomMediaAndSelectors();
4804
+ if (customMediaQueries || customSelectorUses) {
4805
+ resolveCustomMediaAndSelectors();
4806
+ }
4265
4807
 
4266
4808
  /** @type {BuildInfo} */
4267
4809
  (module.buildInfo).strict = true;
@@ -4286,6 +4828,9 @@ class CssParser extends Parser {
4286
4828
  : "redirect-warn";
4287
4829
 
4288
4830
  if (cssExportEntries.length > 0) {
4831
+ if (isModules && declaredExports.size > 0) {
4832
+ this._resolveAmbiguousExports(state, declaredExports, cssExportEntries);
4833
+ }
4289
4834
  module.addDependency(new CssIcssExportDependency(cssExportEntries));
4290
4835
  }
4291
4836