@depup/webpack 5.106.1-depup.0 → 5.109.2-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 (669) hide show
  1. package/README.md +9 -11
  2. package/bin/webpack.js +12 -0
  3. package/changes.json +16 -24
  4. package/hot/dev-server.js +2 -0
  5. package/lib/APIPlugin.js +60 -35
  6. package/lib/AsyncDependenciesBlock.js +3 -0
  7. package/lib/AutomaticPrefetchPlugin.js +6 -1
  8. package/lib/BannerPlugin.js +13 -5
  9. package/lib/Cache.js +27 -5
  10. package/lib/CacheFacade.js +41 -0
  11. package/lib/Chunk.js +71 -25
  12. package/lib/ChunkGraph.js +153 -19
  13. package/lib/ChunkGroup.js +115 -28
  14. package/lib/ChunkTemplate.js +9 -0
  15. package/lib/CircularModulesPlugin.js +190 -0
  16. package/lib/CleanPlugin.js +27 -28
  17. package/lib/CodeGenerationResults.js +19 -0
  18. package/lib/CompatibilityPlugin.js +85 -37
  19. package/lib/Compilation.js +656 -112
  20. package/lib/Compiler.js +109 -35
  21. package/lib/ConcatenationScope.js +34 -4
  22. package/lib/ConditionalInitFragment.js +6 -0
  23. package/lib/ConstPlugin.js +15 -12
  24. package/lib/ContextExclusionPlugin.js +3 -1
  25. package/lib/ContextModule.js +345 -55
  26. package/lib/ContextModuleFactory.js +193 -51
  27. package/lib/ContextReplacementPlugin.js +8 -1
  28. package/lib/DefinePlugin.js +537 -139
  29. package/lib/DependenciesBlock.js +6 -1
  30. package/lib/Dependency.js +159 -11
  31. package/lib/DependencyTemplate.js +7 -1
  32. package/lib/DependencyTemplates.js +4 -0
  33. package/lib/DotenvPlugin.js +3 -0
  34. package/lib/DynamicEntryPlugin.js +3 -1
  35. package/lib/EntryOptionPlugin.js +42 -2
  36. package/lib/EntryPlugin.js +4 -1
  37. package/lib/Entrypoint.js +5 -1
  38. package/lib/EnvironmentPlugin.js +3 -2
  39. package/lib/ErrorHelpers.js +7 -0
  40. package/lib/EvalDevToolModulePlugin.js +3 -1
  41. package/lib/EvalSourceMapDevToolPlugin.js +11 -11
  42. package/lib/ExportsInfo.js +421 -113
  43. package/lib/ExportsInfoApiPlugin.js +4 -3
  44. package/lib/ExternalModule.js +381 -80
  45. package/lib/ExternalModuleFactoryPlugin.js +75 -3
  46. package/lib/ExternalsPlugin.js +3 -1
  47. package/lib/FileSystemInfo.js +701 -175
  48. package/lib/FlagAllModulesAsUsedPlugin.js +3 -6
  49. package/lib/FlagDependencyExportsPlugin.js +82 -9
  50. package/lib/FlagDependencyUsagePlugin.js +115 -8
  51. package/lib/FlagEntryExportAsUsedPlugin.js +4 -1
  52. package/lib/Generator.js +24 -3
  53. package/lib/HotModuleReplacementPlugin.js +110 -44
  54. package/lib/IgnorePlugin.js +5 -2
  55. package/lib/IgnoreWarningsPlugin.js +2 -1
  56. package/lib/InitFragment.js +33 -30
  57. package/lib/JavascriptMetaInfoPlugin.js +9 -6
  58. package/lib/LazyBarrel.js +389 -0
  59. package/lib/LibraryTemplatePlugin.js +2 -1
  60. package/lib/LoaderOptionsPlugin.js +3 -1
  61. package/lib/LoaderTargetPlugin.js +3 -1
  62. package/lib/MainTemplate.js +15 -0
  63. package/lib/ManifestPlugin.js +9 -2
  64. package/lib/Module.js +121 -57
  65. package/lib/ModuleFactory.js +6 -1
  66. package/lib/ModuleFilenameHelpers.js +18 -4
  67. package/lib/ModuleGraph.js +69 -2
  68. package/lib/ModuleGraphConnection.js +9 -0
  69. package/lib/ModuleInfoHeaderPlugin.js +5 -0
  70. package/lib/ModuleNotFoundError.js +3 -83
  71. package/lib/ModuleProfile.js +27 -1
  72. package/lib/ModuleSourceTypeConstants.js +52 -19
  73. package/lib/ModuleTemplate.js +10 -0
  74. package/lib/ModuleTypeConstants.js +20 -4
  75. package/lib/MultiCompiler.js +59 -4
  76. package/lib/MultiStats.js +9 -0
  77. package/lib/MultiWatching.js +6 -0
  78. package/lib/NoEmitOnErrorsPlugin.js +1 -1
  79. package/lib/NodeStuffPlugin.js +78 -46
  80. package/lib/NormalModule.js +519 -206
  81. package/lib/NormalModuleFactory.js +156 -31
  82. package/lib/NormalModuleReplacementPlugin.js +3 -1
  83. package/lib/NullFactory.js +1 -0
  84. package/lib/OptionsApply.js +1 -0
  85. package/lib/Parser.js +3 -1
  86. package/lib/PlatformPlugin.js +2 -1
  87. package/lib/PrefetchPlugin.js +4 -1
  88. package/lib/ProgressPlugin.js +351 -161
  89. package/lib/ProvidePlugin.js +6 -3
  90. package/lib/RawModule.js +32 -16
  91. package/lib/RecordIdsPlugin.js +9 -0
  92. package/lib/RequestShortener.js +8 -0
  93. package/lib/ResolverFactory.js +5 -0
  94. package/lib/RuntimeGlobals.js +58 -5
  95. package/lib/RuntimeModule.js +22 -7
  96. package/lib/RuntimePlugin.js +123 -118
  97. package/lib/RuntimeTemplate.js +616 -37
  98. package/lib/SelfModuleFactory.js +3 -0
  99. package/lib/SourceMapDevToolModuleOptionsPlugin.js +2 -0
  100. package/lib/SourceMapDevToolPlugin.js +341 -63
  101. package/lib/Stats.js +6 -0
  102. package/lib/Template.js +52 -6
  103. package/lib/TemplatedPathPlugin.js +505 -138
  104. package/lib/UseStrictPlugin.js +3 -2
  105. package/lib/WarnCaseSensitiveModulesPlugin.js +72 -3
  106. package/lib/WarnDeprecatedOptionPlugin.js +6 -2
  107. package/lib/WarnNoModeSetPlugin.js +18 -2
  108. package/lib/WatchIgnorePlugin.js +5 -1
  109. package/lib/Watching.js +25 -3
  110. package/lib/WebpackError.js +3 -74
  111. package/lib/WebpackIsIncludedPlugin.js +4 -2
  112. package/lib/WebpackOptionsApply.js +88 -25
  113. package/lib/WebpackOptionsDefaulter.js +1 -0
  114. package/lib/asset/AssetBytesGenerator.js +28 -10
  115. package/lib/asset/AssetBytesParser.js +1 -0
  116. package/lib/asset/AssetGenerator.js +199 -60
  117. package/lib/asset/AssetModule.js +47 -0
  118. package/lib/asset/AssetModulesPlugin.js +115 -24
  119. package/lib/asset/AssetParser.js +4 -2
  120. package/lib/asset/AssetSourceGenerator.js +26 -8
  121. package/lib/asset/AssetSourceParser.js +1 -0
  122. package/lib/asset/RawDataUrlModule.js +23 -13
  123. package/lib/asset/WebManifestGenerator.js +164 -0
  124. package/lib/asset/WebManifestParser.js +130 -0
  125. package/lib/async-modules/AsyncModuleHelpers.js +1 -0
  126. package/lib/async-modules/AwaitDependenciesInitFragment.js +18 -4
  127. package/lib/async-modules/InferAsyncModulesPlugin.js +1 -1
  128. package/lib/async-modules/isGeneratorLowered.js +26 -0
  129. package/lib/buildChunkGraph.js +107 -15
  130. package/lib/bun/BunTargetPlugin.js +42 -0
  131. package/lib/cache/AddBuildDependenciesPlugin.js +3 -1
  132. package/lib/cache/AddManagedPathsPlugin.js +5 -1
  133. package/lib/cache/IdleFileCachePlugin.js +6 -1
  134. package/lib/cache/MemoryCachePlugin.js +1 -1
  135. package/lib/cache/MemoryWithGcCachePlugin.js +4 -1
  136. package/lib/cache/PackFileCacheStrategy.js +302 -12
  137. package/lib/cache/ResolverCachePlugin.js +12 -1
  138. package/lib/cache/getLazyHashedEtag.js +13 -2
  139. package/lib/cache/mergeEtags.js +4 -0
  140. package/lib/cli.js +142 -20
  141. package/lib/config/browserslistTargetHandler.js +141 -0
  142. package/lib/config/defaults.js +612 -43
  143. package/lib/config/defineConfig.js +31 -0
  144. package/lib/config/normalization.js +46 -1
  145. package/lib/config/target.js +200 -2
  146. package/lib/container/ContainerEntryDependency.js +2 -0
  147. package/lib/container/ContainerEntryModule.js +27 -14
  148. package/lib/container/ContainerEntryModuleFactory.js +1 -0
  149. package/lib/container/ContainerExposedDependency.js +6 -2
  150. package/lib/container/ContainerPlugin.js +2 -1
  151. package/lib/container/ContainerReferencePlugin.js +3 -2
  152. package/lib/container/FallbackDependency.js +9 -7
  153. package/lib/container/FallbackItemDependency.js +1 -0
  154. package/lib/container/FallbackModule.js +22 -9
  155. package/lib/container/FallbackModuleFactory.js +1 -0
  156. package/lib/container/HoistContainerReferencesPlugin.js +47 -55
  157. package/lib/container/ModuleFederationPlugin.js +21 -29
  158. package/lib/container/RemoteModule.js +33 -10
  159. package/lib/container/RemoteRuntimeModule.js +15 -12
  160. package/lib/container/RemoteToExternalDependency.js +1 -0
  161. package/lib/container/options.js +7 -0
  162. package/lib/css/CssGenerator.js +540 -272
  163. package/lib/css/CssInjectStyleRuntimeModule.js +86 -70
  164. package/lib/css/CssLoadingRuntimeModule.js +173 -81
  165. package/lib/{CssModule.js → css/CssModule.js} +72 -37
  166. package/lib/css/CssModulesPlugin.js +371 -208
  167. package/lib/css/CssParser.js +3538 -1963
  168. package/lib/css/syntax.js +4155 -0
  169. package/lib/debug/ProfilingPlugin.js +33 -2
  170. package/lib/deno/DenoTargetPlugin.js +41 -0
  171. package/lib/dependencies/AMDDefineDependency.js +29 -17
  172. package/lib/dependencies/AMDDefineDependencyParserPlugin.js +19 -6
  173. package/lib/dependencies/AMDPlugin.js +6 -3
  174. package/lib/dependencies/AMDRequireArrayDependency.js +13 -11
  175. package/lib/dependencies/AMDRequireContextDependency.js +10 -11
  176. package/lib/dependencies/AMDRequireDependenciesBlock.js +1 -0
  177. package/lib/dependencies/AMDRequireDependenciesBlockParserPlugin.js +28 -14
  178. package/lib/dependencies/AMDRequireDependency.js +28 -20
  179. package/lib/dependencies/AMDRequireItemDependency.js +1 -0
  180. package/lib/dependencies/AMDRuntimeModules.js +3 -0
  181. package/lib/dependencies/CachedConstDependency.js +9 -1
  182. package/lib/dependencies/CommonJsDependencyHelpers.js +104 -0
  183. package/lib/dependencies/CommonJsExportRequireDependency.js +157 -38
  184. package/lib/dependencies/CommonJsExportsDependency.js +74 -20
  185. package/lib/dependencies/CommonJsExportsParserPlugin.js +246 -15
  186. package/lib/dependencies/CommonJsFullRequireDependency.js +91 -27
  187. package/lib/dependencies/CommonJsImportsParserPlugin.js +189 -24
  188. package/lib/dependencies/CommonJsPlugin.js +7 -4
  189. package/lib/dependencies/CommonJsRequireContextDependency.js +13 -13
  190. package/lib/dependencies/CommonJsRequireDependency.js +135 -13
  191. package/lib/dependencies/CommonJsSelfReferenceDependency.js +60 -16
  192. package/lib/dependencies/ConstDependency.js +22 -12
  193. package/lib/dependencies/ContextDependency.js +13 -2
  194. package/lib/dependencies/ContextDependencyHelpers.js +7 -4
  195. package/lib/dependencies/ContextDependencyTemplateAsId.js +2 -1
  196. package/lib/dependencies/ContextDependencyTemplateAsRequireCall.js +1 -0
  197. package/lib/dependencies/ContextElementDependency.js +27 -14
  198. package/lib/dependencies/CreateRequireParserPlugin.js +14 -7
  199. package/lib/dependencies/CreateScriptUrlDependency.js +9 -7
  200. package/lib/dependencies/CriticalDependencyWarning.js +3 -1
  201. package/lib/dependencies/CssIcssExportDependency.js +681 -367
  202. package/lib/dependencies/CssIcssImportDependency.js +62 -17
  203. package/lib/dependencies/CssIcssSymbolDependency.js +36 -17
  204. package/lib/dependencies/CssImportDependency.js +37 -1
  205. package/lib/dependencies/CssUrlDependency.js +87 -14
  206. package/lib/dependencies/DelegatedSourceDependency.js +1 -0
  207. package/lib/dependencies/DllEntryDependency.js +12 -13
  208. package/lib/dependencies/DynamicExports.js +5 -0
  209. package/lib/dependencies/EntryDependency.js +1 -0
  210. package/lib/dependencies/ExportBindingInitFragment.js +164 -0
  211. package/lib/dependencies/ExportsInfoDependency.js +18 -12
  212. package/lib/dependencies/ExternalModuleDependency.js +13 -5
  213. package/lib/dependencies/ExternalModuleInitFragment.js +10 -5
  214. package/lib/dependencies/ExternalModuleInitFragmentDependency.js +19 -12
  215. package/lib/dependencies/HarmonyAcceptDependency.js +24 -26
  216. package/lib/dependencies/HarmonyAcceptImportDependency.js +2 -0
  217. package/lib/dependencies/HarmonyCompatibilityDependency.js +33 -14
  218. package/lib/dependencies/HarmonyDetectionParserPlugin.js +108 -30
  219. package/lib/dependencies/HarmonyEvaluatedImportSpecifierDependency.js +34 -3
  220. package/lib/dependencies/HarmonyExportDependencyParserPlugin.js +70 -33
  221. package/lib/dependencies/HarmonyExportExpressionDependency.js +133 -43
  222. package/lib/dependencies/HarmonyExportHeaderDependency.js +11 -9
  223. package/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +268 -44
  224. package/lib/dependencies/HarmonyExportInitFragment.js +28 -20
  225. package/lib/dependencies/HarmonyExportSpecifierDependency.js +88 -18
  226. package/lib/dependencies/HarmonyExports.js +6 -1
  227. package/lib/dependencies/HarmonyImportDependency.js +60 -4
  228. package/lib/dependencies/HarmonyImportDependencyParserPlugin.js +139 -146
  229. package/lib/dependencies/HarmonyImportGuard.js +427 -0
  230. package/lib/dependencies/HarmonyImportSideEffectDependency.js +22 -1
  231. package/lib/dependencies/HarmonyImportSpecifierDependency.js +146 -24
  232. package/lib/{HarmonyLinkingError.js → dependencies/HarmonyLinkingError.js} +6 -3
  233. package/lib/dependencies/HarmonyModulesPlugin.js +11 -1
  234. package/lib/dependencies/HarmonyTopLevelThisParserPlugin.js +2 -1
  235. package/lib/dependencies/HtmlEntryDependency.js +1295 -0
  236. package/lib/dependencies/HtmlInlineHtmlDependency.js +107 -0
  237. package/lib/dependencies/HtmlInlineScriptDependency.js +126 -0
  238. package/lib/dependencies/HtmlInlineStyleDependency.js +152 -0
  239. package/lib/dependencies/HtmlSourceDependency.js +172 -0
  240. package/lib/dependencies/ImportContextDependency.js +9 -9
  241. package/lib/dependencies/ImportDependency.js +92 -3
  242. package/lib/dependencies/ImportEagerDependency.js +2 -0
  243. package/lib/dependencies/ImportMetaContextDependency.js +1 -0
  244. package/lib/dependencies/ImportMetaContextDependencyParserPlugin.js +35 -19
  245. package/lib/dependencies/ImportMetaContextPlugin.js +40 -8
  246. package/lib/dependencies/ImportMetaGlobDependency.js +81 -0
  247. package/lib/dependencies/ImportMetaGlobDependencyParserPlugin.js +78 -0
  248. package/lib/dependencies/ImportMetaGlobHelpers.js +660 -0
  249. package/lib/dependencies/ImportMetaHotAcceptDependency.js +2 -0
  250. package/lib/dependencies/ImportMetaHotDeclineDependency.js +2 -0
  251. package/lib/dependencies/ImportMetaPlugin.js +595 -209
  252. package/lib/dependencies/ImportMetaResolveDependency.js +90 -0
  253. package/lib/dependencies/ImportParserPlugin.js +114 -27
  254. package/lib/dependencies/ImportPhase.js +17 -11
  255. package/lib/dependencies/ImportPlugin.js +2 -1
  256. package/lib/dependencies/ImportWeakDependency.js +3 -0
  257. package/lib/dependencies/JsonExportsDependency.js +15 -10
  258. package/lib/dependencies/LoaderDependency.js +2 -0
  259. package/lib/dependencies/LoaderImportDependency.js +3 -0
  260. package/lib/dependencies/LoaderPlugin.js +9 -2
  261. package/lib/dependencies/LocalModule.js +15 -12
  262. package/lib/dependencies/LocalModuleDependency.js +15 -13
  263. package/lib/dependencies/LocalModulesHelpers.js +3 -0
  264. package/lib/dependencies/ModuleDecoratorDependency.js +16 -10
  265. package/lib/dependencies/ModuleDependency.js +14 -0
  266. package/lib/dependencies/ModuleDependencyTemplateAsId.js +1 -0
  267. package/lib/dependencies/ModuleDependencyTemplateAsRequireId.js +1 -0
  268. package/lib/dependencies/ModuleHotAcceptDependency.js +2 -0
  269. package/lib/dependencies/ModuleHotDeclineDependency.js +2 -0
  270. package/lib/dependencies/ModuleInitFragmentDependency.js +19 -11
  271. package/lib/dependencies/NullDependency.js +2 -0
  272. package/lib/dependencies/PrefetchDependency.js +1 -0
  273. package/lib/dependencies/ProvidedDependency.js +36 -27
  274. package/lib/dependencies/PureExpressionDependency.js +14 -10
  275. package/lib/dependencies/RequireContextDependency.js +1 -0
  276. package/lib/dependencies/RequireContextDependencyParserPlugin.js +2 -1
  277. package/lib/dependencies/RequireContextPlugin.js +2 -1
  278. package/lib/dependencies/RequireEnsureDependenciesBlock.js +1 -0
  279. package/lib/dependencies/RequireEnsureDependenciesBlockParserPlugin.js +4 -6
  280. package/lib/dependencies/RequireEnsureDependency.js +16 -13
  281. package/lib/dependencies/RequireEnsureItemDependency.js +1 -0
  282. package/lib/dependencies/RequireEnsurePlugin.js +2 -1
  283. package/lib/dependencies/RequireHeaderDependency.js +7 -4
  284. package/lib/dependencies/RequireIncludeDependency.js +2 -0
  285. package/lib/dependencies/RequireIncludeDependencyParserPlugin.js +11 -12
  286. package/lib/dependencies/RequireIncludePlugin.js +2 -1
  287. package/lib/{RequireJsStuffPlugin.js → dependencies/RequireJsStuffPlugin.js} +9 -8
  288. package/lib/dependencies/RequireResolveContextDependency.js +10 -11
  289. package/lib/dependencies/RequireResolveDependency.js +2 -0
  290. package/lib/dependencies/RequireResolveHeaderDependency.js +8 -5
  291. package/lib/dependencies/RuntimeRequirementsDependency.js +11 -8
  292. package/lib/dependencies/StaticExportsDependency.js +13 -10
  293. package/lib/dependencies/SystemPlugin.js +9 -6
  294. package/lib/dependencies/SystemRuntimeModule.js +1 -0
  295. package/lib/dependencies/TopLevelAwaitDependency.js +93 -0
  296. package/lib/dependencies/URLContextDependency.js +8 -7
  297. package/lib/dependencies/URLDependency.js +157 -33
  298. package/lib/dependencies/URLPlugin.js +2 -0
  299. package/lib/dependencies/UnsupportedDependency.js +12 -13
  300. package/lib/dependencies/WebAssemblyExportImportedDependency.js +15 -16
  301. package/lib/dependencies/WebAssemblyImportDependency.js +19 -18
  302. package/lib/dependencies/WebpackIsIncludedDependency.js +3 -0
  303. package/lib/dependencies/{WorkerPlugin.js → WorkerAndWorkletPlugin.js} +364 -114
  304. package/lib/dependencies/WorkerDependency.js +111 -27
  305. package/lib/dependencies/WorkletDependency.js +278 -0
  306. package/lib/dependencies/getFunctionExpression.js +1 -0
  307. package/lib/dependencies/processExportInfo.js +14 -11
  308. package/lib/{DelegatedModule.js → dll/DelegatedModule.js} +71 -44
  309. package/lib/{DelegatedModuleFactoryPlugin.js → dll/DelegatedModuleFactoryPlugin.js} +27 -4
  310. package/lib/{DelegatedPlugin.js → dll/DelegatedPlugin.js} +5 -3
  311. package/lib/{DllEntryPlugin.js → dll/DllEntryPlugin.js} +9 -5
  312. package/lib/{DllModule.js → dll/DllModule.js} +36 -24
  313. package/lib/{DllModuleFactory.js → dll/DllModuleFactory.js} +5 -4
  314. package/lib/{DllPlugin.js → dll/DllPlugin.js} +24 -6
  315. package/lib/{DllReferencePlugin.js → dll/DllReferencePlugin.js} +26 -18
  316. package/lib/{LibManifestPlugin.js → dll/LibManifestPlugin.js} +14 -10
  317. package/lib/electron/ElectronTargetPlugin.js +24 -5
  318. package/lib/{AbstractMethodError.js → errors/AbstractMethodError.js} +10 -1
  319. package/lib/{AsyncDependencyToInitialChunkError.js → errors/AsyncDependencyToInitialChunkError.js} +8 -3
  320. package/lib/errors/BuildCycleError.js +1 -1
  321. package/lib/{ChunkRenderError.js → errors/ChunkRenderError.js} +1 -1
  322. package/lib/{CodeGenerationError.js → errors/CodeGenerationError.js} +1 -1
  323. package/lib/{CommentCompilationWarning.js → errors/CommentCompilationWarning.js} +9 -3
  324. package/lib/{ConcurrentCompilationError.js → errors/ConcurrentCompilationError.js} +5 -2
  325. package/lib/{EnvironmentNotSupportAsyncWarning.js → errors/EnvironmentNotSupportAsyncWarning.js} +5 -5
  326. package/lib/{HookWebpackError.js → errors/HookWebpackError.js} +20 -16
  327. package/lib/{IgnoreErrorModuleFactory.js → errors/IgnoreErrorModuleFactory.js} +7 -4
  328. package/lib/{InvalidDependenciesModuleWarning.js → errors/InvalidDependenciesModuleWarning.js} +6 -3
  329. package/lib/errors/JSONParseError.js +115 -0
  330. package/lib/errors/LoaderLoadingError.js +20 -0
  331. package/lib/{ModuleBuildError.js → errors/ModuleBuildError.js} +22 -16
  332. package/lib/{ModuleDependencyError.js → errors/ModuleDependencyError.js} +10 -3
  333. package/lib/{ModuleDependencyWarning.js → errors/ModuleDependencyWarning.js} +13 -5
  334. package/lib/{ModuleError.js → errors/ModuleError.js} +10 -14
  335. package/lib/{ModuleHashingError.js → errors/ModuleHashingError.js} +5 -1
  336. package/lib/errors/ModuleNotFoundError.js +94 -0
  337. package/lib/errors/ModuleParseError.js +141 -0
  338. package/lib/{ModuleRestoreError.js → errors/ModuleRestoreError.js} +4 -1
  339. package/lib/{ModuleStoreError.js → errors/ModuleStoreError.js} +5 -1
  340. package/lib/{ModuleWarning.js → errors/ModuleWarning.js} +13 -14
  341. package/lib/{NodeStuffInWebError.js → errors/NodeStuffInWebError.js} +7 -5
  342. package/lib/errors/NonErrorEmittedError.js +30 -0
  343. package/lib/{UnhandledSchemeError.js → errors/UnhandledSchemeError.js} +9 -2
  344. package/lib/{UnsupportedFeatureWarning.js → errors/UnsupportedFeatureWarning.js} +4 -3
  345. package/lib/errors/WebpackError.js +84 -0
  346. package/lib/esm/ExportWebpackRequireRuntimeModule.js +2 -0
  347. package/lib/esm/ModuleChunkFormatPlugin.js +52 -15
  348. package/lib/esm/ModuleChunkLoadingPlugin.js +11 -3
  349. package/lib/esm/ModuleChunkLoadingRuntimeModule.js +80 -52
  350. package/lib/hmr/HotModuleReplacement.runtime.js +175 -30
  351. package/lib/hmr/HotModuleReplacementRuntimeModule.js +8 -0
  352. package/lib/hmr/JavascriptHotModuleReplacement.runtime.js +173 -26
  353. package/lib/hmr/JavascriptHotModuleReplacementHelper.js +1 -0
  354. package/lib/hmr/LazyCompilationPlugin.js +154 -7
  355. package/lib/hmr/lazyCompilationBackend.js +53 -12
  356. package/lib/html/HtmlGenerator.js +1490 -0
  357. package/lib/html/HtmlModule.js +41 -0
  358. package/lib/html/HtmlModulesPlugin.js +1129 -0
  359. package/lib/html/HtmlParser.js +1970 -0
  360. package/lib/html/favicon.svg +1 -0
  361. package/lib/html/syntax.js +9106 -0
  362. package/lib/ids/ChunkModuleIdRangePlugin.js +3 -1
  363. package/lib/ids/DeterministicChunkIdsPlugin.js +3 -1
  364. package/lib/ids/DeterministicModuleIdsPlugin.js +3 -1
  365. package/lib/ids/HashedModuleIdsPlugin.js +2 -1
  366. package/lib/ids/IdHelpers.js +49 -12
  367. package/lib/ids/NamedChunkIdsPlugin.js +3 -1
  368. package/lib/ids/NamedModuleIdsPlugin.js +3 -1
  369. package/lib/ids/NaturalChunkIdsPlugin.js +1 -1
  370. package/lib/ids/NaturalModuleIdsPlugin.js +1 -1
  371. package/lib/ids/OccurrenceChunkIdsPlugin.js +2 -1
  372. package/lib/ids/OccurrenceModuleIdsPlugin.js +4 -1
  373. package/lib/ids/SyncModuleIdsPlugin.js +3 -1
  374. package/lib/index.js +66 -15
  375. package/lib/javascript/ArrayPushCallbackChunkFormatPlugin.js +5 -6
  376. package/lib/javascript/BasicEvaluatedExpression.js +370 -49
  377. package/lib/javascript/ChunkFormatHelpers.js +2 -1
  378. package/lib/javascript/ChunkHelpers.js +1 -0
  379. package/lib/javascript/CommonJsChunkFormatPlugin.js +1 -1
  380. package/lib/javascript/EnableChunkLoadingPlugin.js +6 -1
  381. package/lib/javascript/JavascriptGenerator.js +213 -51
  382. package/lib/javascript/JavascriptModule.js +54 -0
  383. package/lib/javascript/JavascriptModulesPlugin.js +628 -198
  384. package/lib/javascript/JavascriptParser.js +1334 -471
  385. package/lib/javascript/JavascriptParserHelpers.js +10 -7
  386. package/lib/javascript/StartupHelpers.js +5 -0
  387. package/lib/javascript/syntax.js +5037 -0
  388. package/lib/json/JsonData.js +5 -0
  389. package/lib/json/JsonGenerator.js +21 -0
  390. package/lib/json/JsonModule.js +40 -0
  391. package/lib/json/JsonModulesPlugin.js +8 -1
  392. package/lib/json/JsonParser.js +18 -27
  393. package/lib/library/AbstractLibraryPlugin.js +17 -2
  394. package/lib/library/AmdLibraryPlugin.js +8 -0
  395. package/lib/library/AssignLibraryPlugin.js +21 -3
  396. package/lib/library/EnableLibraryPlugin.js +8 -2
  397. package/lib/library/ExportPropertyLibraryPlugin.js +10 -0
  398. package/lib/{FalseIIFEUmdWarning.js → library/FalseIIFEUmdWarning.js} +2 -1
  399. package/lib/library/JsonpLibraryPlugin.js +8 -0
  400. package/lib/library/ModuleLibraryPlugin.js +154 -7
  401. package/lib/library/SystemLibraryPlugin.js +11 -3
  402. package/lib/library/UmdLibraryPlugin.js +16 -0
  403. package/lib/loaders/LoaderRunner.js +714 -0
  404. package/lib/loaders/loadLoader.js +100 -0
  405. package/lib/logging/Logger.js +17 -0
  406. package/lib/logging/createConsoleLogger.js +7 -0
  407. package/lib/logging/runtime.js +2 -0
  408. package/lib/logging/truncateArgs.js +2 -0
  409. package/lib/node/CommonJsChunkLoadingPlugin.js +5 -1
  410. package/lib/node/NodeEnvironmentPlugin.js +7 -3
  411. package/lib/node/NodeSourcePlugin.js +1 -1
  412. package/lib/node/NodeTargetPlugin.js +4 -63
  413. package/lib/node/NodeTemplatePlugin.js +3 -1
  414. package/lib/node/NodeWatchFileSystem.js +40 -22
  415. package/lib/node/ReadFileChunkLoadingRuntimeModule.js +13 -9
  416. package/lib/node/ReadFileCompileAsyncWasmPlugin.js +33 -3
  417. package/lib/node/ReadFileCompileWasmPlugin.js +28 -3
  418. package/lib/node/RequireChunkLoadingRuntimeModule.js +21 -16
  419. package/lib/node/nodeBuiltins.js +80 -0
  420. package/lib/node/nodeConsole.js +116 -64
  421. package/lib/optimize/AggressiveMergingPlugin.js +22 -16
  422. package/lib/optimize/AggressiveSplittingPlugin.js +6 -1
  423. package/lib/optimize/ConcatenatedModule.js +603 -130
  424. package/lib/optimize/ConstExportsPlugin.js +211 -0
  425. package/lib/optimize/EnsureChunkConditionsPlugin.js +2 -1
  426. package/lib/optimize/FlagIncludedChunksPlugin.js +15 -4
  427. package/lib/optimize/InlineExports.js +178 -0
  428. package/lib/optimize/InnerGraph.js +374 -262
  429. package/lib/optimize/InnerGraphPlugin.js +246 -117
  430. package/lib/optimize/LimitChunkCountPlugin.js +9 -0
  431. package/lib/optimize/MangleExportsPlugin.js +5 -1
  432. package/lib/optimize/MergeDuplicateChunksPlugin.js +2 -0
  433. package/lib/optimize/MinChunkSizePlugin.js +2 -1
  434. package/lib/optimize/MinMaxSizeWarning.js +5 -4
  435. package/lib/optimize/ModuleConcatenationPlugin.js +229 -55
  436. package/lib/optimize/RealContentHashPlugin.js +130 -52
  437. package/lib/optimize/RemoveEmptyChunksPlugin.js +2 -1
  438. package/lib/optimize/RemoveParentModulesPlugin.js +3 -1
  439. package/lib/optimize/RuntimeChunkPlugin.js +2 -1
  440. package/lib/optimize/SideEffectsFlagPlugin.js +381 -55
  441. package/lib/optimize/SplitChunksPlugin.js +200 -50
  442. package/lib/performance/AssetsOverSizeLimitWarning.js +3 -2
  443. package/lib/performance/EntrypointsOverSizeLimitWarning.js +3 -2
  444. package/lib/performance/NoAsyncChunksWarning.js +5 -3
  445. package/lib/performance/SizeLimitsPlugin.js +8 -2
  446. package/lib/prefetch/ChunkPrefetchFunctionRuntimeModule.js +1 -0
  447. package/lib/prefetch/ChunkPrefetchPreloadPlugin.js +21 -0
  448. package/lib/prefetch/ChunkPrefetchStartupRuntimeModule.js +1 -0
  449. package/lib/prefetch/ChunkPrefetchTriggerRuntimeModule.js +5 -1
  450. package/lib/prefetch/ChunkPreloadTriggerRuntimeModule.js +25 -13
  451. package/lib/prefetch/ResourceHintPlugin.js +687 -0
  452. package/lib/prefetch/ResourceHintRuntimeModule.js +149 -0
  453. package/lib/prefetch/StartupAssetHintRuntimeModule.js +210 -0
  454. package/lib/prefetch/parseResourceHintOptions.js +103 -0
  455. package/lib/rules/BasicEffectRulePlugin.js +3 -0
  456. package/lib/rules/BasicMatcherRulePlugin.js +3 -0
  457. package/lib/rules/ObjectMatcherRulePlugin.js +3 -0
  458. package/lib/rules/RuleSetCompiler.js +132 -0
  459. package/lib/rules/UseEffectRulePlugin.js +10 -3
  460. package/lib/runtime/AsyncModuleGeneratorRuntimeModule.js +56 -0
  461. package/lib/runtime/AsyncModuleRuntimeModule.js +52 -33
  462. package/lib/runtime/AutoPublicPathRuntimeModule.js +22 -9
  463. package/lib/runtime/BaseUriRuntimeModule.js +1 -0
  464. package/lib/runtime/ChunkNameRuntimeModule.js +1 -0
  465. package/lib/runtime/CommonJsWrapRuntimeModule.js +37 -0
  466. package/lib/runtime/CompatGetDefaultExportRuntimeModule.js +2 -1
  467. package/lib/runtime/CompatRuntimeModule.js +2 -0
  468. package/lib/runtime/CreateFakeNamespaceObjectRuntimeModule.js +7 -4
  469. package/lib/runtime/CreateScriptRuntimeModule.js +1 -0
  470. package/lib/runtime/CreateScriptUrlRuntimeModule.js +1 -0
  471. package/lib/runtime/DefinePropertyGettersRuntimeModule.js +34 -4
  472. package/lib/runtime/EnsureChunkRuntimeModule.js +1 -0
  473. package/lib/runtime/GetChunkFilenameRuntimeModule.js +88 -8
  474. package/lib/runtime/GetFullHashRuntimeModule.js +1 -0
  475. package/lib/runtime/GetMainFilenameRuntimeModule.js +1 -0
  476. package/lib/runtime/GetTrustedTypesPolicyRuntimeModule.js +2 -1
  477. package/lib/runtime/GetWorkletBootstrapRuntimeModule.js +59 -0
  478. package/lib/runtime/GlobalRuntimeModule.js +1 -0
  479. package/lib/runtime/HasOwnPropertyRuntimeModule.js +2 -1
  480. package/lib/runtime/HelperRuntimeModule.js +5 -0
  481. package/lib/runtime/LoadScriptRuntimeModule.js +28 -37
  482. package/lib/runtime/MakeDeferredNamespaceObjectRuntime.js +354 -37
  483. package/lib/runtime/MakeNamespaceObjectRuntimeModule.js +2 -1
  484. package/lib/runtime/NonceRuntimeModule.js +1 -0
  485. package/lib/runtime/OnChunksLoadedRuntimeModule.js +5 -4
  486. package/lib/runtime/PublicPathRuntimeModule.js +1 -0
  487. package/lib/runtime/RelativeUrlRuntimeModule.js +4 -2
  488. package/lib/runtime/RuntimeIdRuntimeModule.js +1 -0
  489. package/lib/runtime/SetAnonymousDefaultNameRuntimeModule.js +38 -0
  490. package/lib/runtime/StartupChunkDependenciesPlugin.js +13 -1
  491. package/lib/runtime/StartupChunkDependenciesRuntimeModule.js +2 -1
  492. package/lib/runtime/StartupEntrypointRuntimeModule.js +5 -3
  493. package/lib/runtime/SystemContextRuntimeModule.js +1 -0
  494. package/lib/runtime/ToBinaryRuntimeModule.js +1 -0
  495. package/lib/runtime/WorkerRuntimeModule.js +33 -0
  496. package/lib/schemes/DataUriPlugin.js +14 -2
  497. package/lib/schemes/FileUriPlugin.js +1 -1
  498. package/lib/schemes/HttpUriPlugin.js +86 -4
  499. package/lib/schemes/VirtualUrlPlugin.js +8 -4
  500. package/lib/serialization/AggregateErrorSerializer.js +9 -6
  501. package/lib/serialization/ArraySerializer.js +6 -8
  502. package/lib/serialization/BinaryMiddleware.js +427 -1006
  503. package/lib/serialization/DateObjectSerializer.js +4 -2
  504. package/lib/serialization/ErrorObjectSerializer.js +10 -6
  505. package/lib/serialization/FileMiddleware.js +345 -59
  506. package/lib/serialization/MapObjectSerializer.js +7 -9
  507. package/lib/serialization/NullPrototypeObjectSerializer.js +9 -9
  508. package/lib/serialization/ObjectMiddleware.js +73 -13
  509. package/lib/serialization/PlainObjectSerializer.js +16 -8
  510. package/lib/serialization/RegExpObjectSerializer.js +4 -2
  511. package/lib/serialization/Serializer.js +6 -0
  512. package/lib/serialization/SerializerMiddleware.js +14 -2
  513. package/lib/serialization/SetObjectSerializer.js +6 -8
  514. package/lib/serialization/SingleItemMiddleware.js +3 -0
  515. package/lib/sharing/ConsumeSharedFallbackDependency.js +1 -0
  516. package/lib/sharing/ConsumeSharedModule.js +21 -7
  517. package/lib/sharing/ConsumeSharedPlugin.js +11 -11
  518. package/lib/sharing/ConsumeSharedRuntimeModule.js +55 -45
  519. package/lib/sharing/ProvideForSharedDependency.js +1 -0
  520. package/lib/sharing/ProvideSharedDependency.js +34 -15
  521. package/lib/sharing/ProvideSharedModule.js +42 -12
  522. package/lib/sharing/ProvideSharedModuleFactory.js +1 -0
  523. package/lib/sharing/ProvideSharedPlugin.js +13 -8
  524. package/lib/sharing/SharePlugin.js +5 -1
  525. package/lib/sharing/ShareRuntimeModule.js +19 -16
  526. package/lib/sharing/resolveMatchedConfigs.js +6 -2
  527. package/lib/sharing/utils.js +9 -1
  528. package/lib/stats/DefaultStatsFactoryPlugin.js +289 -201
  529. package/lib/stats/DefaultStatsPresetPlugin.js +14 -2
  530. package/lib/stats/DefaultStatsPrinterPlugin.js +74 -170
  531. package/lib/stats/StatsFactory.js +70 -27
  532. package/lib/stats/StatsPrinter.js +16 -2
  533. package/lib/typescript/TypeScriptPlugin.js +210 -0
  534. package/lib/url/URLParserPlugin.js +111 -23
  535. package/lib/util/ArrayHelpers.js +1 -0
  536. package/lib/util/ArrayQueue.js +10 -5
  537. package/lib/util/AsyncQueue.js +154 -74
  538. package/lib/util/Hash.js +2 -2
  539. package/lib/util/IterableHelpers.js +3 -0
  540. package/lib/util/LazyBucketSortedSet.js +26 -0
  541. package/lib/util/LazySet.js +45 -4
  542. package/lib/util/LocConverter.js +64 -0
  543. package/lib/util/ParallelismFactorCalculator.js +1 -0
  544. package/lib/util/Queue.js +6 -3
  545. package/lib/util/Semaphore.js +15 -1
  546. package/lib/util/SetHelpers.js +4 -1
  547. package/lib/util/SortableSet.js +7 -1
  548. package/lib/util/SourceProcessor.js +119 -0
  549. package/lib/util/StackedCacheMap.js +20 -3
  550. package/lib/util/StackedMap.js +162 -43
  551. package/lib/util/StringXor.js +1 -1
  552. package/lib/util/TupleQueue.js +7 -3
  553. package/lib/util/TupleSet.js +14 -0
  554. package/lib/util/URLAbsoluteSpecifier.js +1 -0
  555. package/lib/util/WeakTupleMap.js +60 -1
  556. package/lib/util/binarySearchBounds.js +3 -2
  557. package/lib/util/chainedImports.js +3 -3
  558. package/lib/util/cleverMerge.js +19 -2
  559. package/lib/util/comparators.js +35 -4
  560. package/lib/util/compileBooleanMatcher.js +9 -0
  561. package/lib/util/concatenate.js +80 -24
  562. package/lib/util/conventions.js +46 -1
  563. package/lib/util/createHash.js +0 -1
  564. package/lib/util/createHooksRegistry.js +43 -0
  565. package/lib/util/createMappings.js +118 -0
  566. package/lib/util/dataURL.js +3 -2
  567. package/lib/util/deprecation.js +19 -0
  568. package/lib/util/deterministicGrouping.js +46 -17
  569. package/lib/util/extractSourceMap.js +2 -1
  570. package/lib/util/extractUrlAndGlobal.js +1 -0
  571. package/lib/util/findGraphRoots.js +7 -0
  572. package/lib/{formatLocation.js → util/formatLocation.js} +4 -2
  573. package/lib/{SizeFormatHelpers.js → util/formatSize.js} +10 -3
  574. package/lib/util/fs.js +87 -14
  575. package/lib/util/generateDebugId.js +1 -0
  576. package/lib/util/globUtils.js +710 -0
  577. package/lib/util/hash/BatchedHash.js +1 -0
  578. package/lib/util/hash/BulkUpdateHash.js +1 -0
  579. package/lib/util/hash/DebugHash.js +1 -0
  580. package/lib/util/hash/hash-digest.js +32 -15
  581. package/lib/util/hash/md4.js +1 -1
  582. package/lib/util/hash/wasm-hash.js +5 -0
  583. package/lib/util/hash/xxhash64.js +1 -1
  584. package/lib/util/identifier.js +118 -7
  585. package/lib/util/implicitTypeLoaderFallback.js +62 -0
  586. package/lib/util/internalSerializables.js +102 -60
  587. package/lib/util/magicComment.js +149 -7
  588. package/lib/util/makeSerializable.js +7 -0
  589. package/lib/util/memoize.js +2 -0
  590. package/lib/util/mimeTypes.js +176 -0
  591. package/lib/util/nonNumericOnlyHash.js +31 -1
  592. package/lib/util/numberHash.js +2 -2
  593. package/lib/util/parseJson.js +41 -0
  594. package/lib/util/processAsyncTree.js +8 -0
  595. package/lib/util/property.js +9 -2
  596. package/lib/util/publicPathPlaceholder.js +64 -0
  597. package/lib/util/registerExternalSerializer.js +24 -4
  598. package/lib/util/removeBOM.js +1 -0
  599. package/lib/util/runtime.js +32 -0
  600. package/lib/util/semver.js +15 -0
  601. package/lib/util/serialization.js +2 -0
  602. package/lib/util/smartGrouping.js +8 -0
  603. package/lib/util/source.js +23 -0
  604. package/lib/util/topologicalSort.js +69 -0
  605. package/lib/validateSchema.js +1 -0
  606. package/lib/wasm/EnableWasmLoadingPlugin.js +15 -1
  607. package/lib/wasm-async/AsyncWasmCompileRuntimeModule.js +25 -18
  608. package/lib/wasm-async/AsyncWasmLoadingRuntimeModule.js +34 -22
  609. package/lib/wasm-async/AsyncWasmModule.js +77 -0
  610. package/lib/wasm-async/AsyncWebAssemblyGenerator.js +6 -0
  611. package/lib/wasm-async/AsyncWebAssemblyJavascriptGenerator.js +6 -1
  612. package/lib/wasm-async/AsyncWebAssemblyModulesPlugin.js +22 -126
  613. package/lib/wasm-async/AsyncWebAssemblyParser.js +3 -2
  614. package/lib/wasm-async/UniversalCompileAsyncWasmPlugin.js +13 -2
  615. package/lib/wasm-sync/SyncWasmModule.js +39 -0
  616. package/lib/wasm-sync/UnsupportedWebAssemblyFeatureError.js +7 -3
  617. package/lib/wasm-sync/WasmChunkLoadingRuntimeModule.js +86 -19
  618. package/lib/wasm-sync/WasmFinalizeExportsPlugin.js +4 -3
  619. package/lib/wasm-sync/WebAssemblyGenerator.js +27 -1
  620. package/lib/wasm-sync/WebAssemblyInInitialChunkError.js +9 -3
  621. package/lib/wasm-sync/WebAssemblyJavascriptGenerator.js +4 -0
  622. package/lib/wasm-sync/WebAssemblyModulesPlugin.js +20 -1
  623. package/lib/wasm-sync/WebAssemblyParser.js +9 -3
  624. package/lib/wasm-sync/WebAssemblyUtils.js +2 -0
  625. package/lib/web/FetchCompileAsyncWasmPlugin.js +29 -1
  626. package/lib/web/FetchCompileWasmPlugin.js +27 -1
  627. package/lib/web/JsonpChunkLoadingPlugin.js +11 -1
  628. package/lib/web/JsonpChunkLoadingRuntimeModule.js +58 -64
  629. package/lib/web/JsonpTemplatePlugin.js +2 -1
  630. package/lib/webpack.js +78 -1
  631. package/lib/webworker/ImportScriptsChunkLoadingPlugin.js +10 -1
  632. package/lib/webworker/ImportScriptsChunkLoadingRuntimeModule.js +15 -10
  633. package/lib/webworker/WebWorkerTemplatePlugin.js +1 -1
  634. package/module.d.ts +21 -0
  635. package/package.json +79 -77
  636. package/schemas/WebpackOptions.check.js +1 -1
  637. package/schemas/WebpackOptions.json +1173 -80
  638. package/schemas/plugins/{DllPlugin.check.d.ts → HtmlGeneratorOptions.check.d.ts} +1 -1
  639. package/schemas/plugins/HtmlGeneratorOptions.check.js +6 -0
  640. package/schemas/plugins/HtmlGeneratorOptions.json +3 -0
  641. package/schemas/plugins/{DllReferencePlugin.check.d.ts → HtmlParserOptions.check.d.ts} +1 -1
  642. package/schemas/plugins/HtmlParserOptions.check.js +6 -0
  643. package/schemas/plugins/HtmlParserOptions.json +3 -0
  644. package/schemas/plugins/ProgressPlugin.check.js +1 -1
  645. package/schemas/plugins/ProgressPlugin.json +38 -0
  646. package/schemas/plugins/container/ContainerReferencePlugin.check.js +1 -1
  647. package/schemas/plugins/container/ContainerReferencePlugin.json +2 -0
  648. package/schemas/plugins/container/ExternalsType.check.js +1 -1
  649. package/schemas/plugins/container/ModuleFederationPlugin.check.js +1 -1
  650. package/schemas/plugins/container/ModuleFederationPlugin.json +2 -0
  651. package/schemas/plugins/css/CssAutoOrModuleParserOptions.check.d.ts +7 -0
  652. package/schemas/plugins/css/CssAutoOrModuleParserOptions.check.js +6 -0
  653. package/schemas/plugins/css/CssAutoOrModuleParserOptions.json +3 -0
  654. package/schemas/plugins/css/CssModuleParserOptions.check.js +1 -1
  655. package/schemas/plugins/css/CssParserOptions.check.js +1 -1
  656. package/schemas/plugins/dll/DllPlugin.check.d.ts +7 -0
  657. package/schemas/plugins/dll/DllReferencePlugin.check.d.ts +7 -0
  658. package/types.d.ts +11053 -3019
  659. package/lib/CaseSensitiveModulesWarning.js +0 -72
  660. package/lib/GraphHelpers.js +0 -46
  661. package/lib/ModuleParseError.js +0 -125
  662. package/lib/NoModeWarning.js +0 -23
  663. package/lib/css/CssMergeStyleSheetsRuntimeModule.js +0 -56
  664. package/lib/css/walkCssTokens.js +0 -1843
  665. package/lib/util/AppendOnlyStackedSet.js +0 -78
  666. /package/schemas/plugins/{DllPlugin.check.js → dll/DllPlugin.check.js} +0 -0
  667. /package/schemas/plugins/{DllPlugin.json → dll/DllPlugin.json} +0 -0
  668. /package/schemas/plugins/{DllReferencePlugin.check.js → dll/DllReferencePlugin.check.js} +0 -0
  669. /package/schemas/plugins/{DllReferencePlugin.json → dll/DllReferencePlugin.json} +0 -0
@@ -0,0 +1,4155 @@
1
+ /*
2
+ MIT License http://www.opensource.org/licenses/mit-license.php
3
+ Author Tobias Koppers @sokra
4
+ */
5
+
6
+ "use strict";
7
+
8
+ const LocConverter = require("../util/LocConverter");
9
+ const GenericSourceProcessor = require("../util/SourceProcessor");
10
+ const { makeCacheable } = require("../util/identifier");
11
+
12
+ // spec: https://drafts.csswg.org/css-syntax/
13
+
14
+ /**
15
+ * @typedef {object} CssWhitespaceToken
16
+ * @property {number} type
17
+ * @property {number} start byte offset of the first whitespace code point
18
+ * @property {number} end byte offset just past the last whitespace code point
19
+ */
20
+ /**
21
+ * @typedef {object} CssCommentToken
22
+ * @property {number} type
23
+ * @property {number} start byte offset of the opening `/`
24
+ * @property {number} end byte offset just past the closing `/`
25
+ */
26
+ /**
27
+ * @typedef {object} CssStringToken
28
+ * @property {number} type
29
+ * @property {number} start byte offset of the opening quote
30
+ * @property {number} end byte offset just past the closing quote (or EOF for unterminated strings)
31
+ */
32
+ /**
33
+ * @typedef {object} CssBadStringToken
34
+ * @property {number} type
35
+ * @property {number} start byte offset of the opening quote
36
+ * @property {number} end byte offset where parsing gave up (typically the newline that broke the string)
37
+ */
38
+ /**
39
+ * @typedef {object} CssLeftCurlyBracketToken
40
+ * @property {number} type
41
+ * @property {number} start byte offset of `{`
42
+ * @property {number} end `start + 1`
43
+ */
44
+ /**
45
+ * @typedef {object} CssRightCurlyBracketToken
46
+ * @property {number} type
47
+ * @property {number} start byte offset of `}`
48
+ * @property {number} end `start + 1`
49
+ */
50
+ /**
51
+ * @typedef {object} CssLeftSquareBracketToken
52
+ * @property {number} type
53
+ * @property {number} start byte offset of `[`
54
+ * @property {number} end `start + 1`
55
+ */
56
+ /**
57
+ * @typedef {object} CssRightSquareBracketToken
58
+ * @property {number} type
59
+ * @property {number} start byte offset of `]`
60
+ * @property {number} end `start + 1`
61
+ */
62
+ /**
63
+ * @typedef {object} CssLeftParenthesisToken
64
+ * @property {number} type
65
+ * @property {number} start byte offset of `(`
66
+ * @property {number} end `start + 1`
67
+ */
68
+ /**
69
+ * @typedef {object} CssRightParenthesisToken
70
+ * @property {number} type
71
+ * @property {number} start byte offset of `)`
72
+ * @property {number} end `start + 1`
73
+ */
74
+ /**
75
+ * @typedef {object} CssFunctionToken
76
+ * @property {number} type
77
+ * @property {number} start byte offset of the function name's first code point
78
+ * @property {number} end byte offset just past the `(` that closes the function token
79
+ */
80
+ /**
81
+ * @typedef {object} CssUrlToken
82
+ * @property {number} type
83
+ * @property {number} start byte offset of the `url(` keyword (i.e. the `u`)
84
+ * @property {number} end byte offset just past the closing `)` (or EOF)
85
+ * @property {number} contentStart byte offset of the first code point of the unquoted URL content (post leading whitespace)
86
+ * @property {number} contentEnd byte offset just past the last code point of the unquoted URL content (pre trailing whitespace / `)` / EOF)
87
+ */
88
+ /**
89
+ * @typedef {object} CssBadUrlToken
90
+ * @property {number} type
91
+ * @property {number} start byte offset of the `url(` keyword
92
+ * @property {number} end byte offset where parsing gave up (past the recovery `)` or EOF)
93
+ */
94
+ /**
95
+ * @typedef {object} CssColonToken
96
+ * @property {number} type
97
+ * @property {number} start byte offset of `:`
98
+ * @property {number} end `start + 1`
99
+ */
100
+ /**
101
+ * @typedef {object} CssAtKeywordToken
102
+ * @property {number} type
103
+ * @property {number} start byte offset of `@`
104
+ * @property {number} end byte offset just past the last ident-sequence code point
105
+ */
106
+ /**
107
+ * @typedef {object} CssDelimToken
108
+ * @property {number} type
109
+ * @property {number} start byte offset of the delim code point
110
+ * @property {number} end `start + 1`
111
+ */
112
+ /**
113
+ * @typedef {object} CssIdentToken
114
+ * @property {number} type
115
+ * @property {number} start byte offset of the first ident code point
116
+ * @property {number} end byte offset just past the last ident-sequence code point
117
+ */
118
+ /**
119
+ * @typedef {object} CssPercentageToken
120
+ * @property {number} type
121
+ * @property {number} start byte offset of the first numeric code point
122
+ * @property {number} end byte offset just past the `%`
123
+ */
124
+ /**
125
+ * @typedef {object} CssNumberToken
126
+ * @property {number} type
127
+ * @property {number} start byte offset of the first numeric code point
128
+ * @property {number} end byte offset just past the last numeric code point
129
+ */
130
+ /**
131
+ * @typedef {object} CssDimensionToken
132
+ * @property {number} type
133
+ * @property {number} start byte offset of the first numeric code point
134
+ * @property {number} end byte offset just past the last unit ident code point
135
+ * @property {number} unitStart byte offset of the first unit-ident code point (== end of the numeric run)
136
+ */
137
+ /**
138
+ * @typedef {object} CssHashToken
139
+ * @property {number} type
140
+ * @property {number} start byte offset of `#`
141
+ * @property {number} end byte offset just past the last ident-sequence code point
142
+ * @property {boolean} isId true when the hash starts an ident sequence (`#foo`), false for non-ident hashes (`#1abc`)
143
+ */
144
+ /**
145
+ * @typedef {object} CssSemicolonToken
146
+ * @property {number} type
147
+ * @property {number} start byte offset of `;`
148
+ * @property {number} end `start + 1`
149
+ */
150
+ /**
151
+ * @typedef {object} CssCommaToken
152
+ * @property {number} type
153
+ * @property {number} start byte offset of `,`
154
+ * @property {number} end `start + 1`
155
+ */
156
+ /**
157
+ * @typedef {object} CssCdoToken
158
+ * @property {number} type
159
+ * @property {number} start byte offset of `<`
160
+ * @property {number} end byte offset just past `<!--`
161
+ */
162
+ /**
163
+ * @typedef {object} CssCdcToken
164
+ * @property {number} type
165
+ * @property {number} start byte offset of `-`
166
+ * @property {number} end byte offset just past `-->`
167
+ */
168
+ /**
169
+ * @typedef {CssWhitespaceToken | CssCommentToken | CssStringToken | CssBadStringToken | CssLeftCurlyBracketToken | CssRightCurlyBracketToken | CssLeftSquareBracketToken | CssRightSquareBracketToken | CssLeftParenthesisToken | CssRightParenthesisToken | CssFunctionToken | CssUrlToken | CssBadUrlToken | CssColonToken | CssAtKeywordToken | CssDelimToken | CssIdentToken | CssPercentageToken | CssNumberToken | CssDimensionToken | CssHashToken | CssSemicolonToken | CssCommaToken | CssCdoToken | CssCdcToken} CssToken
170
+ */
171
+
172
+ const CC_LINE_FEED = "\n".charCodeAt(0);
173
+ const CC_CARRIAGE_RETURN = "\r".charCodeAt(0);
174
+ const CC_FORM_FEED = "\f".charCodeAt(0);
175
+
176
+ const CC_TAB = "\t".charCodeAt(0);
177
+ const CC_SPACE = " ".charCodeAt(0);
178
+
179
+ const CC_SOLIDUS = "/".charCodeAt(0);
180
+ const CC_REVERSE_SOLIDUS = "\\".charCodeAt(0);
181
+ const CC_ASTERISK = "*".charCodeAt(0);
182
+
183
+ const CC_LEFT_PARENTHESIS = "(".charCodeAt(0);
184
+ const CC_RIGHT_PARENTHESIS = ")".charCodeAt(0);
185
+ const CC_LEFT_CURLY = "{".charCodeAt(0);
186
+ const CC_RIGHT_CURLY = "}".charCodeAt(0);
187
+ const CC_LEFT_SQUARE = "[".charCodeAt(0);
188
+ const CC_RIGHT_SQUARE = "]".charCodeAt(0);
189
+
190
+ const CC_QUOTATION_MARK = '"'.charCodeAt(0);
191
+ const CC_APOSTROPHE = "'".charCodeAt(0);
192
+
193
+ const CC_FULL_STOP = ".".charCodeAt(0);
194
+ const CC_COLON = ":".charCodeAt(0);
195
+ const CC_SEMICOLON = ";".charCodeAt(0);
196
+ const CC_COMMA = ",".charCodeAt(0);
197
+ const CC_PERCENTAGE = "%".charCodeAt(0);
198
+ const CC_AT_SIGN = "@".charCodeAt(0);
199
+
200
+ const CC_LOW_LINE = "_".charCodeAt(0);
201
+ const CC_LOWER_A = "a".charCodeAt(0);
202
+ const CC_LOWER_D = "d".charCodeAt(0);
203
+ const CC_LOWER_F = "f".charCodeAt(0);
204
+ const CC_LOWER_E = "e".charCodeAt(0);
205
+ const CC_LOWER_U = "u".charCodeAt(0);
206
+ const CC_LOWER_R = "r".charCodeAt(0);
207
+ const CC_LOWER_L = "l".charCodeAt(0);
208
+ const CC_LOWER_Z = "z".charCodeAt(0);
209
+ const CC_EXCLAMATION = "!".charCodeAt(0);
210
+ const CC_UPPER_A = "A".charCodeAt(0);
211
+ const CC_UPPER_F = "F".charCodeAt(0);
212
+ const CC_UPPER_E = "E".charCodeAt(0);
213
+ const CC_UPPER_Z = "Z".charCodeAt(0);
214
+ const CC_0 = "0".charCodeAt(0);
215
+ const CC_9 = "9".charCodeAt(0);
216
+
217
+ const CC_NUMBER_SIGN = "#".charCodeAt(0);
218
+ const CC_PLUS_SIGN = "+".charCodeAt(0);
219
+ const CC_HYPHEN_MINUS = "-".charCodeAt(0);
220
+
221
+ const CC_LESS_THAN_SIGN = "<".charCodeAt(0);
222
+ const CC_GREATER_THAN_SIGN = ">".charCodeAt(0);
223
+
224
+ // Lexer token types (CSS Syntax Level 3 §4) plus the `<eof-token>`. Numeric so
225
+ // the per-token `type` slot stays compact and `next` / `consume` / the consume
226
+ // algorithms dispatch on integer `===` instead of string comparison. Exported
227
+ // alongside `readToken` (the per-token lexer primitive) for the unit test.
228
+ const TT_COMMENT = 1;
229
+ const TT_WHITESPACE = 2;
230
+ const TT_STRING = 3;
231
+ const TT_BAD_STRING_TOKEN = 4;
232
+ const TT_HASH = 5;
233
+ const TT_DELIM = 6;
234
+ // The three opening brackets are kept contiguous (7..9) so "is this an opening
235
+ // bracket?" is a single range check (`>= TT_LEFT_PARENTHESIS && <= TT_LEFT_CURLY_BRACKET`).
236
+ const TT_LEFT_PARENTHESIS = 7;
237
+ const TT_LEFT_SQUARE_BRACKET = 8;
238
+ const TT_LEFT_CURLY_BRACKET = 9;
239
+ const TT_RIGHT_PARENTHESIS = 10;
240
+ const TT_RIGHT_SQUARE_BRACKET = 11;
241
+ const TT_RIGHT_CURLY_BRACKET = 12;
242
+ const TT_COMMA = 13;
243
+ const TT_COLON = 14;
244
+ const TT_SEMICOLON = 15;
245
+ const TT_AT_KEYWORD = 16;
246
+ const TT_FUNCTION = 17;
247
+ const TT_URL = 18;
248
+ const TT_BAD_URL_TOKEN = 19;
249
+ const TT_IDENTIFIER = 20;
250
+ const TT_NUMBER = 21;
251
+ const TT_PERCENTAGE = 22;
252
+ const TT_DIMENSION = 23;
253
+ const TT_CDO = 24;
254
+ const TT_CDC = 25;
255
+ const TT_EOF = 26;
256
+
257
+ // The opening bracket types (7..9) and their mirror closers (10..12) are laid
258
+ // out so a closer is always `opener + 3`; `consumeASimpleBlock` uses that
259
+ // directly. The associated block char is a dense array indexed by the opener's
260
+ // offset from `TT_LEFT_PARENTHESIS` — a plain element load instead of a numeric
261
+ // object-key lookup.
262
+ /** @type {SimpleBlockToken[]} */
263
+ const BLOCK_TOKEN_CHAR = ["(", "[", "{"];
264
+
265
+ /**
266
+ * @param {number} cc char code
267
+ * @returns {boolean} true, if cc is a newline (per the spec: LF, CR, or FF)
268
+ */
269
+ const _isNewline = (cc) =>
270
+ cc === CC_LINE_FEED || cc === CC_CARRIAGE_RETURN || cc === CC_FORM_FEED;
271
+
272
+ /**
273
+ * If the source had a CR followed by an LF, advance past the LF —
274
+ * the spec normalises CRLF to LF during preprocessing.
275
+ * @param {number} cc char code already consumed (the CR)
276
+ * @param {string} input input
277
+ * @param {number} pos position just past `cc`
278
+ * @returns {number} position past the CRLF pair (or unchanged for bare CR)
279
+ */
280
+ const consumeExtraNewline = (cc, input, pos) => {
281
+ if (cc === CC_CARRIAGE_RETURN && input.charCodeAt(pos) === CC_LINE_FEED) {
282
+ pos++;
283
+ }
284
+ return pos;
285
+ };
286
+
287
+ /**
288
+ * @param {number} cc char code
289
+ * @returns {boolean} true, if cc is space or tab
290
+ */
291
+ const _isSpace = (cc) => cc === CC_SPACE || cc === CC_TAB;
292
+
293
+ /**
294
+ * @param {number} cc char code
295
+ * @returns {boolean} true, if cc is whitespace (space/tab/newline)
296
+ */
297
+ // Space-first: U+0020 is the common case, so it short-circuits before the
298
+ // rarer tab / newline tests.
299
+ const _isWhiteSpace = (cc) => _isSpace(cc) || _isNewline(cc);
300
+
301
+ // Whitespace membership table for the run-consumption loop — one load instead
302
+ // of up to five compares per char. EOF (NaN) / non-ASCII index to undefined.
303
+ const _wsTable = new Uint8Array(128);
304
+ _wsTable[CC_SPACE] = 1;
305
+ _wsTable[CC_TAB] = 1;
306
+ _wsTable[CC_LINE_FEED] = 1;
307
+ _wsTable[CC_CARRIAGE_RETURN] = 1;
308
+ _wsTable[CC_FORM_FEED] = 1;
309
+
310
+ /**
311
+ * @param {number} cc char code
312
+ * @returns {boolean} true, if cc is a digit
313
+ */
314
+ const _isDigit = (cc) => cc >= CC_0 && cc <= CC_9;
315
+
316
+ /**
317
+ * @param {number} cc char code
318
+ * @returns {boolean} true, if cc is a hex digit
319
+ */
320
+ const _isHexDigit = (cc) =>
321
+ _isDigit(cc) ||
322
+ (cc >= CC_UPPER_A && cc <= CC_UPPER_F) ||
323
+ (cc >= CC_LOWER_A && cc <= CC_LOWER_F);
324
+
325
+ /**
326
+ * @param {number} cc char code
327
+ * @returns {boolean} is letter (a-z / A-Z)
328
+ */
329
+ const _isLetter = (cc) =>
330
+ (cc >= CC_LOWER_A && cc <= CC_LOWER_Z) ||
331
+ (cc >= CC_UPPER_A && cc <= CC_UPPER_Z);
332
+
333
+ /**
334
+ * Spec: ident-start = letter / non-ASCII / `_`. Internal helper that
335
+ * accepts an explicit char code (lookahead).
336
+ * @param {number} cc char code
337
+ * @returns {boolean} true, if cc is an ident-start code point
338
+ */
339
+ const _isIdentStartCodePointCC = (cc) =>
340
+ _isLetter(cc) || cc >= 0x80 || cc === CC_LOW_LINE;
341
+
342
+ /**
343
+ * Spec: ident-code = ident-start / digit / hyphen-minus.
344
+ */
345
+ // Full `charCodeAt` range (0..0xFFFF) so the per-code-point ident test is one
346
+ // table load with no `cc < 128` branch — `_consumeAnIdentSequence` runs this on
347
+ // every character of every ident / class / property name (the tokenizer's
348
+ // hottest loop). Every non-ASCII code unit (>= 0x80) is an ident code point per
349
+ // spec, so those default to 1; only the ASCII rows carry real classification.
350
+ // Callers must index with `cc | 0`: EOF (`charCodeAt` → NaN) becomes 0 (NUL,
351
+ // not an ident) — a raw NaN index is an out-of-range access that permanently
352
+ // degrades the load site's IC.
353
+ const _identCharTable = new Uint8Array(0x10000).fill(1);
354
+ for (let i = 0; i < 128; i++) {
355
+ _identCharTable[i] =
356
+ _isLetter(i) || i === CC_LOW_LINE || _isDigit(i) || i === CC_HYPHEN_MINUS
357
+ ? 1
358
+ : 0;
359
+ }
360
+ /**
361
+ * @param {number} cc char code
362
+ * @returns {boolean} true, if cc is an ident-sequence code point
363
+ */
364
+ const _isIdentCodePoint = (cc) => _identCharTable[cc | 0] === 1;
365
+
366
+ /**
367
+ * ASCII case-insensitive equality against a lowercase literal — avoids the
368
+ * `toLowerCase()` allocation and matches CSS's ASCII case-insensitive keyword
369
+ * matching. `lit` must be lowercase ASCII.
370
+ * @param {string} s string to test
371
+ * @param {string} lit lowercase ASCII literal to match
372
+ * @returns {boolean} true, if `s` equals `lit` ignoring ASCII case
373
+ */
374
+ const equalsLowerCase = (s, lit) => {
375
+ if (s.length !== lit.length) return false;
376
+ for (let i = 0; i < lit.length; i++) {
377
+ let c = s.charCodeAt(i);
378
+ if (c >= CC_UPPER_A && c <= CC_UPPER_Z) c |= 0x20;
379
+ if (c !== lit.charCodeAt(i)) return false;
380
+ }
381
+ return true;
382
+ };
383
+
384
+ /**
385
+ * Case-sensitive equality of a source range against a literal — no slice.
386
+ * @param {string} input source
387
+ * @param {number} start range start
388
+ * @param {number} end range end (exclusive)
389
+ * @param {string} lit literal to match
390
+ * @returns {boolean} true when the range equals `lit`
391
+ */
392
+ const rangeEquals = (input, start, end, lit) =>
393
+ end - start === lit.length && input.startsWith(lit, start);
394
+
395
+ /**
396
+ * ASCII case-insensitive equality of a source range against a lowercase ASCII literal — no slice.
397
+ * @param {string} input source
398
+ * @param {number} start range start
399
+ * @param {number} end range end (exclusive)
400
+ * @param {string} lit lowercase ASCII literal to match
401
+ * @returns {boolean} true when the range equals `lit` ignoring ASCII case
402
+ */
403
+ const rangeEqualsLowerCase = (input, start, end, lit) => {
404
+ if (end - start !== lit.length) return false;
405
+ for (let i = 0; i < lit.length; i++) {
406
+ let c = input.charCodeAt(start + i);
407
+ if (c >= CC_UPPER_A && c <= CC_UPPER_Z) c |= 0x20;
408
+ if (c !== lit.charCodeAt(i)) return false;
409
+ }
410
+ return true;
411
+ };
412
+
413
+ /**
414
+ * `s.toLowerCase()` that returns `s` itself (no allocation) when it can't
415
+ * change — no ASCII uppercase and no non-ASCII (whose Unicode case mapping is
416
+ * left to the real `toLowerCase`).
417
+ * @param {string} s string
418
+ * @returns {string} lowercased string
419
+ */
420
+ const toLowerCaseIfNeeded = (s) => {
421
+ for (let i = 0; i < s.length; i++) {
422
+ const c = s.charCodeAt(i);
423
+ if ((c >= CC_UPPER_A && c <= CC_UPPER_Z) || c > 127) return s.toLowerCase();
424
+ }
425
+ return s;
426
+ };
427
+
428
+ /**
429
+ * A custom property name (`<dashed-ident>`): a `--`-prefixed identifier other than bare `--`.
430
+ * @param {string} identifier identifier
431
+ * @returns {boolean} true when identifier is dashed, otherwise false
432
+ */
433
+ const isDashedIdentifier = (identifier) =>
434
+ identifier.startsWith("--") && identifier.length >= 3;
435
+
436
+ /**
437
+ * Consume an escaped code point.
438
+ * @param {string} input input
439
+ * @param {number} pos position just past the `\`
440
+ * @returns {number} position past the escape sequence
441
+ */
442
+ const _consumeAnEscapedCodePoint = (input, pos) => {
443
+ // Caller has verified the `\` and the next code point form a valid
444
+ // escape. Hex digits: consume up to 6 hex digits, then one optional
445
+ // whitespace. Non-hex: consume one code point.
446
+ // `\` at EOF: nothing to consume; return pos so callers don't overrun.
447
+ if (pos >= input.length) return pos;
448
+ const cc = input.charCodeAt(pos);
449
+ pos++;
450
+ if (pos === input.length) return pos;
451
+ if (_isHexDigit(cc)) {
452
+ for (let i = 0; i < 5; i++) {
453
+ if (!_isHexDigit(input.charCodeAt(pos))) break;
454
+ pos++;
455
+ }
456
+ const trail = input.charCodeAt(pos);
457
+ if (_isWhiteSpace(trail)) {
458
+ pos++;
459
+ pos = consumeExtraNewline(trail, input, pos);
460
+ }
461
+ }
462
+ return pos;
463
+ };
464
+
465
+ /**
466
+ * Spec: "two code points are a valid escape" — first is `\`, second is
467
+ * not a newline.
468
+ * @param {string} input input
469
+ * @param {number} pos position of the second code point
470
+ * @param {number=} f first code point (defaults to `input.charCodeAt(pos - 1)`)
471
+ * @param {number=} s second code point (defaults to `input.charCodeAt(pos)`)
472
+ * @returns {boolean} true, if the two code points form a valid escape
473
+ */
474
+ const _ifTwoCodePointsAreValidEscape = (input, pos, f, s) => {
475
+ const first = f || input.charCodeAt(pos - 1);
476
+ const second = s || input.charCodeAt(pos);
477
+ if (first !== CC_REVERSE_SOLIDUS) return false;
478
+ if (_isNewline(second)) return false;
479
+ return true;
480
+ };
481
+
482
+ /**
483
+ * Spec: "three code points would start an ident sequence".
484
+ * @param {string} input input
485
+ * @param {number} pos position
486
+ * @param {number=} f first code point (defaults to `input.charCodeAt(pos - 1)`)
487
+ * @param {number=} s second code point (defaults to `input.charCodeAt(pos)`)
488
+ * @param {number=} t third code point (defaults to `input.charCodeAt(pos + 1)`)
489
+ * @returns {boolean} true, if the three code points start an ident sequence
490
+ */
491
+ const _ifThreeCodePointsWouldStartAnIdentSequence = (input, pos, f, s, t) => {
492
+ const first = f || input.charCodeAt(pos - 1);
493
+ const second = s || input.charCodeAt(pos);
494
+ const third = t || input.charCodeAt(pos + 1);
495
+ if (first === CC_HYPHEN_MINUS) {
496
+ return (
497
+ _isIdentStartCodePointCC(second) ||
498
+ second === CC_HYPHEN_MINUS ||
499
+ _ifTwoCodePointsAreValidEscape(input, pos, second, third)
500
+ );
501
+ }
502
+ if (_isIdentStartCodePointCC(first)) return true;
503
+ if (first === CC_REVERSE_SOLIDUS) {
504
+ return _ifTwoCodePointsAreValidEscape(input, pos, first, second);
505
+ }
506
+ return false;
507
+ };
508
+
509
+ /**
510
+ * Spec: "three code points would start a number".
511
+ * @param {string} input input
512
+ * @param {number} pos position
513
+ * @param {number=} f first code point
514
+ * @param {number=} s second code point
515
+ * @param {number=} t third code point
516
+ * @returns {boolean} true, if the three code points start a number
517
+ */
518
+ const _ifThreeCodePointsWouldStartANumber = (input, pos, f, s, t) => {
519
+ const first = f || input.charCodeAt(pos - 1);
520
+ const second = s || input.charCodeAt(pos);
521
+ const third = t || input.charCodeAt(pos + 1);
522
+ if (first === CC_PLUS_SIGN || first === CC_HYPHEN_MINUS) {
523
+ if (_isDigit(second)) return true;
524
+ return second === CC_FULL_STOP && _isDigit(third);
525
+ }
526
+ if (first === CC_FULL_STOP) return _isDigit(second);
527
+ /* istanbul ignore next -- @preserve: spec-general; every caller passes `pos` just past a +/-/. so `first` is never a bare digit here */
528
+ return _isDigit(first);
529
+ };
530
+
531
+ /**
532
+ * Consume an ident sequence (no validation of the first code points).
533
+ * @param {string} input input
534
+ * @param {number} pos position
535
+ * @returns {number} position just past the last ident-sequence code point
536
+ */
537
+ const _consumeAnIdentSequence = (input, pos) => {
538
+ // Hot loop (every ident, at-keyword, hash, function name, unit). Both checks
539
+ // are inlined from `_isIdentCodePoint` / `_ifTwoCodePointsAreValidEscape`: the
540
+ // ident test is a single full-range table load (no `cc < 128` branch), and the
541
+ // escape test reads the following code point only when `cc` is a `\` (rare)
542
+ // instead of eagerly.
543
+ for (;;) {
544
+ const cc = input.charCodeAt(pos) | 0;
545
+ pos++;
546
+ if (_identCharTable[cc] === 1) {
547
+ continue;
548
+ }
549
+ if (cc === CC_REVERSE_SOLIDUS && !_isNewline(input.charCodeAt(pos))) {
550
+ pos = _consumeAnEscapedCodePoint(input, pos);
551
+ continue;
552
+ }
553
+ return pos - 1;
554
+ }
555
+ };
556
+
557
+ /**
558
+ * @param {number} cc char code
559
+ * @returns {boolean} true, if cc is a non-printable code point
560
+ */
561
+ const _isNonPrintableCodePoint = (cc) =>
562
+ (cc >= 0x00 && cc <= 0x08) ||
563
+ cc === 0x0b ||
564
+ (cc >= 0x0e && cc <= 0x1f) ||
565
+ cc === 0x7f;
566
+
567
+ /**
568
+ * Consume the body of a number per the spec (does not classify integer
569
+ * vs number — caller / token type handles that).
570
+ * @param {string} input input
571
+ * @param {number} pos position at the first numeric / sign code point
572
+ * @returns {number} position just past the number
573
+ */
574
+ const _consumeANumber = (input, pos) => {
575
+ let cc = input.charCodeAt(pos);
576
+ if (cc === CC_HYPHEN_MINUS || cc === CC_PLUS_SIGN) {
577
+ pos++;
578
+ }
579
+ while (_isDigit(input.charCodeAt(pos))) pos++;
580
+ if (
581
+ input.charCodeAt(pos) === CC_FULL_STOP &&
582
+ _isDigit(input.charCodeAt(pos + 1))
583
+ ) {
584
+ pos++;
585
+ while (_isDigit(input.charCodeAt(pos))) pos++;
586
+ }
587
+ cc = input.charCodeAt(pos);
588
+ if (
589
+ (cc === CC_LOWER_E || cc === CC_UPPER_E) &&
590
+ (((input.charCodeAt(pos + 1) === CC_HYPHEN_MINUS ||
591
+ input.charCodeAt(pos + 1) === CC_PLUS_SIGN) &&
592
+ _isDigit(input.charCodeAt(pos + 2))) ||
593
+ _isDigit(input.charCodeAt(pos + 1)))
594
+ ) {
595
+ pos++;
596
+ cc = input.charCodeAt(pos);
597
+ if (cc === CC_PLUS_SIGN || cc === CC_HYPHEN_MINUS) {
598
+ pos++;
599
+ }
600
+ while (_isDigit(input.charCodeAt(pos))) pos++;
601
+ }
602
+ return pos;
603
+ };
604
+
605
+ /**
606
+ * Spec recovery: when the tokenizer realises it's mid-bad-url, consume
607
+ * until `)` or EOF.
608
+ * @param {string} input input
609
+ * @param {number} pos position
610
+ * @returns {number} position past the recovery `)` or EOF
611
+ */
612
+ const _consumeTheRemnantsOfABadUrl = (input, pos) => {
613
+ for (;;) {
614
+ if (pos === input.length) return pos;
615
+ const cc = input.charCodeAt(pos);
616
+ pos++;
617
+ if (cc === CC_RIGHT_PARENTHESIS) return pos;
618
+ if (_ifTwoCodePointsAreValidEscape(input, pos)) {
619
+ pos = _consumeAnEscapedCodePoint(input, pos);
620
+ }
621
+ }
622
+ };
623
+
624
+ /**
625
+ * A mutable lexer token. The `next` / `consume` hot path reuses a single
626
+ * instance per `TokenStream` (the lexer writes into it instead of allocating
627
+ * one object per token), which also keeps the parser's `t.type` reads
628
+ * monomorphic. All fields are present from construction so the shape never
629
+ * transitions; type-specific fields (`isId` / `contentStart` / `contentEnd` /
630
+ * `unitStart`) carry stale values for unrelated token types and are only read
631
+ * by `tokenToNode` for the matching type. Pass a fresh one per `readToken` call
632
+ * to collect the raw token list (e.g. tests).
633
+ * @typedef {object} MutableToken
634
+ * @property {number} type one of the `TT_*` constants
635
+ * @property {number} start byte offset of the token's first code point
636
+ * @property {number} end byte offset just past the token's last code point
637
+ * @property {boolean} isId hash tokens: starts an ident sequence
638
+ * @property {number} contentStart url tokens: first content code point
639
+ * @property {number} contentEnd url tokens: just past the last content code point
640
+ * @property {number} unitStart dimension tokens: first unit-ident code point
641
+ */
642
+
643
+ /**
644
+ * @returns {MutableToken} a fresh lexer token with the canonical shape
645
+ */
646
+ const createToken = () => ({
647
+ type: TT_EOF,
648
+ start: 0,
649
+ end: 0,
650
+ isId: false,
651
+ contentStart: 0,
652
+ contentEnd: 0,
653
+ unitStart: 0
654
+ });
655
+
656
+ /**
657
+ * Populate `out`'s common fields and return it — the lexer functions' return
658
+ * statement (kept tiny so V8 can inline it).
659
+ * @param {MutableToken} out token to populate
660
+ * @param {number} type one of the `TT_*` constants
661
+ * @param {number} start byte offset of the token's first code point
662
+ * @param {number} end byte offset just past the token's last code point
663
+ * @returns {MutableToken} `out`
664
+ */
665
+ const fill = (out, type, start, end) => {
666
+ out.type = type;
667
+ out.start = start;
668
+ out.end = end;
669
+ return out;
670
+ };
671
+
672
+ /**
673
+ * Whitespace token. Caller advances past the leading code point so
674
+ * `start = pos - 1`.
675
+ * @param {string} input input
676
+ * @param {number} pos position just past the first whitespace code point
677
+ * @param {MutableToken} out token to populate
678
+ * @returns {MutableToken | undefined} the resulting token, or undefined at EOF
679
+ */
680
+ function consumeSpace(input, pos, out) {
681
+ const start = pos - 1;
682
+ while (_wsTable[input.charCodeAt(pos)] === 1) pos++;
683
+ return fill(out, TT_WHITESPACE, start, pos);
684
+ }
685
+
686
+ // Sticky fast-forward classes: a native run-skip over the ordinary characters of
687
+ // a string / url token, so long values (data: URIs, base64) don't cost one JS
688
+ // char read each. The negated classes match exactly the per-char terminators the
689
+ // loops below handle (quotes / backslash / newlines for strings; plus `(`, `)`,
690
+ // whitespace and non-printable code points for urls).
691
+ const _STRING_SAFE = /[^"'\\\n\r\f]+/y;
692
+ // eslint-disable-next-line no-control-regex -- url terminators include the control range and DEL (they make a bad-url)
693
+ const _URL_SAFE = /[^\u0000-\u0020\u007F"'()\\]+/y;
694
+
695
+ /**
696
+ * Consume a string token. Caller advanced past the opening quote so
697
+ * `pos - 1` holds the ending code point and `pos - 1` is the start.
698
+ * @param {string} input input
699
+ * @param {number} pos position just past the opening quote
700
+ * @param {MutableToken} out token to populate
701
+ * @returns {MutableToken | undefined} the resulting token, or undefined at EOF
702
+ */
703
+ function consumeAStringToken(input, pos, out) {
704
+ const start = pos - 1;
705
+ const endingCodePoint = input.charCodeAt(pos - 1);
706
+ for (;;) {
707
+ _STRING_SAFE.lastIndex = pos;
708
+ if (_STRING_SAFE.test(input)) pos = _STRING_SAFE.lastIndex;
709
+ if (pos === input.length) {
710
+ return fill(out, TT_STRING, start, pos);
711
+ }
712
+ const cc = input.charCodeAt(pos);
713
+ pos++;
714
+ if (cc === endingCodePoint) {
715
+ return fill(out, TT_STRING, start, pos);
716
+ }
717
+ if (_isNewline(cc)) {
718
+ pos--;
719
+ return fill(out, TT_BAD_STRING_TOKEN, start, pos);
720
+ }
721
+ if (cc === CC_REVERSE_SOLIDUS) {
722
+ // `\` at EOF: string ends here; emit the token so ranges cover all input.
723
+ if (pos === input.length) return fill(out, TT_STRING, start, pos);
724
+ if (_isNewline(input.charCodeAt(pos))) {
725
+ const ccNl = input.charCodeAt(pos);
726
+ pos++;
727
+ pos = consumeExtraNewline(ccNl, input, pos);
728
+ } else if (_ifTwoCodePointsAreValidEscape(input, pos)) {
729
+ pos = _consumeAnEscapedCodePoint(input, pos);
730
+ }
731
+ }
732
+ }
733
+ }
734
+
735
+ /**
736
+ * `#` — hash or delim.
737
+ * @param {string} input input
738
+ * @param {number} pos position just past `#`
739
+ * @param {MutableToken} out token to populate
740
+ * @returns {MutableToken | undefined} the resulting token, or undefined at EOF
741
+ */
742
+ function consumeNumberSign(input, pos, out) {
743
+ const start = pos - 1;
744
+ const first = input.charCodeAt(pos);
745
+ const second = input.charCodeAt(pos + 1);
746
+ if (
747
+ _isIdentCodePoint(first) ||
748
+ _ifTwoCodePointsAreValidEscape(input, pos, first, second)
749
+ ) {
750
+ const third = input.charCodeAt(pos + 2);
751
+ out.isId = _ifThreeCodePointsWouldStartAnIdentSequence(
752
+ input,
753
+ pos,
754
+ first,
755
+ second,
756
+ third
757
+ );
758
+ pos = _consumeAnIdentSequence(input, pos);
759
+ return fill(out, TT_HASH, start, pos);
760
+ }
761
+ return fill(out, TT_DELIM, start, pos);
762
+ }
763
+
764
+ /**
765
+ * `-` — number / cdc / ident / delim.
766
+ * @param {string} input input
767
+ * @param {number} pos position just past `-`
768
+ * @param {MutableToken} out token to populate
769
+ * @returns {MutableToken | undefined} the resulting token, or undefined at EOF
770
+ */
771
+ function consumeHyphenMinus(input, pos, out) {
772
+ // Read the two lookahead code points once; the lead is the known `-`.
773
+ const second = input.charCodeAt(pos);
774
+ const third = input.charCodeAt(pos + 1);
775
+ if (
776
+ _ifThreeCodePointsWouldStartANumber(
777
+ input,
778
+ pos,
779
+ CC_HYPHEN_MINUS,
780
+ second,
781
+ third
782
+ )
783
+ ) {
784
+ pos--;
785
+ return consumeANumericToken(input, pos, out);
786
+ }
787
+ if (second === CC_HYPHEN_MINUS && third === CC_GREATER_THAN_SIGN) {
788
+ return fill(out, TT_CDC, pos - 1, pos + 2);
789
+ }
790
+ if (
791
+ _ifThreeCodePointsWouldStartAnIdentSequence(
792
+ input,
793
+ pos,
794
+ CC_HYPHEN_MINUS,
795
+ second,
796
+ third
797
+ )
798
+ ) {
799
+ pos--;
800
+ return consumeAnIdentLikeToken(input, pos, out);
801
+ }
802
+ return fill(out, TT_DELIM, pos - 1, pos);
803
+ }
804
+
805
+ /**
806
+ * `.` — number or delim.
807
+ * @param {string} input input
808
+ * @param {number} pos position just past `.`
809
+ * @param {MutableToken} out token to populate
810
+ * @returns {MutableToken | undefined} the resulting token, or undefined at EOF
811
+ */
812
+ function consumeFullStop(input, pos, out) {
813
+ const start = pos - 1;
814
+ if (_ifThreeCodePointsWouldStartANumber(input, pos)) {
815
+ pos--;
816
+ return consumeANumericToken(input, pos, out);
817
+ }
818
+ return fill(out, TT_DELIM, start, pos);
819
+ }
820
+
821
+ /**
822
+ * `+` — number or delim.
823
+ * @param {string} input input
824
+ * @param {number} pos position just past `+`
825
+ * @param {MutableToken} out token to populate
826
+ * @returns {MutableToken | undefined} the resulting token, or undefined at EOF
827
+ */
828
+ function consumePlusSign(input, pos, out) {
829
+ const start = pos - 1;
830
+ if (_ifThreeCodePointsWouldStartANumber(input, pos)) {
831
+ pos--;
832
+ return consumeANumericToken(input, pos, out);
833
+ }
834
+ return fill(out, TT_DELIM, start, pos);
835
+ }
836
+
837
+ /**
838
+ * Numeric token: number / percentage / dimension.
839
+ * @param {string} input input
840
+ * @param {number} pos position at the first numeric/sign code point
841
+ * @param {MutableToken} out token to populate
842
+ * @returns {MutableToken | undefined} the resulting token, or undefined at EOF
843
+ */
844
+ function consumeANumericToken(input, pos, out) {
845
+ const start = pos;
846
+ pos = _consumeANumber(input, pos);
847
+ const first = input.charCodeAt(pos);
848
+ // A unit can only begin with `-`, `\`, or an ident-start code point — exactly
849
+ // the cases where the §4 "would start an ident sequence" check can be true. For
850
+ // a plain number (next char is whitespace / `;` / `,` / `)` / EOF, the common
851
+ // case) skip the two lookahead reads and the call entirely.
852
+ if (
853
+ (first === CC_HYPHEN_MINUS ||
854
+ first === CC_REVERSE_SOLIDUS ||
855
+ _isIdentStartCodePointCC(first)) &&
856
+ _ifThreeCodePointsWouldStartAnIdentSequence(
857
+ input,
858
+ pos,
859
+ first,
860
+ input.charCodeAt(pos + 1),
861
+ input.charCodeAt(pos + 2)
862
+ )
863
+ ) {
864
+ out.unitStart = pos;
865
+ pos = _consumeAnIdentSequence(input, pos);
866
+ return fill(out, TT_DIMENSION, start, pos);
867
+ }
868
+ if (first === CC_PERCENTAGE) {
869
+ return fill(out, TT_PERCENTAGE, start, pos + 1);
870
+ }
871
+ return fill(out, TT_NUMBER, start, pos);
872
+ }
873
+
874
+ /**
875
+ * Consume an unquoted url token. Caller has already eaten `url(` and
876
+ * any leading whitespace.
877
+ * @param {string} input input
878
+ * @param {number} pos position at the first content code point
879
+ * @param {number} fnStart byte offset of the `u` in `url(`
880
+ * @param {MutableToken} out token to populate
881
+ * @returns {MutableToken | undefined} the resulting token, or undefined at EOF
882
+ */
883
+ function consumeAUrlToken(input, pos, fnStart, out) {
884
+ while (_isWhiteSpace(input.charCodeAt(pos))) pos++;
885
+ const contentStart = pos;
886
+ out.contentStart = contentStart;
887
+ for (;;) {
888
+ _URL_SAFE.lastIndex = pos;
889
+ if (_URL_SAFE.test(input)) pos = _URL_SAFE.lastIndex;
890
+ if (pos === input.length) {
891
+ out.contentEnd = pos;
892
+ return fill(out, TT_URL, fnStart, pos);
893
+ }
894
+ const cc = input.charCodeAt(pos);
895
+ pos++;
896
+ if (cc === CC_RIGHT_PARENTHESIS) {
897
+ out.contentEnd = pos - 1;
898
+ return fill(out, TT_URL, fnStart, pos);
899
+ }
900
+ if (_isWhiteSpace(cc)) {
901
+ const end = pos - 1;
902
+ while (_isWhiteSpace(input.charCodeAt(pos))) pos++;
903
+ if (pos === input.length) {
904
+ out.contentEnd = end;
905
+ return fill(out, TT_URL, fnStart, pos);
906
+ }
907
+ if (input.charCodeAt(pos) === CC_RIGHT_PARENTHESIS) {
908
+ pos++;
909
+ out.contentEnd = end;
910
+ return fill(out, TT_URL, fnStart, pos);
911
+ }
912
+ pos = _consumeTheRemnantsOfABadUrl(input, pos);
913
+ return fill(out, TT_BAD_URL_TOKEN, fnStart, pos);
914
+ }
915
+ if (
916
+ cc === CC_QUOTATION_MARK ||
917
+ cc === CC_APOSTROPHE ||
918
+ cc === CC_LEFT_PARENTHESIS ||
919
+ _isNonPrintableCodePoint(cc)
920
+ ) {
921
+ pos = _consumeTheRemnantsOfABadUrl(input, pos);
922
+ return fill(out, TT_BAD_URL_TOKEN, fnStart, pos);
923
+ }
924
+ if (cc === CC_REVERSE_SOLIDUS) {
925
+ if (_ifTwoCodePointsAreValidEscape(input, pos)) {
926
+ pos = _consumeAnEscapedCodePoint(input, pos);
927
+ } else {
928
+ pos = _consumeTheRemnantsOfABadUrl(input, pos);
929
+ return fill(out, TT_BAD_URL_TOKEN, fnStart, pos);
930
+ }
931
+ }
932
+ }
933
+ }
934
+
935
+ /**
936
+ * Consume an ident-like token: ident / function / url / bad-url.
937
+ * @param {string} input input
938
+ * @param {number} pos position at the first ident-start code point
939
+ * @param {MutableToken} out token to populate
940
+ * @returns {MutableToken | undefined} the resulting token, or undefined at EOF
941
+ */
942
+ function consumeAnIdentLikeToken(input, pos, out) {
943
+ const start = pos;
944
+ pos = _consumeAnIdentSequence(input, pos);
945
+ // `url` case-insensitively (ASCII lower via `| 0x20`) without a
946
+ // `slice().toLowerCase()` allocation per identifier; an escaped ident can't
947
+ // be exactly 3 raw chars, so the length gate keeps this equivalent.
948
+ if (
949
+ pos - start === 3 &&
950
+ (input.charCodeAt(start) | 0x20) === CC_LOWER_U &&
951
+ (input.charCodeAt(start + 1) | 0x20) === CC_LOWER_R &&
952
+ (input.charCodeAt(start + 2) | 0x20) === CC_LOWER_L &&
953
+ input.charCodeAt(pos) === CC_LEFT_PARENTHESIS
954
+ ) {
955
+ pos++;
956
+ const end = pos;
957
+ while (
958
+ _isWhiteSpace(input.charCodeAt(pos)) &&
959
+ _isWhiteSpace(input.charCodeAt(pos + 1))
960
+ ) {
961
+ pos++;
962
+ }
963
+ if (
964
+ input.charCodeAt(pos) === CC_QUOTATION_MARK ||
965
+ input.charCodeAt(pos) === CC_APOSTROPHE ||
966
+ (_isWhiteSpace(input.charCodeAt(pos)) &&
967
+ (input.charCodeAt(pos + 1) === CC_QUOTATION_MARK ||
968
+ input.charCodeAt(pos + 1) === CC_APOSTROPHE))
969
+ ) {
970
+ // End at `end` (the `(`'s closer position), not `pos` — the
971
+ // lookahead-eaten whitespace must be re-tokenized as a whitespace
972
+ // token rather than swallowed silently. The reader resumes at
973
+ // `token.end`, so returning `end` here does that.
974
+ return fill(out, TT_FUNCTION, start, end);
975
+ }
976
+ return consumeAUrlToken(input, pos, start, out);
977
+ }
978
+ if (input.charCodeAt(pos) === CC_LEFT_PARENTHESIS) {
979
+ pos++;
980
+ return fill(out, TT_FUNCTION, start, pos);
981
+ }
982
+ return fill(out, TT_IDENTIFIER, start, pos);
983
+ }
984
+
985
+ /**
986
+ * `<` — CDO or delim.
987
+ * @param {string} input input
988
+ * @param {number} pos position just past `<`
989
+ * @param {MutableToken} out token to populate
990
+ * @returns {MutableToken | undefined} the resulting token, or undefined at EOF
991
+ */
992
+ function consumeLessThan(input, pos, out) {
993
+ if (
994
+ input.charCodeAt(pos) === CC_EXCLAMATION &&
995
+ input.charCodeAt(pos + 1) === CC_HYPHEN_MINUS &&
996
+ input.charCodeAt(pos + 2) === CC_HYPHEN_MINUS
997
+ ) {
998
+ return fill(out, TT_CDO, pos - 1, pos + 3);
999
+ }
1000
+ return fill(out, TT_DELIM, pos - 1, pos);
1001
+ }
1002
+
1003
+ /**
1004
+ * `@` — at-keyword or delim.
1005
+ * @param {string} input input
1006
+ * @param {number} pos position just past `@`
1007
+ * @param {MutableToken} out token to populate
1008
+ * @returns {MutableToken | undefined} the resulting token, or undefined at EOF
1009
+ */
1010
+ function consumeCommercialAt(input, pos, out) {
1011
+ const start = pos - 1;
1012
+ if (
1013
+ _ifThreeCodePointsWouldStartAnIdentSequence(
1014
+ input,
1015
+ pos,
1016
+ input.charCodeAt(pos),
1017
+ input.charCodeAt(pos + 1),
1018
+ input.charCodeAt(pos + 2)
1019
+ )
1020
+ ) {
1021
+ pos = _consumeAnIdentSequence(input, pos);
1022
+ return fill(out, TT_AT_KEYWORD, start, pos);
1023
+ }
1024
+ return fill(out, TT_DELIM, start, pos);
1025
+ }
1026
+
1027
+ /**
1028
+ * `\` — escape starts an ident-like token, otherwise it's a delim.
1029
+ * @param {string} input input
1030
+ * @param {number} pos position just past `\`
1031
+ * @param {MutableToken} out token to populate
1032
+ * @returns {MutableToken | undefined} the resulting token, or undefined at EOF
1033
+ */
1034
+ function consumeReverseSolidus(input, pos, out) {
1035
+ if (_ifTwoCodePointsAreValidEscape(input, pos)) {
1036
+ pos--;
1037
+ return consumeAnIdentLikeToken(input, pos, out);
1038
+ }
1039
+ return fill(out, TT_DELIM, pos - 1, pos);
1040
+ }
1041
+
1042
+ // `consumeAToken` dispatch: the §4 token rules keyed by the lead code point are
1043
+ // === Tokenizer lead-character dispatch (CSS Syntax Level 3 §4 "consume a token") ===
1044
+ //
1045
+ // `consumeAToken` selects a sub-routine from the first ("lead") code point of each
1046
+ // token. The §4 rules are keyed on specific code points (`"` `#` `(` digit
1047
+ // ident-start …) that sit SPARSELY across the ASCII range, so a plain `switch (cc)`
1048
+ // compiles to a jump table spanning U+0009..U+007D in which the most common lead —
1049
+ // an ident-start letter — is not a case and reaches its handler only after the
1050
+ // digit/whitespace tests miss. `_charClass` precomputes, for every ASCII code
1051
+ // point, a dense handler id (`HC_*`, 0..12) so `consumeAToken` is one array load +
1052
+ // a compact 13-entry jump table and idents dispatch directly. Non-ASCII
1053
+ // (cc >= 128) is always ident-start per §4, so it skips the table.
1054
+ //
1055
+ // Extending for a spec change: repoint the code point in the build loop below; if
1056
+ // it needs a new sub-routine, add an `HC_*` id, a `case` in `consumeAToken`, and a
1057
+ // row here. This list is the authoritative "which lead code point dispatches
1058
+ // where" map (§4 "consume a token", step by lead code point):
1059
+ //
1060
+ // HC_WHITESPACE whitespace U+0009 TAB U+000A LF U+000C FF U+000D CR U+0020 SPACE
1061
+ // HC_STRING string start U+0022 " U+0027 '
1062
+ // HC_SINGLE one-char token ( ) , : ; [ ] { } (its token type comes from `_singleTT`)
1063
+ // HC_NUMBER_SIGN hash / delim U+0023 #
1064
+ // HC_PLUS_SIGN number / delim U+002B +
1065
+ // HC_HYPHEN_MINUS number / CDC / ident / delim U+002D -
1066
+ // HC_FULL_STOP number / delim U+002E .
1067
+ // HC_LESS_THAN CDO / delim U+003C <
1068
+ // HC_AT_SIGN at-keyword / delim U+0040 @
1069
+ // HC_REVERSE_SOLIDUS escape / delim U+005C \
1070
+ // HC_DIGIT number U+0030..U+0039 0-9
1071
+ // HC_IDENT ident-like U+0041..U+005A A-Z U+0061..U+007A a-z U+005F _ (plus cc >= 128)
1072
+ // HC_DELIM anything else -> a single <delim-token>
1073
+ //
1074
+ // `_singleTT[cc]` is the token type for the HC_SINGLE code points (a second table
1075
+ // so they share one handler instead of one `case` each). The default class 0 is
1076
+ // the delim handler (anything not matched below), so it needs no named constant.
1077
+ const HC_WHITESPACE = 1;
1078
+ const HC_STRING = 2;
1079
+ const HC_SINGLE = 3;
1080
+ const HC_NUMBER_SIGN = 4;
1081
+ const HC_PLUS_SIGN = 5;
1082
+ const HC_HYPHEN_MINUS = 6;
1083
+ const HC_FULL_STOP = 7;
1084
+ const HC_LESS_THAN = 8;
1085
+ const HC_AT_SIGN = 9;
1086
+ const HC_REVERSE_SOLIDUS = 10;
1087
+ const HC_DIGIT = 11;
1088
+ const HC_IDENT = 12;
1089
+ // Full `charCodeAt` range so `consumeAToken` dispatches with one table load and
1090
+ // no `cc < 128` branch. Every non-ASCII code point (>= 0x80) is an ident-start
1091
+ // lead per §4, so those rows are seeded to `HC_IDENT`; the ASCII rows below
1092
+ // overwrite 0..127 with their real class.
1093
+ const _charClass = new Uint8Array(0x10000).fill(HC_IDENT, 128);
1094
+ const _singleTT = new Uint8Array(128);
1095
+ _singleTT[CC_LEFT_PARENTHESIS] = TT_LEFT_PARENTHESIS;
1096
+ _singleTT[CC_RIGHT_PARENTHESIS] = TT_RIGHT_PARENTHESIS;
1097
+ _singleTT[CC_COMMA] = TT_COMMA;
1098
+ _singleTT[CC_COLON] = TT_COLON;
1099
+ _singleTT[CC_SEMICOLON] = TT_SEMICOLON;
1100
+ _singleTT[CC_LEFT_SQUARE] = TT_LEFT_SQUARE_BRACKET;
1101
+ _singleTT[CC_RIGHT_SQUARE] = TT_RIGHT_SQUARE_BRACKET;
1102
+ _singleTT[CC_LEFT_CURLY] = TT_LEFT_CURLY_BRACKET;
1103
+ _singleTT[CC_RIGHT_CURLY] = TT_RIGHT_CURLY_BRACKET;
1104
+ // Each ASCII code point belongs to exactly one class; HC_SINGLE is seeded from
1105
+ // `_singleTT` above, the rest follow §4's lead-code-point rules, and everything
1106
+ // unmatched stays the delim class (0). Keep this in sync with the table above.
1107
+ for (let i = 0; i < 128; i++) {
1108
+ if (_singleTT[i] !== 0) {
1109
+ _charClass[i] = HC_SINGLE;
1110
+ } else if (_isWhiteSpace(i)) {
1111
+ _charClass[i] = HC_WHITESPACE;
1112
+ } else if (i === CC_QUOTATION_MARK || i === CC_APOSTROPHE) {
1113
+ _charClass[i] = HC_STRING;
1114
+ } else if (i === CC_NUMBER_SIGN) {
1115
+ _charClass[i] = HC_NUMBER_SIGN;
1116
+ } else if (i === CC_PLUS_SIGN) {
1117
+ _charClass[i] = HC_PLUS_SIGN;
1118
+ } else if (i === CC_HYPHEN_MINUS) {
1119
+ _charClass[i] = HC_HYPHEN_MINUS;
1120
+ } else if (i === CC_FULL_STOP) {
1121
+ _charClass[i] = HC_FULL_STOP;
1122
+ } else if (i === CC_LESS_THAN_SIGN) {
1123
+ _charClass[i] = HC_LESS_THAN;
1124
+ } else if (i === CC_AT_SIGN) {
1125
+ _charClass[i] = HC_AT_SIGN;
1126
+ } else if (i === CC_REVERSE_SOLIDUS) {
1127
+ _charClass[i] = HC_REVERSE_SOLIDUS;
1128
+ } else if (_isDigit(i)) {
1129
+ _charClass[i] = HC_DIGIT;
1130
+ } else if (_isIdentStartCodePointCC(i)) {
1131
+ _charClass[i] = HC_IDENT;
1132
+ }
1133
+ // else stays the delim class (0)
1134
+ }
1135
+
1136
+ /**
1137
+ * Per-character dispatcher. The outer loop has already advanced past
1138
+ * the lead code point (`pos - 1` is the lead).
1139
+ * @param {string} input input
1140
+ * @param {number} pos position just past the lead code point
1141
+ * @param {number} cc the lead code point (`input.charCodeAt(pos - 1)`, already read by the caller)
1142
+ * @param {MutableToken} out token to populate
1143
+ * @returns {MutableToken | undefined} the resulting token, or undefined at EOF
1144
+ */
1145
+ function consumeAToken(input, pos, cc, out) {
1146
+ // `u` / `U` would start a unicode-range token in the spec; those are not
1147
+ // produced, so they map to HC_IDENT and fall through to ident-like.
1148
+ switch (_charClass[cc]) {
1149
+ // Run of whitespace → one <whitespace-token>.
1150
+ case HC_WHITESPACE:
1151
+ return consumeSpace(input, pos, out);
1152
+ // `"` / `'` → <string-token> (or <bad-string-token> on a raw newline).
1153
+ case HC_STRING:
1154
+ return consumeAStringToken(input, pos, out);
1155
+ // One-code-point token: its type is looked up in `_singleTT` (the `(` `)`
1156
+ // `,` `:` `;` `[` `]` `{` `}` set), so all of them share this arm.
1157
+ case HC_SINGLE:
1158
+ return fill(out, _singleTT[cc], pos - 1, pos);
1159
+ // `#` → <hash-token> if an ident/escape follows, else a <delim-token>.
1160
+ case HC_NUMBER_SIGN:
1161
+ return consumeNumberSign(input, pos, out);
1162
+ // `+` → <number-token> if it starts a number, else a <delim-token>.
1163
+ case HC_PLUS_SIGN:
1164
+ return consumePlusSign(input, pos, out);
1165
+ // `-` → number / <CDC-token> (`-->`) / ident / <delim-token>.
1166
+ case HC_HYPHEN_MINUS:
1167
+ return consumeHyphenMinus(input, pos, out);
1168
+ // `.` → <number-token> if a digit follows, else a <delim-token>.
1169
+ case HC_FULL_STOP:
1170
+ return consumeFullStop(input, pos, out);
1171
+ // `<` → <CDO-token> (`<!--`), else a <delim-token>.
1172
+ case HC_LESS_THAN:
1173
+ return consumeLessThan(input, pos, out);
1174
+ // `@` → <at-keyword-token> if an ident follows, else a <delim-token>.
1175
+ case HC_AT_SIGN:
1176
+ return consumeCommercialAt(input, pos, out);
1177
+ // `\` → ident-like token if it's a valid escape, else a <delim-token>.
1178
+ case HC_REVERSE_SOLIDUS:
1179
+ return consumeReverseSolidus(input, pos, out);
1180
+ // Digit → numeric token; `pos - 1` re-includes the digit the caller passed.
1181
+ case HC_DIGIT:
1182
+ return consumeANumericToken(input, pos - 1, out);
1183
+ // Ident-start (letter / `_` / non-ASCII, incl. `u`/`U`) → ident / function /
1184
+ // url token; `pos - 1` re-includes the lead code point.
1185
+ case HC_IDENT:
1186
+ return consumeAnIdentLikeToken(input, pos - 1, out);
1187
+ default:
1188
+ // HC_DELIM. EOF is impossible here (caller guarded with the outer
1189
+ // loop's `pos < input.length` check). Anything else: a <delim-token>.
1190
+ return fill(out, TT_DELIM, pos - 1, pos);
1191
+ }
1192
+ }
1193
+
1194
+ /**
1195
+ * Read one raw token (comment / whitespace / value token) starting at byte
1196
+ * `pos`, writing it into the caller-supplied `out` and returning `out`. The
1197
+ * token's `end` is the next read position. Returns `undefined` at end-of-input —
1198
+ * `pos >= length`, an unterminated comment, or a string ending on a trailing
1199
+ * escape. This is the shared lexer core: `next` reuses one `out` across calls so
1200
+ * the parse hot path allocates no per-token object; loop over it with a fresh
1201
+ * `out` per call to collect the raw token list (e.g. tests). Comment tokens are
1202
+ * returned here; `next` filters them.
1203
+ * @param {string} input input
1204
+ * @param {number} pos byte offset to read from
1205
+ * @param {MutableToken} out token to populate
1206
+ * @returns {MutableToken | undefined} the token, or undefined at EOF
1207
+ */
1208
+ function readToken(input, pos, out) {
1209
+ if (pos >= input.length) return undefined;
1210
+ const cc = input.charCodeAt(pos);
1211
+ // Comment: `/*…*/` is yielded as a token (filtered by `next`).
1212
+ if (cc === CC_SOLIDUS && input.charCodeAt(pos + 1) === CC_ASTERISK) {
1213
+ const start = pos;
1214
+ // Jump to the closing `*/` in one native scan instead of a per-character
1215
+ // loop — comment bodies (license banners, source comments) can be long.
1216
+ // No close: unterminated comment runs to EOF so ranges cover all input.
1217
+ const close = input.indexOf("*/", pos + 2);
1218
+ return fill(
1219
+ out,
1220
+ TT_COMMENT,
1221
+ start,
1222
+ close === -1 ? input.length : close + 2
1223
+ );
1224
+ }
1225
+ // `consumeAToken` dispatches on the lead code point at `pos` (it expects the
1226
+ // position just past the lead and the already-read lead code point).
1227
+ return consumeAToken(input, pos + 1, cc, out);
1228
+ }
1229
+
1230
+ // AST shape mirrors tabatkins/parse-css (the CSS Syntax Level 3 reference), with two deviations: nodes carry a `range` byte offset pair + a lazy `loc` getter, and have no methods beyond it.
1231
+
1232
+ /**
1233
+ * AST node / leaf-token `type` discriminators (spec name where it has one, else
1234
+ * parse-css's PascalCase). Numeric for the same reasons as the `TT_*` token
1235
+ * constants: a compact `Node#type` slot and integer `===` / `Map` keys on the
1236
+ * visitor hot path. Kept as a `NodeType` namespace (not bare constants) because
1237
+ * consumers reference members as `NodeType.AtRule`; exported so visitor maps
1238
+ * (`SourceProcessor#use`) and `CssParser` name nodes instead of a string
1239
+ * literal. A lexer token type never reaches a `Node#type`.
1240
+ * @enum {number}
1241
+ */
1242
+ const NodeType = {
1243
+ Ident: 1,
1244
+ Function: 2,
1245
+ AtKeyword: 3,
1246
+ Hash: 4,
1247
+ String: 5,
1248
+ BadString: 6,
1249
+ Url: 7,
1250
+ BadUrl: 8,
1251
+ Delim: 9,
1252
+ Number: 10,
1253
+ Percentage: 11,
1254
+ Dimension: 12,
1255
+ Whitespace: 13,
1256
+ Colon: 14,
1257
+ Semicolon: 15,
1258
+ Comma: 16,
1259
+ // Preserved tokens for stray closers / CDO / CDC (kept as component values per §5.4.8 "consume a token and return it").
1260
+ RightParenthesis: 17,
1261
+ RightSquareBracket: 18,
1262
+ RightCurlyBracket: 19,
1263
+ CDO: 20,
1264
+ CDC: 21,
1265
+ SimpleBlock: 22,
1266
+ Declaration: 23,
1267
+ AtRule: 24,
1268
+ QualifiedRule: 25,
1269
+ Stylesheet: 26,
1270
+ // Comments are never tree nodes; this type exists only so a `NodeType.Comment`
1271
+ // visitor can be registered (fired during tokenization — see `grammar`).
1272
+ Comment: 27
1273
+ };
1274
+ const {
1275
+ Ident: T_IDENT,
1276
+ Function: T_FUNCTION,
1277
+ AtKeyword: T_AT_KEYWORD,
1278
+ Hash: T_HASH,
1279
+ String: T_STRING,
1280
+ BadString: T_BAD_STRING,
1281
+ Url: T_URL,
1282
+ BadUrl: T_BAD_URL,
1283
+ Delim: T_DELIM,
1284
+ Number: T_NUMBER,
1285
+ Percentage: T_PERCENTAGE,
1286
+ Dimension: T_DIMENSION,
1287
+ Whitespace: T_WHITESPACE,
1288
+ Colon: T_COLON,
1289
+ Semicolon: T_SEMICOLON,
1290
+ Comma: T_COMMA,
1291
+ RightParenthesis: T_RIGHT_PARENTHESIS,
1292
+ RightSquareBracket: T_RIGHT_SQUARE_BRACKET,
1293
+ RightCurlyBracket: T_RIGHT_CURLY_BRACKET,
1294
+ CDO: T_CDO,
1295
+ CDC: T_CDC,
1296
+ SimpleBlock: T_SIMPLE_BLOCK,
1297
+ Declaration: T_DECLARATION,
1298
+ AtRule: T_AT_RULE,
1299
+ QualifiedRule: T_QUALIFIED_RULE,
1300
+ Stylesheet: T_STYLESHEET,
1301
+ Comment: T_COMMENT
1302
+ } = NodeType;
1303
+
1304
+ /**
1305
+ * Base AST node — the property-accessor view the `parseA*` entry points return
1306
+ * (see `_makeReader`). Every concrete node carries the `[start, end)` byte
1307
+ * `range` of the source slice it covers; `loc` is computed on demand from the
1308
+ * shared `LocConverter`, so line/column conversion is only paid when a consumer
1309
+ * needs it. The concrete node typedefs below extend this via `&`.
1310
+ *
1311
+ * Inside the parser a node ref is an integer id into the columns; the reader
1312
+ * exposes this property shape over a retained snapshot of those columns.
1313
+ * @typedef {object} Node
1314
+ * @property {number} type node-type discriminator
1315
+ * @property {number} start byte offset of the node's first code point
1316
+ * @property {number} end byte offset just past the node's last code point
1317
+ * @property {[number, number]} range the `[start, end)` byte range
1318
+ * @property {{ start: { line: number, column: number }, end: { line: number, column: number } }} loc source location (1-based line, 0-based column)
1319
+ * @property {() => string} toString source slice for this node
1320
+ * @property {string} unescapedName name with CSS escapes resolved (name-bearing nodes only)
1321
+ */
1322
+
1323
+ /**
1324
+ * @param {string} s numeric text
1325
+ * @returns {"+" | "-" | ""} the spec sign ("" when unsigned)
1326
+ */
1327
+ const _signOf = (s) => {
1328
+ const c = s.charCodeAt(0);
1329
+ return c === CC_PLUS_SIGN ? "+" : c === CC_HYPHEN_MINUS ? "-" : "";
1330
+ };
1331
+
1332
+ /**
1333
+ * @param {string} s numeric text (no unit / `%`)
1334
+ * @returns {"integer" | "number"} the spec type flag
1335
+ */
1336
+ const _typeFlagOf = (s) =>
1337
+ s.includes(".") || s.includes("e") || s.includes("E") ? "number" : "integer";
1338
+
1339
+ /**
1340
+ * Leaf token node (property-accessor view) — `value` is the raw source slice
1341
+ * (identifier text, quoted string including quotes, a dimension's full `123px`,
1342
+ * …; hash / at-keyword drop their `#` / `@` prefix, url uses its content range).
1343
+ * The `NumberToken` / `HashToken` / `UrlToken` / `DimensionToken` typedefs below
1344
+ * narrow the value accessors. `numericValue` / `typeFlag` / `sign` / `unit` are
1345
+ * derived from the source on read and are only meaningful on the matching token
1346
+ * type; `contentStart` / `contentEnd` mark a url token's inner content range.
1347
+ * @typedef {Node & { value: string, unescaped: string, numericValue: number, typeFlag: "integer" | "number" | "id" | "unrestricted", sign: "+" | "-" | "", unit: string, contentStart: number, contentEnd: number }} Token
1348
+ */
1349
+
1350
+ /**
1351
+ * Number token (`123`, `-1.5`, `+2e3`). `value` is the raw source slice (the spec's "value"); `numericValue` / `typeFlag` / `sign` are lazy getters derived from it (see `Token`).
1352
+ * @typedef {Token & { numericValue: number, typeFlag: "integer" | "number", sign: "+" | "-" | "" }} NumberToken
1353
+ */
1354
+
1355
+ /**
1356
+ * Percentage token (`50%`). `value` is the raw slice including `%`; `numericValue` (without `%`) and `sign` are lazy getters.
1357
+ * @typedef {Token & { numericValue: number, sign: "+" | "-" | "" }} PercentageToken
1358
+ */
1359
+
1360
+ /**
1361
+ * Dimension token (`100px`, `1.5em`). `value` is the raw slice (number + unit); `numericValue` / `typeFlag` / `sign` (of the numeric part) and `unit` (lower-cased) are lazy getters.
1362
+ * @typedef {Token & { numericValue: number, typeFlag: "integer" | "number", sign: "+" | "-" | "", unit: string }} DimensionToken
1363
+ */
1364
+
1365
+ // Spec "Assert: …" preconditions are comments only (callers satisfy them); a future `strict` option could reinstate them as throws.
1366
+
1367
+ /**
1368
+ * Hash token (`#foo`). `value` is the name without the leading `#`; `typeFlag` is the spec type flag ("id" when the name forms a valid `<id>` selector, "unrestricted" otherwise).
1369
+ * @typedef {Token & { typeFlag: "id" | "unrestricted" }} HashToken
1370
+ */
1371
+
1372
+ /**
1373
+ * Old-style unquoted URL token (`url(unquoted)`). `value` is the unquoted body;
1374
+ * `contentStart` / `contentEnd` mark the inner content range in the source.
1375
+ * @typedef {Token & { contentStart: number, contentEnd: number }} UrlToken
1376
+ */
1377
+
1378
+ /**
1379
+ * Function node: `name(component-values...)`. `name` is the raw source slice
1380
+ * before the `(` (callers lowercase / unescape as needed); `nameStart` / `nameEnd`
1381
+ * are its `[start, end)` byte offsets; `value` is the component values inside the parentheses.
1382
+ * @typedef {Node & { name: string, nameStart: number, nameEnd: number, value: ComponentValue[] }} FunctionNode
1383
+ */
1384
+
1385
+ /** @typedef {"[" | "(" | "{"} SimpleBlockToken */
1386
+
1387
+ /**
1388
+ * Simple block (`[...]`, `(...)` not preceded by an ident, `{...}`). `token` is
1389
+ * the opening character. `value` is the component values inside. This shape is
1390
+ * produced by `consumeASimpleBlock` (§5.4.9) and appears in preludes.
1391
+ *
1392
+ * Note: `consumeABlock` (§5.4.4) returns the parsed block's separate `decls` /
1393
+ * `rules` lists (per §5.4.5), not a SimpleBlock wrapper — see
1394
+ * `AtRule` / `QualifiedRule`'s `declarations` and `childRules` fields.
1395
+ * @typedef {Node & { token: SimpleBlockToken, value: ComponentValue[] }} SimpleBlock
1396
+ */
1397
+
1398
+ /**
1399
+ * A CSS component value (CSS Syntax §5.4.8): a preserved token, a function, or
1400
+ * a simple block (`Token` also covers `HashToken` / `UrlToken`).
1401
+ * @typedef {Token | FunctionNode | SimpleBlock} ComponentValue
1402
+ */
1403
+
1404
+ /**
1405
+ * A CSS rule — an at-rule or a qualified rule.
1406
+ * @typedef {AtRule | QualifiedRule} Rule
1407
+ */
1408
+
1409
+ /**
1410
+ * Declaration: `name: value [!important][;]`. `name` is the raw property-name
1411
+ * slice; `value` is the trimmed component-value list (whitespace stripped from
1412
+ * both ends); `important` records a stripped `!important`.
1413
+ * @typedef {Node & { name: string, nameStart: number, nameEnd: number, value: ComponentValue[], important: boolean }} Declaration
1414
+ */
1415
+
1416
+ /**
1417
+ * At-rule: `@name <prelude> ;` or `@name <prelude> { ... }`. `name` is the
1418
+ * at-keyword without the leading `@`; `prelude` is the component values up to
1419
+ * the at-rule's `;` / block / enclosing `}`. Per §5.4.2 the block is consumed
1420
+ * into separate `declarations` (a `Declaration[]`) and `childRules` (a `Rule[]`,
1421
+ * each an at-rule or qualified rule); both are `null` for a `;`-terminated
1422
+ * at-rule. `blockStart` / `blockEnd` are the `{` start / `}` end offsets
1423
+ * (webpack extension, not in spec; the spec doesn't track brace positions), or
1424
+ * `-1` / `-1` when there is no block. `range[1]` points past `}` for a block, or
1425
+ * at the `;` / `}` / EOF position otherwise (callers check the byte at `range[1]`
1426
+ * to tell them apart).
1427
+ * @typedef {Node & { name: string, nameStart: number, nameEnd: number, prelude: ComponentValue[], declarations: Declaration[] | null, childRules: Rule[] | null, blockStart: number, blockEnd: number }} AtRule
1428
+ */
1429
+
1430
+ /**
1431
+ * Qualified rule: `<prelude> { <block> }`. `prelude` is the component values
1432
+ * before the `{` (selectors, keyframe parameters, …); `declarations` and
1433
+ * `childRules` are the parsed `{ ... }` body (split per tabatkins/parse-css.js
1434
+ * reference impl), or both `null` when EOF was hit before `{`. `blockStart` /
1435
+ * `blockEnd` are the `{` start / `}` end offsets (webpack extension), or `-1` /
1436
+ * `-1` when there is no block.
1437
+ * @typedef {Node & { prelude: ComponentValue[], declarations: Declaration[] | null, childRules: Rule[] | null, blockStart: number, blockEnd: number }} QualifiedRule
1438
+ */
1439
+
1440
+ /**
1441
+ * Stylesheet (CSS Syntax §5.3.4): the result of `parseAStylesheet`. `rules`
1442
+ * holds the top-level at-rules / qualified rules (top-level declarations are
1443
+ * parse errors and never produced).
1444
+ * @typedef {Node & { rules: Rule[] }} Stylesheet
1445
+ */
1446
+
1447
+ // Lexer-token-type → AST-node-type map. A single `_makeLeaf` call site (vs a
1448
+ // ~20-case switch with an alloc in each arm) keeps V8 on the fast monomorphic
1449
+ // path — the switch form showed up as generic stubs in profiles. URL is the one
1450
+ // type with extra own state, handled first.
1451
+ const _ttToNodeType = new Uint8Array(27);
1452
+ _ttToNodeType[TT_WHITESPACE] = T_WHITESPACE;
1453
+ _ttToNodeType[TT_IDENTIFIER] = T_IDENT;
1454
+ _ttToNodeType[TT_STRING] = T_STRING;
1455
+ _ttToNodeType[TT_DELIM] = T_DELIM;
1456
+ _ttToNodeType[TT_NUMBER] = T_NUMBER;
1457
+ _ttToNodeType[TT_PERCENTAGE] = T_PERCENTAGE;
1458
+ _ttToNodeType[TT_DIMENSION] = T_DIMENSION;
1459
+ _ttToNodeType[TT_HASH] = T_HASH;
1460
+ _ttToNodeType[TT_AT_KEYWORD] = T_AT_KEYWORD;
1461
+ _ttToNodeType[TT_BAD_STRING_TOKEN] = T_BAD_STRING;
1462
+ _ttToNodeType[TT_BAD_URL_TOKEN] = T_BAD_URL;
1463
+ _ttToNodeType[TT_COLON] = T_COLON;
1464
+ _ttToNodeType[TT_COMMA] = T_COMMA;
1465
+ _ttToNodeType[TT_SEMICOLON] = T_SEMICOLON;
1466
+ _ttToNodeType[TT_RIGHT_PARENTHESIS] = T_RIGHT_PARENTHESIS;
1467
+ _ttToNodeType[TT_RIGHT_SQUARE_BRACKET] = T_RIGHT_SQUARE_BRACKET;
1468
+ _ttToNodeType[TT_RIGHT_CURLY_BRACKET] = T_RIGHT_CURLY_BRACKET;
1469
+ _ttToNodeType[TT_CDO] = T_CDO;
1470
+ _ttToNodeType[TT_CDC] = T_CDC;
1471
+
1472
+ // === AST construction ===
1473
+ // Nodes live in one struct-of-arrays node store: a node ref is an integer id
1474
+ // into parallel typed-array columns, so per-node allocation is avoided entirely.
1475
+ // The consume algorithms build nodes through the `_make*` / `_set*` primitives
1476
+ // below, which write those columns directly. The streaming `grammar` walks each
1477
+ // top-level node and recycles the columns; the `parseA*` entry points instead
1478
+ // retain the columns as a snapshot and hand back property-accessor nodes over it
1479
+ // (see `_makeReader`). Child lists are plain arrays of node ids in both modes.
1480
+
1481
+ // Active skip state (from `CssProcessOptions.skip`), applied by the grammar.
1482
+ // `_skipTypes` is indexed by `NodeType` (1 = skip): drop that component-value
1483
+ // leaf / container from declaration value and function-arg lists. The two
1484
+ // prelude flags scan a rule's prelude without materializing its tree (url tokens
1485
+ // / functions kept, so `url()` in a selector or `@import url(…)` still resolves).
1486
+ // A skipped node is still tokenized (positions stay correct) but never pushed,
1487
+ // so it is never walked or read — the caller must only skip what nothing reads.
1488
+ // `parseA*` leave these at their no-skip defaults so they build the full tree.
1489
+ const _NO_SKIP_TYPES = new Uint8Array(32);
1490
+ // Shared frozen empty list for block bodies with no decls / no child rules (the
1491
+ // common case — most rules carry only declarations). Every consumer reads these
1492
+ // lists read-only and null-guards, so one immutable instance replaces ~one empty
1493
+ // array allocation per rule; frozen so any errant push fails loud.
1494
+ const _EMPTY_LIST = /** @type {Rule[]} */ (
1495
+ /** @type {unknown} */ (Object.freeze([]))
1496
+ );
1497
+ /** @type {Uint8Array} */
1498
+ let _skipTypes = _NO_SKIP_TYPES;
1499
+ // Fast-path flag: true only when a real skip set is active, so the (dominant)
1500
+ // no-skip parses pay one boolean test instead of a node-type lookup per value.
1501
+ let _skipActive = false;
1502
+ let _skipSelectorPrelude = false;
1503
+ let _skipAtRulePrelude = false;
1504
+
1505
+ // Scratch content-list pool: a container's value / prelude is built in a plain
1506
+ // array, then sealed into the flat value buffer by `_setValue`, which returns
1507
+ // the array to the pool — so a parse allocates almost no per-list arrays. An
1508
+ // abandoned (never-sealed) list simply falls out of the pool.
1509
+ /** @type {Node[][]} */
1510
+ const _listPool = [];
1511
+ const _takeList = () =>
1512
+ _listPool.length > 0
1513
+ ? /** @type {Node[]} */ (_listPool.pop())
1514
+ : /** @type {Node[]} */ ([]);
1515
+
1516
+ // -- struct-of-arrays store: nodes live in reused typed-array columns --
1517
+ // A node ref is its integer id; fields live in parallel arrays indexed by id.
1518
+ // Two reused int slots (`_aux0/1`) plus a flags byte carry the per-type
1519
+ // extras; child lists hang off three object arrays. Aux slot meaning by type:
1520
+ // url: aux0 contentStart, aux1 contentEnd
1521
+ // function: aux0 nameEnd
1522
+ // declaration: aux0 nameEnd, flags bit0 important
1523
+ // at-rule: aux0 nameEnd, aux1 blockStart (blockEnd == end)
1524
+ // qualified: aux1 blockStart (blockEnd == end)
1525
+ // `name` / `nameStart` / a simple block's `token` are derived from the source
1526
+ // on read (see the accessors), so they need no slot. A node's main content
1527
+ // (value | prelude | stylesheet rules) is a `_flat` span (see below).
1528
+ // `grammar` resets `_nodeCount` to 0 after each top-level rule's walk, so the
1529
+ // buffers are reused across rules and the parse allocates almost nothing.
1530
+ let _capacity = 0;
1531
+ let _nodeCount = 0;
1532
+ let _types = new Uint8Array(0);
1533
+ let _starts = new Int32Array(0);
1534
+ let _ends = new Int32Array(0);
1535
+ let _aux0 = new Int32Array(0);
1536
+ let _aux1 = new Int32Array(0);
1537
+ let _flags = new Uint8Array(0);
1538
+ // Content-list spans: a container's value / prelude is `_flat[start, start+len)`
1539
+ // (node refs), recycled per top-level rule like the node columns.
1540
+ let _listStarts = new Int32Array(0);
1541
+ let _listLens = new Int32Array(0);
1542
+ let _flat = new Int32Array(0);
1543
+ let _flatTop = 0;
1544
+ // Peak usage of the current parse, and use-once regrow hints: after an
1545
+ // over-capacity shrink the next grow jumps straight back to the previous
1546
+ // parse's peak (one exact-fit allocation instead of re-doubling up).
1547
+ let _peak = 0;
1548
+ let _flatPeak = 0;
1549
+ let _growHint = 0;
1550
+ let _flatGrowHint = 0;
1551
+
1552
+ /** @param {number} need minimum flat-buffer capacity */
1553
+ const _flatGrow = (need) => {
1554
+ let cap = _flat.length || 4096;
1555
+ if (_flatGrowHint > cap) cap = _flatGrowHint;
1556
+ _flatGrowHint = 0;
1557
+ while (cap < need) cap *= 2;
1558
+ const next = new Int32Array(cap);
1559
+ next.set(_flat);
1560
+ _flat = next;
1561
+ };
1562
+ // Reassigned (not mutated) when a `parseA*` parse hands its columns to a
1563
+ // retained snapshot, so the next parse starts on fresh arrays.
1564
+ /** @type {(Node[] | null)[]} */
1565
+ let _declarationLists = [];
1566
+ /** @type {(Node[] | null)[]} */
1567
+ let _childRuleLists = [];
1568
+ let _input = "";
1569
+ let _locConverter = /** @type {LocConverter} */ (/** @type {unknown} */ (null));
1570
+
1571
+ // Node refs are integers here but typed `Node` across the parser; these are
1572
+ // identity casts that just satisfy the type system at the boundary.
1573
+ /** @type {(n: Node) => number} */
1574
+ const _nodeIndex = (n) => /** @type {number} */ (/** @type {unknown} */ (n));
1575
+ /** @type {(i: number) => Node} */
1576
+ const _nodeRef = (i) => /** @type {Node} */ (/** @type {unknown} */ (i));
1577
+
1578
+ /** @param {number} need minimum capacity */
1579
+ const _grow = (need) => {
1580
+ let cap = _capacity || 4096;
1581
+ if (_growHint > cap) cap = _growHint;
1582
+ _growHint = 0;
1583
+ while (cap < need) cap *= 2;
1584
+ const ty = new Uint8Array(cap);
1585
+ ty.set(_types);
1586
+ _types = ty;
1587
+ const st = new Int32Array(cap);
1588
+ st.set(_starts);
1589
+ _starts = st;
1590
+ const en = new Int32Array(cap);
1591
+ en.set(_ends);
1592
+ _ends = en;
1593
+ const a0 = new Int32Array(cap);
1594
+ a0.set(_aux0);
1595
+ _aux0 = a0;
1596
+ const a1 = new Int32Array(cap);
1597
+ a1.set(_aux1);
1598
+ _aux1 = a1;
1599
+ const fl = new Uint8Array(cap);
1600
+ fl.set(_flags);
1601
+ _flags = fl;
1602
+ const ls = new Int32Array(cap);
1603
+ ls.set(_listStarts);
1604
+ _listStarts = ls;
1605
+ const ll = new Int32Array(cap);
1606
+ ll.set(_listLens);
1607
+ _listLens = ll;
1608
+ _capacity = cap;
1609
+ };
1610
+ /** @type {(type: number, start: number, end: number) => Node} */
1611
+ const _makeLeaf = (type, start, end) => {
1612
+ // Ids are 1-based: a node ref is used in truthiness checks (`if (!parent)`),
1613
+ // so 0 must stay reserved for "no node".
1614
+ // Leaves never read the flag / list slots — `_makeContainer` clears
1615
+ // them instead, keeping the dominant leaf allocation at three writes.
1616
+ const i = _nodeCount + 1;
1617
+ if (i >= _capacity) _grow(i + 1);
1618
+ _types[i] = type;
1619
+ _starts[i] = start;
1620
+ _ends[i] = end;
1621
+ _nodeCount = i;
1622
+ return _nodeRef(i);
1623
+ };
1624
+ /** @type {(type: number, start: number, end: number) => Node} */
1625
+ const _makeContainer = (type, start, end) => {
1626
+ const r = _makeLeaf(type, start, end);
1627
+ const i = _nodeIndex(r);
1628
+ _flags[i] = 0;
1629
+ // Clear the content-span length so a reused id never exposes a previous
1630
+ // node's children (content lists are flat spans, so zeroing the length
1631
+ // suffices). `blockStart` (aux1) is NOT defaulted here: only at-rules and
1632
+ // qualified rules carry a block, and they set it on every return path
1633
+ // (`_setBlock`, or `-1` for the no-block forms). `blockEnd` is not stored — a
1634
+ // block rule's `end` is its `blockEnd` (see `_setBlock`), else it is `-1`.
1635
+ _listLens[i] = 0;
1636
+ // The decl / child-rule slots are read only for rules (the walk guards on
1637
+ // type; readers treat a missing slot as `null`), so only rules clear them —
1638
+ // clearing every container would write these `id`-indexed arrays at scattered
1639
+ // ids and degrade them to slow dictionary mode on large non-recycling parses.
1640
+ if (type === T_AT_RULE || type === T_QUALIFIED_RULE) {
1641
+ _declarationLists[i] = null;
1642
+ _childRuleLists[i] = null;
1643
+ }
1644
+ return r;
1645
+ };
1646
+ // Raw token value (the lazy `Token.value` form): hash / at-keyword drop their
1647
+ // one-char prefix, url uses its content range. Shared by the parser's
1648
+ // mid-parse reads and the accessor.
1649
+ /**
1650
+ * @param {number} i node id
1651
+ * @returns {string} raw token value
1652
+ */
1653
+ const _valueOf = (i) => {
1654
+ const ty = _types[i];
1655
+ if (ty === T_HASH || ty === T_AT_KEYWORD) {
1656
+ return _input.slice(_starts[i] + 1, _ends[i]);
1657
+ }
1658
+ if (ty === T_URL) return _input.slice(_aux0[i], _aux1[i]);
1659
+ return _input.slice(_starts[i], _ends[i]);
1660
+ };
1661
+ // Module-level constants (not per-parse closures), so each consume-algorithm
1662
+ // call site keeps one function identity and stays monomorphic.
1663
+ /** @type {(start: number, end: number, contentStart: number, contentEnd: number) => Node} */
1664
+ const _makeUrl = (start, end, cs, ce) => {
1665
+ const r = _makeLeaf(T_URL, start, end);
1666
+ _aux0[_nodeIndex(r)] = cs;
1667
+ _aux1[_nodeIndex(r)] = ce;
1668
+ return r;
1669
+ };
1670
+ /** @type {(start: number) => Node} */
1671
+ const _makeStylesheet = (start) => _makeContainer(T_STYLESHEET, start, start);
1672
+ // name / nameStart are derived from start + nameEnd; only nameEnd is stored.
1673
+ /** @type {(r: Node, nameStart: number, nameEnd: number) => void} */
1674
+ const _setName = (r, ns, ne) => {
1675
+ _aux0[_nodeIndex(r)] = ne;
1676
+ };
1677
+ /** @type {(r: Node, v: number) => void} */
1678
+ const _setEnd = (r, v) => {
1679
+ _ends[_nodeIndex(r)] = v;
1680
+ };
1681
+ // `blockEnd` is not stored: for a block rule the parser sets `end` to the
1682
+ // block end right after this (so `A.blockEnd` reads `end`); a `-1` blockStart
1683
+ // marks the no-block forms, where `blockEnd` derives to `-1`.
1684
+ /** @type {(r: Node, blockStart: number) => void} */
1685
+ const _setBlock = (r, bs) => {
1686
+ _aux1[_nodeIndex(r)] = bs;
1687
+ };
1688
+ /** @type {(r: Node) => void} */
1689
+ const _setImportant = (r) => {
1690
+ _flags[_nodeIndex(r)] |= 1;
1691
+ };
1692
+ // A simple block's token is derived from its opening char on read.
1693
+ /** @type {(r: Node, ch: SimpleBlockToken) => void} */
1694
+ const _setToken = (r, ch) => {};
1695
+ /** @type {(r: Node, list: Node[]) => void} */
1696
+ const _setValue = (r, list) => {
1697
+ // Seal the finished list: copy its refs into the flat buffer and hand the
1698
+ // scratch array back to the pool. The caller never touches `list` again.
1699
+ const len = list.length;
1700
+ // Empty seal (common in non-modules skip mode, where value/prelude leaves are
1701
+ // dropped): `_makeContainer` already left `_listLens` at 0, so skip the flat
1702
+ // writes entirely and just recycle the scratch array.
1703
+ if (len !== 0) {
1704
+ const i = _nodeIndex(r);
1705
+ const start = _flatTop;
1706
+ if (start + len > _flat.length) _flatGrow(start + len);
1707
+ for (let k = 0; k < len; k++) {
1708
+ _flat[start + k] = _nodeIndex(list[k]);
1709
+ }
1710
+ _flatTop = start + len;
1711
+ _listStarts[i] = start;
1712
+ _listLens[i] = len;
1713
+ list.length = 0;
1714
+ }
1715
+ _listPool.push(list);
1716
+ };
1717
+ /** @type {(r: Node, decls: Node[], childRules: Node[]) => void} */
1718
+ const _setBody = (r, decls, childRules) => {
1719
+ const i = _nodeIndex(r);
1720
+ _declarationLists[i] = decls;
1721
+ _childRuleLists[i] = childRules;
1722
+ };
1723
+ /** @type {(r: Node) => number} */
1724
+ const _nodeTypeOf = (r) => _types[_nodeIndex(r)];
1725
+ /** @type {(r: Node) => number} */
1726
+ const _nodeStartOf = (r) => _starts[_nodeIndex(r)];
1727
+ /** @type {(r: Node) => string} */
1728
+ const _nodeValueOf = (r) => _valueOf(_nodeIndex(r));
1729
+ /** @type {(r: Node) => SimpleBlockToken} */
1730
+ const _nodeTokenOf = (r) =>
1731
+ /** @type {SimpleBlockToken} */ (_input[_starts[_nodeIndex(r)]]);
1732
+ // A container's value, a rule's prelude, and a stylesheet's rules all seal into
1733
+ // the one content-list writer, so `_setPrelude` / `_setRules` are named views of
1734
+ // `_setValue` that keep the consume algorithms reading in spec terms.
1735
+ const _setPrelude = _setValue;
1736
+ const _setRules = _setValue;
1737
+
1738
+ /**
1739
+ * Start a parse into the store: point it at this source, reset the node /
1740
+ * flat cursors so nodes accumulate from id 1, and clear skip state (`grammar`
1741
+ * sets its own afterwards; `parseA*` leave it off to build the full tree).
1742
+ * @param {string} input source
1743
+ * @param {LocConverter} lc loc converter
1744
+ */
1745
+ const _setupParse = (input, lc) => {
1746
+ _input = input;
1747
+ _locConverter = lc;
1748
+ _nodeCount = 0;
1749
+ _flatTop = 0;
1750
+ _skipTypes = _NO_SKIP_TYPES;
1751
+ _skipActive = false;
1752
+ _skipSelectorPrelude = false;
1753
+ _skipAtRulePrelude = false;
1754
+ };
1755
+
1756
+ /**
1757
+ * Materialize a single non-block, non-function lexer token as its leaf AST node — the spec's "consume a token" result (§5.4.8 "anything else"), preserving stray closers / CDO / CDC.
1758
+ * @param {MutableToken} t token from the lexer
1759
+ * @returns {Node} the leaf token node
1760
+ */
1761
+ const tokenToNode = (t) => {
1762
+ const tt = t.type;
1763
+ // URL is the only leaf with own state (its content range); all others are a
1764
+ // plain leaf whose node type comes from the map.
1765
+ if (tt === TT_URL) {
1766
+ const ut = /** @type {CssUrlToken} */ (t);
1767
+ return _makeUrl(t.start, t.end, ut.contentStart, ut.contentEnd);
1768
+ }
1769
+ return _makeLeaf(_ttToNodeType[tt], t.start, t.end);
1770
+ };
1771
+
1772
+ /**
1773
+ * Position-based view over the lexer — webpack's stand-in for the spec's
1774
+ * "normalize into a token stream" (CSS Syntax §9). It unifies the lexer and the
1775
+ * stream in one class: the `readToken` primitive lexes one token (the CSS
1776
+ * tokenizer), and the spec token-stream operations `next` / `consume` /
1777
+ * `discard` / `mark` / `restoreMark` / `discardMark` drive it from a byte
1778
+ * cursor. `parse*` entry points wrap a source string in one of these and every
1779
+ * `consume*` algorithm reads tokens from it.
1780
+ *
1781
+ * No token buffer is kept: the cursor is a byte offset and the only state is
1782
+ * the next token (lazily tokenized once and cached until consumed). The
1783
+ * declaration-vs-qualified-rule backtracking in `consumeABlocksContents`
1784
+ * rewinds by `mark`ing / `restoreMark`ing that byte offset, which simply
1785
+ * re-tokenizes the rewound span — comment tokens are filtered here and fire
1786
+ * `onComment` once each, tracked by a monotonic high-water mark so a
1787
+ * re-tokenized span never re-fires them.
1788
+ *
1789
+ * `SourceProcessor` is handed this class (not an instance) and threads it to
1790
+ * the grammar, so a different language can drive the same visitor machinery by
1791
+ * swapping the tokenizer — the per-token `readToken` primitive — for its own.
1792
+ */
1793
+ class TokenStream {
1794
+ /**
1795
+ * @param {string} input source
1796
+ * @param {number=} pos start byte offset (default `0`)
1797
+ * @param {LocConverter=} locConverter shared loc converter (default a fresh one over `input`)
1798
+ * @param {((input: string, start: number, end: number) => number)=} onComment comment-token callback
1799
+ */
1800
+ constructor(
1801
+ input,
1802
+ pos = 0,
1803
+ locConverter = new LocConverter(input),
1804
+ onComment = undefined
1805
+ ) {
1806
+ /** @type {string} */
1807
+ this.input = input;
1808
+ /** @type {LocConverter} */
1809
+ this.locConverter = locConverter;
1810
+ this._onComment = onComment;
1811
+ // Byte offset where the next token is tokenized from.
1812
+ /** @type {number} */
1813
+ this._pos = pos;
1814
+ // Comments before this offset have already fired `onComment`; a
1815
+ // re-tokenized (backtracked) span never re-fires them.
1816
+ /** @type {number} */
1817
+ this._commentHigh = pos;
1818
+ // Single reused token the lexer writes into on the `next` path — see
1819
+ // `MutableToken`. `_hasNext` marks it cached — a boolean instead of an
1820
+ // object slot, so caching a token never pays a GC write barrier.
1821
+ /** @type {MutableToken} */
1822
+ this._tok = createToken();
1823
+ /** @type {boolean} whether `_tok` holds the (lazily tokenized) next token */
1824
+ this._hasNext = false;
1825
+ /** @type {number[]} byte offsets to rewind to */
1826
+ this._marks = [];
1827
+ }
1828
+
1829
+ /**
1830
+ * The next token (CSS Syntax §3 "next token") — the upcoming token without
1831
+ * consuming it; the `<eof-token>` once the source is exhausted. This is the
1832
+ * token the consume algorithms dispatch on (the spec's "process"). Tokenized
1833
+ * from `_pos` on first use and cached until consumed; comment tokens are
1834
+ * skipped here, firing `onComment` once each.
1835
+ * @returns {MutableToken} the next token
1836
+ */
1837
+ next() {
1838
+ if (!this._hasNext) {
1839
+ const input = this.input;
1840
+ const tok = this._tok;
1841
+ let pos = this._pos;
1842
+ for (;;) {
1843
+ const t = readToken(input, pos, tok);
1844
+ if (t === undefined) {
1845
+ fill(tok, TT_EOF, input.length, input.length);
1846
+ break;
1847
+ }
1848
+ if (t.type === TT_COMMENT) {
1849
+ if (t.start >= this._commentHigh) {
1850
+ if (this._onComment) this._onComment(input, t.start, t.end);
1851
+ this._commentHigh = t.end;
1852
+ }
1853
+ pos = t.end;
1854
+ continue;
1855
+ }
1856
+ break;
1857
+ }
1858
+ this._hasNext = true;
1859
+ }
1860
+ return this._tok;
1861
+ }
1862
+
1863
+ /**
1864
+ * Consume a token (CSS Syntax §3 "consume a token") — return the next token
1865
+ * and advance the cursor past it. The returned token is valid until the next
1866
+ * `next` re-tokenizes (the reused instance is not cleared by advancing).
1867
+ * @returns {MutableToken} the consumed token
1868
+ */
1869
+ consume() {
1870
+ const t = this.next();
1871
+ if (t.type !== TT_EOF) {
1872
+ this._pos = t.end;
1873
+ this._hasNext = false;
1874
+ }
1875
+ return t;
1876
+ }
1877
+
1878
+ /**
1879
+ * Discard a token (CSS Syntax §3 "discard a token") — advance the cursor past
1880
+ * the next token without returning it.
1881
+ * @returns {void}
1882
+ */
1883
+ discard() {
1884
+ const t = this.next();
1885
+ if (t.type !== TT_EOF) {
1886
+ this._pos = t.end;
1887
+ this._hasNext = false;
1888
+ }
1889
+ }
1890
+
1891
+ /**
1892
+ * Advance past the already-peeked next token, skipping the redundant `next()`
1893
+ * re-check `consume` / `discard` pay. Precondition: the caller has just called
1894
+ * `next()` (so `_tok` is the cached next token and `_hasNext` is true) and that
1895
+ * token is not the `<eof-token>` — the hot "peek, decide, advance" sites where
1896
+ * both always hold. Callers that can't guarantee a non-EOF cached token use
1897
+ * `consume` / `discard` instead.
1898
+ * @returns {void}
1899
+ */
1900
+ advance() {
1901
+ this._pos = this._tok.end;
1902
+ this._hasNext = false;
1903
+ }
1904
+
1905
+ /**
1906
+ * Mark (CSS Syntax §3 "mark") — push the current cursor position.
1907
+ * @returns {void}
1908
+ */
1909
+ mark() {
1910
+ this._marks.push(this._pos);
1911
+ }
1912
+
1913
+ /**
1914
+ * Restore a mark (CSS Syntax §3 "restore a mark") — pop the last mark and
1915
+ * rewind the cursor to it. The rewound span is re-tokenized on the next read;
1916
+ * already-fired comments are not re-fired (`_commentHigh`).
1917
+ * @returns {void}
1918
+ */
1919
+ restoreMark() {
1920
+ this._pos = /** @type {number} */ (this._marks.pop());
1921
+ this._hasNext = false;
1922
+ }
1923
+
1924
+ /**
1925
+ * Discard a mark (CSS Syntax §3 "discard a mark") — pop without rewinding.
1926
+ * @returns {void}
1927
+ */
1928
+ discardMark() {
1929
+ this._marks.pop();
1930
+ }
1931
+ }
1932
+
1933
+ /**
1934
+ * Normalize a `parse*` entry point's first argument into a `TokenStream`
1935
+ * (CSS Syntax §9 "normalize into a token stream"). An existing `TokenStream`
1936
+ * is returned as-is (consumed from its current position — it already carries
1937
+ * the shared `LocConverter` and comment hook), so `pos` / `onComment` are
1938
+ * ignored. A raw source string is tokenized from `pos` with a fresh
1939
+ * `LocConverter`; pass a `TokenStream` instead to share one converter across
1940
+ * sub-parses.
1941
+ * @param {string | TokenStream} input source string or an existing stream
1942
+ * @param {number=} pos start byte offset (string input only; default `0`)
1943
+ * @param {((input: string, start: number, end: number) => number)=} onComment comment callback (string input only)
1944
+ * @returns {TokenStream} the stream to consume from
1945
+ */
1946
+ const normalizeIntoTokenStream = (input, pos, onComment) =>
1947
+ input instanceof TokenStream
1948
+ ? input
1949
+ : new TokenStream(input, pos || 0, new LocConverter(input), onComment);
1950
+
1951
+ // === Parser entry points (CSS Syntax Level 3 §5.3) ===
1952
+ // Each `parseA*` is a thin public wrapper over a `consumeA*` algorithm
1953
+ // (§5.4): it takes raw source + a start position (webpack's stand-in for
1954
+ // the spec's "normalize into a token stream") and runs the matching
1955
+ // consume algorithm. The split mirrors tabatkins/parse-css — `parse*`
1956
+ // are the documented entry points, `consume*` are the internal
1957
+ // algorithms that drive the tokenizer.
1958
+
1959
+ /**
1960
+ * @typedef {object} ParseOptions
1961
+ * @property {((input: string, start: number, end: number) => number)=} comment optional comment-token callback; the public `parse*` entry points use it to build the `TokenStream` so the outer parser's comment tracker still sees magic comments inside the consumed range
1962
+ */
1963
+
1964
+ // === parseA* retained store + property-accessor readers ===
1965
+ // `grammar` recycles the columns per top-level rule, but the `parseA*` entry
1966
+ // points must hand back a tree that outlives the parse. Each `parseA*` run parses
1967
+ // into the columns without recycling, then `_finishStore` hands them to a
1968
+ // snapshot object and resets the module columns to fresh arrays so the next parse
1969
+ // can't clobber it. Nodes are exposed as `parseA*` readers: plain objects sharing
1970
+ // one module-level prototype whose getters index the reader's own snapshot by node
1971
+ // id — no per-node class, no eager string slices, child readers built lazily on
1972
+ // access. A single shared prototype (rather than one per store) keeps the readers
1973
+ // monomorphic across parses, so `_readerAt` and every getter stay on the fast path.
1974
+
1975
+ /**
1976
+ * @typedef {object} NodeReader
1977
+ * @property {NodeStore} _store snapshot this reader indexes
1978
+ * @property {number} _i node id into the snapshot columns
1979
+ * @property {number} type node type
1980
+ * @property {number} start start offset
1981
+ * @property {number} end end offset
1982
+ * @property {[number, number]} range start / end offsets
1983
+ * @property {{ start: { line: number, column: number }, end: { line: number, column: number } }} loc source location
1984
+ * @property {() => string} toString source slice
1985
+ * @property {string | ComponentValue[]} value token value (leaf) or component-value list (function / block / declaration)
1986
+ * @property {string} unescaped unescaped token value
1987
+ * @property {number} numericValue parsed numeric value
1988
+ * @property {"integer" | "number" | "id" | "unrestricted"} typeFlag spec type flag
1989
+ * @property {"+" | "-" | ""} sign spec sign
1990
+ * @property {string} unit dimension unit (lower-cased)
1991
+ * @property {number} contentStart url content start offset
1992
+ * @property {number} contentEnd url content end offset
1993
+ * @property {string} name rule / declaration / function name
1994
+ * @property {number} nameStart name start offset
1995
+ * @property {number} nameEnd name end offset
1996
+ * @property {string} unescapedName unescaped name
1997
+ * @property {ComponentValue[]} prelude rule prelude
1998
+ * @property {Declaration[] | null} declarations block declarations
1999
+ * @property {Rule[] | null} childRules block child rules
2000
+ * @property {number} blockStart `{` start offset
2001
+ * @property {number} blockEnd `}` end offset
2002
+ * @property {boolean} important `!important` flag
2003
+ * @property {SimpleBlockToken} token simple-block opening char
2004
+ * @property {Rule[]} rules stylesheet rules
2005
+ */
2006
+
2007
+ /**
2008
+ * @typedef {object} NodeStore
2009
+ * @property {string} input source
2010
+ * @property {LocConverter} lc loc converter
2011
+ * @property {Uint8Array} types node-type column
2012
+ * @property {Int32Array} starts start-offset column
2013
+ * @property {Int32Array} ends end-offset column
2014
+ * @property {Int32Array} aux0 aux slot 0
2015
+ * @property {Int32Array} aux1 aux slot 1
2016
+ * @property {Uint8Array} flags flags column
2017
+ * @property {Int32Array} listStarts content-span start column
2018
+ * @property {Int32Array} listLens content-span length column
2019
+ * @property {Int32Array} flat flat node-ref buffer
2020
+ * @property {(Node[] | null)[]} declLists per-node declaration lists
2021
+ * @property {(Node[] | null)[]} childLists per-node child-rule lists
2022
+ */
2023
+
2024
+ // Shared frozen empty list for a block body with no declarations / child rules,
2025
+ // so equal-empty reads return one reference (mirrors `_EMPTY_LIST`).
2026
+ const _READER_EMPTY = /** @type {Rule[]} */ (
2027
+ /** @type {unknown} */ (Object.freeze([]))
2028
+ );
2029
+
2030
+ /**
2031
+ * Raw token value over a snapshot (the lazy `Token.value` form): hash / at-keyword
2032
+ * drop their one-char prefix, url uses its content range.
2033
+ * @param {NodeStore} store snapshot
2034
+ * @param {number} i node id
2035
+ * @returns {string} raw token value
2036
+ */
2037
+ const _storeValueOf = (store, i) => {
2038
+ const ty = store.types[i];
2039
+ if (ty === T_HASH || ty === T_AT_KEYWORD) {
2040
+ return store.input.slice(store.starts[i] + 1, store.ends[i]);
2041
+ }
2042
+ if (ty === T_URL) return store.input.slice(store.aux0[i], store.aux1[i]);
2043
+ return store.input.slice(store.starts[i], store.ends[i]);
2044
+ };
2045
+
2046
+ /**
2047
+ * @param {NodeStore} store snapshot
2048
+ * @param {number} i node id
2049
+ * @returns {Node} reader over node `i`
2050
+ */
2051
+ const _readerAt = (store, i) => {
2052
+ const o = Object.create(NODE_READER_PROTO);
2053
+ o._store = store;
2054
+ o._i = i;
2055
+ return /** @type {Node} */ (o);
2056
+ };
2057
+
2058
+ /**
2059
+ * Readers over a container's flat content span (value / prelude / rules).
2060
+ * @param {NodeStore} store snapshot
2061
+ * @param {number} i container id
2062
+ * @returns {Node[]} child readers
2063
+ */
2064
+ const _readList = (store, i) => {
2065
+ const s = store.listStarts[i];
2066
+ const len = store.listLens[i];
2067
+ const flat = store.flat;
2068
+ /** @type {Node[]} */
2069
+ const out = [];
2070
+ for (let k = 0; k < len; k++) out.push(_readerAt(store, flat[s + k]));
2071
+ return out;
2072
+ };
2073
+
2074
+ /**
2075
+ * Readers over a node-id list (declarations / child rules).
2076
+ * @param {NodeStore} store snapshot
2077
+ * @param {Node[]} list node-id list
2078
+ * @returns {Node[]} child readers
2079
+ */
2080
+ const _readRefList = (store, list) => {
2081
+ /** @type {Node[]} */
2082
+ const out = [];
2083
+ for (let k = 0; k < list.length; k++) {
2084
+ out.push(_readerAt(store, _nodeIndex(list[k])));
2085
+ }
2086
+ return out;
2087
+ };
2088
+
2089
+ // Module-level reader prototype shared by every `parseA*` reader. Getters index
2090
+ // the reader's own `_store` snapshot by its `_i` node id; because the prototype is
2091
+ // created once (not per store), all readers share one hidden map and stay
2092
+ // monomorphic across parses.
2093
+ const NODE_READER_PROTO = /** @type {NodeReader} */ ({
2094
+ _store: /** @type {NodeStore} */ (/** @type {unknown} */ (null)),
2095
+ _i: 0,
2096
+ get type() {
2097
+ return this._store.types[this._i];
2098
+ },
2099
+ get start() {
2100
+ return this._store.starts[this._i];
2101
+ },
2102
+ get end() {
2103
+ return this._store.ends[this._i];
2104
+ },
2105
+ get range() {
2106
+ const store = this._store;
2107
+ const i = this._i;
2108
+ return /** @type {[number, number]} */ ([store.starts[i], store.ends[i]]);
2109
+ },
2110
+ get loc() {
2111
+ const store = this._store;
2112
+ const i = this._i;
2113
+ const lc = store.lc;
2114
+ // `LocConverter#get` mutates and returns itself, so snapshot the first.
2115
+ const s = lc.get(store.starts[i]);
2116
+ const sl = s.line;
2117
+ const sc = s.column;
2118
+ const e = lc.get(store.ends[i]);
2119
+ return {
2120
+ start: { line: sl, column: sc },
2121
+ end: { line: e.line, column: e.column }
2122
+ };
2123
+ },
2124
+ toString() {
2125
+ const store = this._store;
2126
+ const i = this._i;
2127
+ return store.input.slice(store.starts[i], store.ends[i]);
2128
+ },
2129
+ get value() {
2130
+ const store = this._store;
2131
+ const i = this._i;
2132
+ const ty = store.types[i];
2133
+ // function / simple-block / declaration expose their component-value
2134
+ // list; every leaf token exposes its raw string value.
2135
+ return ty === T_FUNCTION || ty === T_SIMPLE_BLOCK || ty === T_DECLARATION
2136
+ ? /** @type {ComponentValue[]} */ (_readList(store, i))
2137
+ : _storeValueOf(store, i);
2138
+ },
2139
+ get unescaped() {
2140
+ const store = this._store;
2141
+ const i = this._i;
2142
+ const v = _storeValueOf(store, i);
2143
+ return store.types[i] === T_STRING
2144
+ ? unescapeIdentifier(v.slice(1, -1))
2145
+ : unescapeIdentifier(v);
2146
+ },
2147
+ get numericValue() {
2148
+ const store = this._store;
2149
+ const i = this._i;
2150
+ const v = _storeValueOf(store, i);
2151
+ if (store.types[i] === T_DIMENSION) {
2152
+ return Number(v.slice(0, _consumeANumber(v, 0)));
2153
+ }
2154
+ if (store.types[i] === T_PERCENTAGE) return Number(v.slice(0, -1));
2155
+ return Number(v);
2156
+ },
2157
+ get typeFlag() {
2158
+ const store = this._store;
2159
+ const i = this._i;
2160
+ if (store.types[i] === T_HASH) {
2161
+ const input = store.input;
2162
+ const p = store.starts[i] + 1;
2163
+ return _ifThreeCodePointsWouldStartAnIdentSequence(
2164
+ input,
2165
+ p,
2166
+ input.charCodeAt(p),
2167
+ input.charCodeAt(p + 1),
2168
+ input.charCodeAt(p + 2)
2169
+ )
2170
+ ? "id"
2171
+ : "unrestricted";
2172
+ }
2173
+ const v = _storeValueOf(store, i);
2174
+ return _typeFlagOf(
2175
+ store.types[i] === T_DIMENSION ? v.slice(0, _consumeANumber(v, 0)) : v
2176
+ );
2177
+ },
2178
+ get sign() {
2179
+ return _signOf(_storeValueOf(this._store, this._i));
2180
+ },
2181
+ get unit() {
2182
+ const v = _storeValueOf(this._store, this._i);
2183
+ return v.slice(_consumeANumber(v, 0)).toLowerCase();
2184
+ },
2185
+ get contentStart() {
2186
+ return this._store.aux0[this._i];
2187
+ },
2188
+ get contentEnd() {
2189
+ return this._store.aux1[this._i];
2190
+ },
2191
+ get name() {
2192
+ const store = this._store;
2193
+ const i = this._i;
2194
+ // An at-rule's name skips its `@`; others start at the node.
2195
+ return store.types[i] === T_AT_RULE
2196
+ ? store.input.slice(store.starts[i] + 1, store.aux0[i])
2197
+ : store.input.slice(store.starts[i], store.aux0[i]);
2198
+ },
2199
+ get nameStart() {
2200
+ return this._store.starts[this._i];
2201
+ },
2202
+ get nameEnd() {
2203
+ return this._store.aux0[this._i];
2204
+ },
2205
+ get unescapedName() {
2206
+ return unescapeIdentifier(this.name);
2207
+ },
2208
+ get prelude() {
2209
+ return /** @type {ComponentValue[]} */ (_readList(this._store, this._i));
2210
+ },
2211
+ get declarations() {
2212
+ const store = this._store;
2213
+ // Non-rule containers never populate this slot (see `_makeContainer`), so a
2214
+ // missing entry (`undefined`) is normalized to `null` — same as a rule with
2215
+ // no block.
2216
+ const list = store.declLists[this._i] || null;
2217
+ return list === null
2218
+ ? null
2219
+ : /** @type {Declaration[]} */ (
2220
+ list.length > 0 ? _readRefList(store, list) : _READER_EMPTY
2221
+ );
2222
+ },
2223
+ get childRules() {
2224
+ const store = this._store;
2225
+ const list = store.childLists[this._i] || null;
2226
+ return list === null
2227
+ ? null
2228
+ : /** @type {Rule[]} */ (
2229
+ list.length > 0 ? _readRefList(store, list) : _READER_EMPTY
2230
+ );
2231
+ },
2232
+ get blockStart() {
2233
+ return this._store.aux1[this._i];
2234
+ },
2235
+ get blockEnd() {
2236
+ const store = this._store;
2237
+ const i = this._i;
2238
+ return store.aux1[i] !== -1 ? store.ends[i] : -1;
2239
+ },
2240
+ get important() {
2241
+ return (this._store.flags[this._i] & 1) !== 0;
2242
+ },
2243
+ get token() {
2244
+ const store = this._store;
2245
+ return /** @type {SimpleBlockToken} */ (store.input[store.starts[this._i]]);
2246
+ },
2247
+ get rules() {
2248
+ return /** @type {Rule[]} */ (_readList(this._store, this._i));
2249
+ }
2250
+ });
2251
+
2252
+ /**
2253
+ * Hand the module's live columns to a retained snapshot, then reset the
2254
+ * module columns to fresh empty arrays so the next parse starts clean and can't
2255
+ * mutate this store. Called once per `parseA*` after all consuming is done.
2256
+ * @returns {NodeStore} the retained snapshot
2257
+ */
2258
+ const _finishStore = () => {
2259
+ /** @type {NodeStore} */
2260
+ const store = {
2261
+ input: _input,
2262
+ lc: _locConverter,
2263
+ types: _types,
2264
+ starts: _starts,
2265
+ ends: _ends,
2266
+ aux0: _aux0,
2267
+ aux1: _aux1,
2268
+ flags: _flags,
2269
+ listStarts: _listStarts,
2270
+ listLens: _listLens,
2271
+ flat: _flat,
2272
+ declLists: _declarationLists,
2273
+ childLists: _childRuleLists
2274
+ };
2275
+ // Carry this parse's size forward as a one-shot grow hint so the next parse
2276
+ // allocates its columns once instead of re-doubling from scratch (node ids
2277
+ // are 1-based, so `+1`).
2278
+ _growHint = _nodeCount + 1;
2279
+ _flatGrowHint = _flatTop;
2280
+ // Reset module state — the columns now belong to `store`.
2281
+ _capacity = 0;
2282
+ _nodeCount = 0;
2283
+ _flatTop = 0;
2284
+ _types = new Uint8Array(0);
2285
+ _starts = new Int32Array(0);
2286
+ _ends = new Int32Array(0);
2287
+ _aux0 = new Int32Array(0);
2288
+ _aux1 = new Int32Array(0);
2289
+ _flags = new Uint8Array(0);
2290
+ _listStarts = new Int32Array(0);
2291
+ _listLens = new Int32Array(0);
2292
+ _flat = new Int32Array(0);
2293
+ _declarationLists = [];
2294
+ _childRuleLists = [];
2295
+ _listPool.length = 0;
2296
+ _input = "";
2297
+ _locConverter = /** @type {LocConverter} */ (/** @type {unknown} */ (null));
2298
+ return store;
2299
+ };
2300
+
2301
+ /**
2302
+ * Finish the parse and wrap one consumed node ref as a `parseA*` reader, keeping
2303
+ * the caller's node type.
2304
+ * @template {Node} T
2305
+ * @param {T} ref consumed node ref
2306
+ * @returns {T} reader over the retained snapshot
2307
+ */
2308
+ const _finishOne = (ref) =>
2309
+ /** @type {T} */ (_readerAt(_finishStore(), _nodeIndex(ref)));
2310
+
2311
+ /**
2312
+ * Parse a stylesheet, CSS Syntax Level 3
2313
+ * [§5.3.4](https://drafts.csswg.org/css-syntax/#parse-stylesheet).
2314
+ * @param {string | TokenStream} input source string or an existing token stream
2315
+ * @param {number=} pos start position (string input only)
2316
+ * @param {ParseOptions=} options optional comment-token callback (string input only)
2317
+ * @returns {Stylesheet} the parsed stylesheet
2318
+ */
2319
+ const parseAStylesheet = (input, pos = 0, options = {}) => {
2320
+ // 1. If input is a byte stream for a stylesheet, decode bytes from input, and set input to the result.
2321
+ // 2. Normalize input, and set input to the result.
2322
+ const ts = normalizeIntoTokenStream(input, pos, options.comment);
2323
+ _setupParse(ts.input, ts.locConverter);
2324
+ // 3. Create a new stylesheet, with its location set to location (or null, if location was not passed).
2325
+ const start = ts.next().start;
2326
+ const stylesheet = _makeStylesheet(start);
2327
+ // 4. Consume a stylesheet's contents from input, and set the stylesheet's rules to the result.
2328
+ _setRules(stylesheet, consumeAStylesheetsContents(ts));
2329
+ _setEnd(stylesheet, ts.next().start);
2330
+ // 5. Return the stylesheet.
2331
+ return /** @type {Stylesheet} */ (
2332
+ _readerAt(_finishStore(), _nodeIndex(stylesheet))
2333
+ );
2334
+ };
2335
+
2336
+ /**
2337
+ * Parse a stylesheet's contents, CSS Syntax Level 3
2338
+ * [§5.3.5](https://drafts.csswg.org/css-syntax/#parse-stylesheets-contents) —
2339
+ * the top-level rule list via `consumeAStylesheetsContents` (§5.4.1): top-level
2340
+ * declarations are parse errors (never produced) and top-level CDO (`<!--`) /
2341
+ * CDC (`-->`) tokens are discarded.
2342
+ * @param {string | TokenStream} input source string or an existing token stream
2343
+ * @param {number=} pos start position (string input only)
2344
+ * @param {ParseOptions=} options optional comment-token callback (string input only)
2345
+ * @returns {Rule[]} top-level rules
2346
+ */
2347
+ const parseAStylesheetsContents = (input, pos = 0, options = {}) => {
2348
+ // 1. Normalize input, and set input to the result.
2349
+ const ts = normalizeIntoTokenStream(input, pos, options.comment);
2350
+ _setupParse(ts.input, ts.locConverter);
2351
+ // 2. Consume a stylesheet’s contents from input, and return the result.
2352
+ const rules = consumeAStylesheetsContents(ts);
2353
+ const store = _finishStore();
2354
+ return /** @type {Rule[]} */ (_readRefList(store, rules));
2355
+ };
2356
+
2357
+ /**
2358
+ * Parse a block's contents, CSS Syntax Level 3
2359
+ * [§5.3.6](https://drafts.csswg.org/css-syntax/#parse-block-contents).
2360
+ * @param {string | TokenStream} input source string or an existing token stream
2361
+ * @param {number=} pos start position (string input only; just past the opening `{`, or 0)
2362
+ * @param {ParseOptions=} options optional comment-token callback (string input only)
2363
+ * @returns {{ decls: Declaration[], rules: Rule[] }} block decls + rules
2364
+ */
2365
+ const parseABlocksContents = (input, pos = 0, options = {}) => {
2366
+ // 1. Normalize input, and set input to the result.
2367
+ const ts = normalizeIntoTokenStream(input, pos, options.comment);
2368
+ _setupParse(ts.input, ts.locConverter);
2369
+ // 2. Consume a block’s contents from input, and return the result.
2370
+ const { decls, rules } = consumeABlocksContents(ts);
2371
+ const store = _finishStore();
2372
+ return {
2373
+ decls: /** @type {Declaration[]} */ (_readRefList(store, decls)),
2374
+ rules:
2375
+ rules.length > 0
2376
+ ? /** @type {Rule[]} */ (_readRefList(store, rules))
2377
+ : _READER_EMPTY
2378
+ };
2379
+ };
2380
+
2381
+ /**
2382
+ * Parse a rule, CSS Syntax Level 3
2383
+ * [§5.3.7](https://drafts.csswg.org/css-syntax/#parse-rule) — discards leading
2384
+ * whitespace, consumes one at-rule / qualified rule, and requires only trailing
2385
+ * whitespace; `undefined` (syntax error) otherwise.
2386
+ * @param {string | TokenStream} input source string or an existing token stream
2387
+ * @param {number=} pos start position (string input only)
2388
+ * @param {ParseOptions=} options optional comment-token callback (string input only)
2389
+ * @returns {Rule | undefined} the parsed rule
2390
+ */
2391
+ const parseARule = (input, pos = 0, options = {}) => {
2392
+ // 1. Normalize input, and set input to the result.
2393
+ const ts = normalizeIntoTokenStream(input, pos, options.comment);
2394
+ _setupParse(ts.input, ts.locConverter);
2395
+ // 2. Discard whitespace from input.
2396
+ while (ts.next().type === TT_WHITESPACE) ts.advance();
2397
+ // 3. If the next token from input is an <EOF-token>, return a syntax error.
2398
+ // Otherwise, if the next token from input is an <at-keyword-token>, consume an at-rule from input, and let rule be the return value.
2399
+ // Otherwise, consume a qualified rule from input and let rule be the return value.
2400
+ // If nothing or an invalid rule error was returned, return a syntax error.
2401
+ const head = ts.next();
2402
+ if (head.type === TT_EOF) return undefined;
2403
+ const rule =
2404
+ head.type === TT_AT_KEYWORD
2405
+ ? consumeAnAtRule(ts)
2406
+ : consumeAQualifiedRule(ts);
2407
+ if (!rule) return undefined;
2408
+ // 4. Discard whitespace from input.
2409
+ while (ts.next().type === TT_WHITESPACE) ts.advance();
2410
+ // 5. If the next token from input is an <EOF-token>, return rule. Otherwise, return a syntax error.
2411
+ return ts.next().type === TT_EOF ? _finishOne(rule) : undefined;
2412
+ };
2413
+
2414
+ /**
2415
+ * Parse a declaration, CSS Syntax Level 3
2416
+ * [§5.3.8](https://drafts.csswg.org/css-syntax/#parse-declaration).
2417
+ * @param {string | TokenStream} input source string or an existing token stream
2418
+ * @param {number=} pos start position (string input only)
2419
+ * @param {ParseOptions=} options optional comment-token callback (string input only)
2420
+ * @returns {Declaration | undefined} the parsed declaration, or undefined
2421
+ */
2422
+ const parseADeclaration = (input, pos = 0, options = {}) => {
2423
+ // 1. Normalize input, and set input to the result.
2424
+ const ts = normalizeIntoTokenStream(input, pos, options.comment);
2425
+ _setupParse(ts.input, ts.locConverter);
2426
+ // 2. Discard whitespace from input.
2427
+ while (ts.next().type === TT_WHITESPACE) ts.advance();
2428
+ // 3. Consume a declaration from input. If anything was returned, return it. Otherwise, return a syntax error.
2429
+ const decl = consumeADeclaration(ts);
2430
+ return decl === undefined ? undefined : _finishOne(decl);
2431
+ };
2432
+
2433
+ /**
2434
+ * Parse a component value, CSS Syntax Level 3 [§5.3.9](https://drafts.csswg.org/css-syntax/#parse-component-value) — strict entry point that consumes one value and returns `undefined` if non-whitespace input trails (use `consumeAComponentValue` for "one value, ignore the rest").
2435
+ * @param {string | TokenStream} input source string or an existing token stream
2436
+ * @param {number=} pos start position (string input only)
2437
+ * @param {ParseOptions=} options optional comment-token callback (string input only)
2438
+ * @returns {ComponentValue | undefined} the parsed component value, or `undefined` on empty / trailing-garbage input
2439
+ */
2440
+ const parseAComponentValue = (input, pos = 0, options = {}) => {
2441
+ // 1. Normalize input, and set input to the result.
2442
+ const ts = normalizeIntoTokenStream(input, pos, options.comment);
2443
+ _setupParse(ts.input, ts.locConverter);
2444
+ // 2. Discard whitespace from input.
2445
+ while (ts.next().type === TT_WHITESPACE) ts.advance();
2446
+ // 3. If input is empty, return a syntax error.
2447
+ if (ts.next().type === TT_EOF) return undefined;
2448
+ // 4. Consume a component value from input and let value be the return value.
2449
+ const result = consumeAComponentValue(ts);
2450
+ // 5. Discard whitespace from input.
2451
+ while (ts.next().type === TT_WHITESPACE) ts.advance();
2452
+ // 6. If input is empty, return value. Otherwise, return a syntax error.
2453
+ return ts.next().type === TT_EOF ? _finishOne(result) : undefined;
2454
+ };
2455
+
2456
+ /**
2457
+ * Parse a list of component values, CSS Syntax Level 3
2458
+ * [§5.3.10](https://drafts.csswg.org/css-syntax/#parse-list-of-components).
2459
+ * @param {string | TokenStream} input source string or an existing token stream
2460
+ * @param {number=} pos start position (string input only)
2461
+ * @param {ParseOptions=} options comment callback
2462
+ * @returns {ComponentValue[]} component values
2463
+ */
2464
+ const parseAListOfComponentValues = (input, pos = 0, options = {}) => {
2465
+ // 1. Normalize input, and set input to the result.
2466
+ const ts = normalizeIntoTokenStream(input, pos, options.comment);
2467
+ _setupParse(ts.input, ts.locConverter);
2468
+ // 2. Consume a list of component values from input, and return the result.
2469
+ // (`null` needs `bailOnCurly`, which is not passed here.)
2470
+ const values = /** @type {Node[]} */ (consumeAListOfComponentValues(ts));
2471
+ const store = _finishStore();
2472
+ return /** @type {ComponentValue[]} */ (_readRefList(store, values));
2473
+ };
2474
+
2475
+ /**
2476
+ * Parse a comma-separated list of component values, CSS Syntax Level 3 [§5.3.11](https://drafts.csswg.org/css-syntax/#parse-comma-list) — consumes one `<comma-token>`-stopped group of component values per iteration until EOF.
2477
+ * @param {string | TokenStream} input source string or an existing token stream
2478
+ * @param {number=} pos start position (string input only)
2479
+ * @param {ParseOptions=} options comment callback
2480
+ * @returns {ComponentValue[][]} comma-separated groups of component values
2481
+ */
2482
+ const parseACommaSeparatedListOfComponentValues = (
2483
+ input,
2484
+ pos = 0,
2485
+ options = {}
2486
+ ) => {
2487
+ // 1. Normalize input, and set input to the result.
2488
+ const ts = normalizeIntoTokenStream(input, pos, options.comment);
2489
+ _setupParse(ts.input, ts.locConverter);
2490
+ // 2. Let groups be an empty list.
2491
+ /** @type {Node[][]} */
2492
+ const groups = [];
2493
+ // 3. While input is not empty:
2494
+ while (ts.next().type !== TT_EOF) {
2495
+ // 3.1. Consume a list of component values from input, with <comma-token> as the stop token, and append the result to groups.
2496
+ groups.push(
2497
+ /** @type {Node[]} */ (consumeAListOfComponentValues(ts, TT_COMMA))
2498
+ );
2499
+ // 3.2 Discard a token from input.
2500
+ ts.discard();
2501
+ }
2502
+ // 4. Return groups — wrap each group's refs against the retained snapshot.
2503
+ const store = _finishStore();
2504
+ return groups.map(
2505
+ (g) => /** @type {ComponentValue[]} */ (_readRefList(store, g))
2506
+ );
2507
+ };
2508
+
2509
+ // === Parser algorithms (CSS Syntax Level 3 §5.4) ===
2510
+ // The mutually-recursive consume algorithms the `parse*` entry points drive:
2511
+ // each reads tokens from a `TokenStream` and reuses `consumeAComponentValue`
2512
+ // for nested values, mirroring tabatkins/parse-css.
2513
+
2514
+ /**
2515
+ * Consume a stylesheet's contents, CSS Syntax Level 3 [§5.4.1](https://drafts.csswg.org/css-syntax/#consume-stylesheet-contents) — the top-level rule list: whitespace and CDO (`<!--`) / CDC (`-->`) tokens are discarded, an at-keyword starts an at-rule, and anything else starts a qualified rule (so top-level declarations are parse errors and never produced).
2516
+ *
2517
+ * `onRule` is a webpack extension to the algorithm's output: when given, each
2518
+ * consumed rule is handed to it immediately and not collected, so the walker can
2519
+ * process one top-level rule at a time without materializing the whole
2520
+ * stylesheet (the returned list is then empty). When omitted the rules are
2521
+ * collected and returned as the spec specifies.
2522
+ * @param {TokenStream} ts token stream
2523
+ * @param {((rule: Rule) => void)=} onRule optional per-rule sink (streaming); rules are not collected when given
2524
+ * @returns {Rule[]} top-level rules (empty when `onRule` is given)
2525
+ */
2526
+ const consumeAStylesheetsContents = (ts, onRule) => {
2527
+ // Let rules be an initially empty list of rules.
2528
+ /** @type {Rule[]} */
2529
+ const rules = [];
2530
+
2531
+ // Process input
2532
+ for (;;) {
2533
+ const t = ts.next();
2534
+ // <whitespace-token> / <CDO-token> / <CDC-token>
2535
+ // Discard a token from input.
2536
+ if (t.type === TT_WHITESPACE || t.type === TT_CDO || t.type === TT_CDC) {
2537
+ ts.discard();
2538
+ }
2539
+ // <EOF-token>
2540
+ // Return rules.
2541
+ else if (t.type === TT_EOF) {
2542
+ return rules;
2543
+ }
2544
+ // <at-keyword-token>
2545
+ // Consume an at-rule from input. If anything is returned, append it to rules.
2546
+ else if (t.type === TT_AT_KEYWORD) {
2547
+ const at = consumeAnAtRule(ts);
2548
+ if (at) {
2549
+ if (onRule) onRule(at);
2550
+ else rules.push(at);
2551
+ }
2552
+ }
2553
+ // anything else
2554
+ // Consume a qualified rule from input. If a rule is returned, append it to rules.
2555
+ else {
2556
+ const rule = consumeAQualifiedRule(ts);
2557
+ if (rule) {
2558
+ if (onRule) onRule(rule);
2559
+ else rules.push(rule);
2560
+ }
2561
+ }
2562
+ }
2563
+ };
2564
+
2565
+ /**
2566
+ * Consume an at-rule, CSS Syntax Level 3 [§5.4.2](https://drafts.csswg.org/css-syntax/#consume-at-rule) — the next token must be an <at-keyword-token> (asserted); consumes the prelude up to `;` / `{` / `}` / EOF; `{` consumes the block (§5.4.4) onto `.block`, `;` / EOF is discarded, a top-level `}` (when not `nested`) is appended via `consumeAComponentValue`.
2567
+ * @param {TokenStream} ts token stream
2568
+ * @param {boolean=} nested true inside a `{}` block — a top-level `}` ends the at-rule (left for the caller)
2569
+ * @returns {AtRule | undefined} the parsed at-rule
2570
+ */
2571
+ const consumeAnAtRule = (ts, nested = false) => {
2572
+ // Assert (spec): the next token is an <at-keyword-token>.
2573
+ // Consume a token from input, and let rule be a new at-rule with its name set to the returned token’s value, its prelude initially set to an empty list, and no declarations or child rules.
2574
+ const head = ts.consume();
2575
+ const rule = /** @type {AtRule} */ (
2576
+ _makeContainer(T_AT_RULE, head.start, head.end)
2577
+ );
2578
+ _setName(rule, head.start, head.end);
2579
+ // Sealed (`_setPrelude`) at each return — the store consumes the
2580
+ // scratch array when sealing, so it must be complete by then.
2581
+ const prelude = _takeList();
2582
+ // declarations / childRules stay null (no block); the `;` / EOF / nested-`}`
2583
+ // forms set blockStart / blockEnd to -1 explicitly at their return below.
2584
+
2585
+ // Like `consumeAQualifiedRule`: skip mode scans the prelude without
2586
+ // materializing it (url tokens / functions kept so `@import url(…)` still
2587
+ // resolves); the block boundary is found by scanning, not the prelude nodes.
2588
+ const skip = _skipAtRulePrelude;
2589
+
2590
+ // Process input
2591
+ for (;;) {
2592
+ const t = ts.next();
2593
+
2594
+ // <semicolon-token>
2595
+ // <EOF-token>
2596
+ // Discard a token from input. If rule is valid in the current context, return it; otherwise return nothing.
2597
+ if (t.type === TT_SEMICOLON || t.type === TT_EOF) {
2598
+ ts.discard();
2599
+ _setPrelude(rule, prelude);
2600
+ _setBlock(rule, -1);
2601
+ _setEnd(rule, t.start);
2602
+ return rule;
2603
+ }
2604
+ // <}-token>
2605
+ // If nested is true: if rule is valid in the current context, return it; otherwise return nothing.
2606
+ // Otherwise, consume a token and append the result to rule’s prelude.
2607
+ else if (t.type === TT_RIGHT_CURLY_BRACKET) {
2608
+ if (nested) {
2609
+ _setPrelude(rule, prelude);
2610
+ _setBlock(rule, -1);
2611
+ _setEnd(rule, t.start);
2612
+ return rule;
2613
+ }
2614
+ const node = consumeATokenAsNode(ts);
2615
+ if (!skip) prelude.push(node);
2616
+ continue;
2617
+ }
2618
+ // <{-token>
2619
+ // Consume a block from input, and assign the result to rule's declarations and child rules.
2620
+ else if (t.type === TT_LEFT_CURLY_BRACKET) {
2621
+ _setPrelude(rule, prelude);
2622
+ const block = consumeABlock(ts);
2623
+ _setBody(rule, block.decls, block.rules);
2624
+ _setBlock(rule, block.blockStart);
2625
+ _setEnd(rule, block.blockEnd);
2626
+ return rule;
2627
+ }
2628
+
2629
+ // anything else
2630
+ // Consume a component value from input and append the returned value to rule’s prelude.
2631
+ const node = consumeAComponentValue(ts, t);
2632
+ if (!skip) {
2633
+ prelude.push(node);
2634
+ } else if (
2635
+ _nodeTypeOf(node) === T_FUNCTION ||
2636
+ _nodeTypeOf(node) === T_URL
2637
+ ) {
2638
+ prelude.push(node);
2639
+ }
2640
+ }
2641
+ };
2642
+
2643
+ /**
2644
+ * Consume a token (CSS Syntax §3 "consume a token"): advance past the next
2645
+ * token and return it as a leaf AST node. Used directly where the spec says
2646
+ * "consume a token from input" (e.g. the parse-error branches in §5.4.7 /
2647
+ * §5.4.2 / §5.4.3), distinct from `consumeAComponentValue` which would recurse
2648
+ * into a simple block / function.
2649
+ * @param {TokenStream} ts token stream
2650
+ * @returns {Token} the consumed token as a leaf node
2651
+ */
2652
+ const consumeATokenAsNode = (ts) => {
2653
+ const t = ts.consume();
2654
+ return /** @type {Token} */ (tokenToNode(t));
2655
+ };
2656
+
2657
+ /**
2658
+ * Consume a qualified rule, CSS Syntax Level 3 [§5.4.3](https://drafts.csswg.org/css-syntax/#consume-qualified-rule) — consumes the prelude (each component value via `consumeAComponentValue`) up to its `{` block; EOF, the optional `stopToken`, or a nested top-level `}` is a parse error returning nothing (the block-less prelude is dropped), while a non-nested top-level `}` is consumed as a parse error and the prelude continues. A returned rule always has a block.
2659
+ * @param {TokenStream} ts token stream
2660
+ * @param {number=} stopToken token type that ends the prelude (parse error → nothing)
2661
+ * @param {boolean=} nested true inside a `{}` block — a top-level `}` ends the rule (left for the caller)
2662
+ * @returns {QualifiedRule | undefined} parsed qualified rule, or `undefined` on a parse error
2663
+ */
2664
+ const consumeAQualifiedRule = (ts, stopToken, nested = false) => {
2665
+ const start = ts.next().start;
2666
+ // Let rule be a new qualified rule with its prelude, declarations, and child rules all initially set to empty lists.
2667
+ const rule = /** @type {QualifiedRule} */ (
2668
+ _makeContainer(T_QUALIFIED_RULE, start, start)
2669
+ );
2670
+ // Sealed (`_setPrelude`) at the `{` exit — the only path that returns the
2671
+ // rule; the parse-error exits abandon the scratch unsealed. Allocated lazily
2672
+ // on first push: skip mode usually pushes nothing (empty selector prelude),
2673
+ // and `_makeContainer` already zeroed the rule's list length, so a null
2674
+ // prelude reads as empty in the walk.
2675
+ /** @type {Node[] | null} */
2676
+ let prelude = null;
2677
+ // A returned qualified rule always has a block (only the `{` exit returns a
2678
+ // rule), so `_setBlock` always runs — no blockStart / blockEnd default needed.
2679
+
2680
+ // Skip mode leaves `prelude` empty (selector text is recovered from the
2681
+ // rule's byte range, not its nodes); `first`/`second` still track the first
2682
+ // two non-whitespace tokens the `--foo: {` disambiguation below needs.
2683
+ const skip = _skipSelectorPrelude;
2684
+ // Non-skip: first two non-whitespace prelude nodes (computed at the `{`).
2685
+ let first = /** @type {Node} */ (/** @type {unknown} */ (0));
2686
+ let second = /** @type {Node} */ (/** @type {unknown} */ (0));
2687
+ // Skip mode: the same two tokens tracked by token type + start, so a dropped
2688
+ // leaf selector token needs no materialized node just for the disambiguation.
2689
+ // `0` (no token type) = unset.
2690
+ let firstTT = 0;
2691
+ let firstStart = 0;
2692
+ let secondTT = 0;
2693
+
2694
+ // Process input
2695
+ for (;;) {
2696
+ const t = ts.next();
2697
+ // <EOF-token>
2698
+ // stop token (if passed)
2699
+ // This is a parse error. Return nothing.
2700
+ if (t.type === TT_EOF || t.type === stopToken) {
2701
+ return undefined;
2702
+ }
2703
+ // <}-token>
2704
+ // This is a parse error. If nested is true, return nothing. Otherwise, consume a token and append the result to rule’s prelude.
2705
+ else if (t.type === TT_RIGHT_CURLY_BRACKET) {
2706
+ if (nested) return undefined;
2707
+ if (skip) {
2708
+ // Stray `}` is a non-ws token; record its type/start, drop the node.
2709
+ if (firstTT === 0) {
2710
+ firstTT = t.type;
2711
+ firstStart = t.start;
2712
+ } else if (secondTT === 0) {
2713
+ secondTT = t.type;
2714
+ }
2715
+ ts.advance();
2716
+ } else {
2717
+ (prelude || (prelude = _takeList())).push(consumeATokenAsNode(ts));
2718
+ }
2719
+ continue;
2720
+ }
2721
+ // <{-token>
2722
+ // If the first two non-<whitespace-token> values of rule's prelude are an <ident-token> whose value starts with "--" followed by a <colon-token>, then:
2723
+ // - If nested is true, consume the remnants of a bad declaration from input, with nested set to true, and return nothing.
2724
+ // - If nested is false, consume a block from input, and return nothing.
2725
+ // (This disambiguates custom-property declarations from nested qualified rules — `--foo: { … }` at top level of a block is a declaration, not a rule.)
2726
+ // Otherwise, consume a block from input, and let child rules be the result.
2727
+ else if (t.type === TT_LEFT_CURLY_BRACKET) {
2728
+ // `--foo: {` disambiguation: are the first two non-ws prelude tokens an
2729
+ // ident starting with `--` followed by a colon? Skip mode reads the
2730
+ // tracked token type/start; non-skip reads the materialized prelude.
2731
+ let dashedDeclaration;
2732
+ if (skip) {
2733
+ dashedDeclaration =
2734
+ firstTT === TT_IDENTIFIER &&
2735
+ ts.input.startsWith("--", firstStart) &&
2736
+ secondTT === TT_COLON;
2737
+ } else if (prelude === null) {
2738
+ dashedDeclaration = false;
2739
+ } else {
2740
+ let firstIdx = 0;
2741
+ /* istanbul ignore next -- @preserve: leading whitespace is discarded before the rule, so the prelude never starts with it */
2742
+ while (
2743
+ firstIdx < prelude.length &&
2744
+ _nodeTypeOf(prelude[firstIdx]) === T_WHITESPACE
2745
+ ) {
2746
+ firstIdx++;
2747
+ }
2748
+ let secondIdx = firstIdx + 1;
2749
+ while (
2750
+ secondIdx < prelude.length &&
2751
+ _nodeTypeOf(prelude[secondIdx]) === T_WHITESPACE
2752
+ ) {
2753
+ secondIdx++;
2754
+ }
2755
+ first = prelude[firstIdx];
2756
+ second = prelude[secondIdx];
2757
+ dashedDeclaration =
2758
+ first &&
2759
+ _nodeTypeOf(first) === T_IDENT &&
2760
+ // Test the source bytes directly — avoids forcing the lazy `value`
2761
+ // slice just to check the `--` custom-property prefix.
2762
+ ts.input.startsWith("--", _nodeStartOf(first)) &&
2763
+ second &&
2764
+ _nodeTypeOf(second) === T_COLON;
2765
+ }
2766
+ if (dashedDeclaration) {
2767
+ /* istanbul ignore if -- @preserve: when nested, `declarationStartLikely` routes every `--x:` to consumeADeclaration (which accepts custom properties), so this fallthrough is unreachable */
2768
+ if (nested) {
2769
+ consumeTheRemnantsOfABadDeclaration(ts, true);
2770
+ } else {
2771
+ consumeABlock(ts);
2772
+ }
2773
+ return undefined;
2774
+ }
2775
+ if (prelude !== null) _setPrelude(rule, prelude);
2776
+ const block = consumeABlock(ts);
2777
+ _setBody(rule, block.decls, block.rules);
2778
+ _setBlock(rule, block.blockStart);
2779
+ _setEnd(rule, block.blockEnd);
2780
+ return rule;
2781
+ }
2782
+
2783
+ // anything else
2784
+ // Consume a component value from input and append the result to rule’s prelude.
2785
+ if (skip) {
2786
+ const tt = t.type;
2787
+ // Track the first two non-whitespace tokens for the disambiguation above.
2788
+ if (tt !== TT_WHITESPACE) {
2789
+ if (firstTT === 0) {
2790
+ firstTT = tt;
2791
+ firstStart = t.start;
2792
+ } else if (secondTT === 0) {
2793
+ secondTT = tt;
2794
+ }
2795
+ }
2796
+ // Only functions (which may hold a url like `:unknown(url(x))`) and the
2797
+ // `(` / `[` blocks that must be balanced are materialized; the url
2798
+ // visitor keeps url / function nodes. Every other selector leaf token has
2799
+ // no non-modules consumer — drop it without building a node.
2800
+ if (
2801
+ tt === TT_FUNCTION ||
2802
+ (tt >= TT_LEFT_PARENTHESIS && tt <= TT_LEFT_CURLY_BRACKET)
2803
+ ) {
2804
+ const node = consumeAComponentValue(ts, t);
2805
+ const ty = _nodeTypeOf(node);
2806
+ if (ty === T_FUNCTION || ty === T_URL) {
2807
+ (prelude || (prelude = _takeList())).push(node);
2808
+ }
2809
+ } else {
2810
+ ts.advance();
2811
+ }
2812
+ } else {
2813
+ (prelude || (prelude = _takeList())).push(consumeAComponentValue(ts, t));
2814
+ }
2815
+ }
2816
+ };
2817
+
2818
+ /**
2819
+ * Consume a block, CSS Syntax Level 3 [§5.4.4](https://drafts.csswg.org/css-syntax/#consume-block) — the next token must be `<{-token>`; discards it, consumes the block's contents (§5.4.5), discards the closing `}`, and returns its `decls` / `rules` pair. We also return the `[start of {, end of }]` offsets so callers can record the block's source position.
2820
+ * @param {TokenStream} ts token stream
2821
+ * @returns {{ decls: Declaration[], rules: Rule[], blockStart: number, blockEnd: number }} block decls + rules and the `{` start / `}` end offsets
2822
+ */
2823
+ const consumeABlock = (ts) => {
2824
+ // Capture the opening `{`'s start before advancing — the stream reuses one
2825
+ // token instance, so `consumeABlocksContents` below would overwrite it.
2826
+ const blockStart = ts.next().start;
2827
+ // Assert (spec): the next token is <{-token>.
2828
+ // Discard a token from input. Consume a block's contents from input and let result be the result. Discard a token from input.
2829
+ ts.discard();
2830
+ const { decls, rules } = consumeABlocksContents(ts);
2831
+ const close = ts.next();
2832
+ const end = close.type === TT_RIGHT_CURLY_BRACKET ? close.end : close.start;
2833
+ ts.discard();
2834
+ return { decls, rules, blockStart, blockEnd: end };
2835
+ };
2836
+
2837
+ /**
2838
+ * 2-token lookahead: is the next non-whitespace pair `<ident> <colon>`?
2839
+ * Peeks raw code points without advancing; comments still fire `onComment` later.
2840
+ * @param {TokenStream} ts token stream
2841
+ * @returns {boolean} true if consume-a-declaration's step 1 + step 3 would both succeed on the current input
2842
+ */
2843
+ const declarationStartLikely = (ts) => {
2844
+ const t = ts.next();
2845
+ if (t.type !== TT_IDENTIFIER) return false;
2846
+ const input = ts.input;
2847
+ const len = input.length;
2848
+ let pos = t.end;
2849
+ for (;;) {
2850
+ if (pos >= len) return false;
2851
+ const cc = input.charCodeAt(pos);
2852
+ if (_isWhiteSpace(cc)) {
2853
+ pos++;
2854
+ continue;
2855
+ }
2856
+ // Skip a `/* … */` comment (the tokenizer filters comments between tokens).
2857
+ if (cc === CC_SOLIDUS && input.charCodeAt(pos + 1) === CC_ASTERISK) {
2858
+ pos += 2;
2859
+ while (
2860
+ pos < len &&
2861
+ !(
2862
+ input.charCodeAt(pos) === CC_ASTERISK &&
2863
+ input.charCodeAt(pos + 1) === CC_SOLIDUS
2864
+ )
2865
+ ) {
2866
+ pos++;
2867
+ }
2868
+ pos += 2;
2869
+ continue;
2870
+ }
2871
+ // `:` is always a standalone <colon-token>, so the next significant char
2872
+ // being `:` is equivalent to the next token being a <colon-token>.
2873
+ return cc === CC_COLON;
2874
+ }
2875
+ };
2876
+
2877
+ /**
2878
+ * Consume a block's contents, CSS Syntax Level 3 [§5.4.5](https://drafts.csswg.org/css-syntax/#consume-block-contents). Per tabatkins/parse-css.js reference impl: returns separate `decls` and `rules` flat lists, both preserved on EOF / `}` (the spec text's "Return rules" single-list model drops trailing decls because there's no implicit flush before EOF / `}`).
2879
+ *
2880
+ * `onNode` is the same streaming extension `consumeAStylesheetsContents` exposes:
2881
+ * when given, each consumed declaration / rule is handed to it immediately (in
2882
+ * source order) instead of being collected, so the returned lists are empty.
2883
+ * @param {TokenStream} ts token stream
2884
+ * @param {((node: Declaration | Rule) => void)=} onNode optional per-node sink (streaming); nodes are not collected when given
2885
+ * @returns {{ decls: Declaration[], rules: Rule[] }} consumed decls + rules (both empty when `onNode` is given; stops at the enclosing `}` / EOF, left in the stream)
2886
+ */
2887
+ const consumeABlocksContents = (ts, onNode) => {
2888
+ /** @type {Declaration[]} */
2889
+ const decls = [];
2890
+ // Child rules are the common empty case (most rules carry only declarations),
2891
+ // so `rules` is allocated lazily and returned as the shared frozen
2892
+ // `_EMPTY_LIST` when nothing was appended — one fewer array per rule. `decls`
2893
+ // stays eager so the hot declaration append keeps a branch-free `push`.
2894
+ /** @type {Rule[] | null} */
2895
+ let rules = null;
2896
+
2897
+ // Process input:
2898
+ for (;;) {
2899
+ const t = ts.next();
2900
+
2901
+ // <whitespace-token> / <semicolon-token>
2902
+ // Discard a token from input (`t` was just peeked and is non-EOF).
2903
+ if (t.type === TT_WHITESPACE || t.type === TT_SEMICOLON) {
2904
+ ts.advance();
2905
+ }
2906
+ // <EOF-token> / <}-token>
2907
+ // Return decls and rules.
2908
+ else if (t.type === TT_EOF || t.type === TT_RIGHT_CURLY_BRACKET) {
2909
+ return { decls, rules: rules || _EMPTY_LIST };
2910
+ }
2911
+ // <at-keyword-token>
2912
+ // Consume an at-rule from input, with nested set to true. If a rule was returned, append it to rules.
2913
+ else if (t.type === TT_AT_KEYWORD) {
2914
+ const atRule = consumeAnAtRule(ts, true);
2915
+ if (atRule) {
2916
+ if (onNode) onNode(atRule);
2917
+ else (rules || (rules = [])).push(atRule);
2918
+ }
2919
+ }
2920
+ // anything else
2921
+ // Mark input. Consume a declaration from input, with nested set to true.
2922
+ // If a declaration was returned, append it to decls, and discard a mark from input.
2923
+ // Otherwise, restore a mark from input, then consume a qualified rule from input, with nested set to true, and <semicolon-token> as the stop token. If a rule was returned, append it to rules.
2924
+ else {
2925
+ // 2-token peek: consume-a-declaration's steps 1 / 3 require `<ident> <colon>`; if absent it would call consume-the-remnants-of-a-bad-declaration (potentially the rest of the enclosing block) only for the restoreMark to undo it (O(N²) on flat blocks of qualified rules). Skip straight to consume-a-qualified-rule — same observable result.
2926
+ if (declarationStartLikely(ts)) {
2927
+ ts.mark();
2928
+ const decl = consumeADeclaration(ts, true);
2929
+ if (decl) {
2930
+ if (onNode) onNode(decl);
2931
+ else decls.push(decl);
2932
+ ts.discardMark();
2933
+ continue;
2934
+ }
2935
+ ts.restoreMark();
2936
+ }
2937
+ const rule = consumeAQualifiedRule(ts, TT_SEMICOLON, true);
2938
+ if (rule) {
2939
+ if (onNode) onNode(rule);
2940
+ else (rules || (rules = [])).push(rule);
2941
+ }
2942
+ }
2943
+ }
2944
+ };
2945
+
2946
+ /**
2947
+ * Consume the remnants of a bad declaration, CSS Syntax Level 3 [§5.4.11](https://drafts.csswg.org/css-syntax/#consume-the-remnants-of-a-bad-declaration). Advances the stream past a malformed declaration's tail so the caller (`consumeABlocksContents`) can resume cleanly.
2948
+ * @param {TokenStream} ts token stream
2949
+ * @param {boolean} nested whether the call originates from inside a `{}` block
2950
+ * @returns {void}
2951
+ */
2952
+ const consumeTheRemnantsOfABadDeclaration = (ts, nested) => {
2953
+ // Process input:
2954
+ for (;;) {
2955
+ const t = ts.next();
2956
+ // <eof-token> / <semicolon-token>
2957
+ // Discard a token from input, and return.
2958
+ if (t.type === TT_EOF || t.type === TT_SEMICOLON) {
2959
+ ts.discard();
2960
+ return;
2961
+ }
2962
+ // <}-token>
2963
+ // If nested is true, return. Otherwise, discard a token.
2964
+ if (t.type === TT_RIGHT_CURLY_BRACKET) {
2965
+ if (nested) return;
2966
+ ts.discard();
2967
+ continue;
2968
+ }
2969
+ // anything else
2970
+ // Consume a component value from input, and do nothing.
2971
+ consumeAComponentValue(ts);
2972
+ }
2973
+ };
2974
+
2975
+ /**
2976
+ * Consume a declaration, CSS Syntax Level 3 [§5.4.6](https://drafts.csswg.org/css-syntax/#consume-declaration).
2977
+ * @param {TokenStream} ts token stream
2978
+ * @param {boolean=} nested true inside a `{}` block — a top-level `}` ends the value
2979
+ * @returns {Declaration | undefined} parsed declaration, or `undefined` on the spec's "return nothing" branches (steps 1, 3, 8)
2980
+ */
2981
+ const consumeADeclaration = (ts, nested = false) => {
2982
+ const { input } = ts;
2983
+ // Let decl be a new declaration, with an initially empty name and a value set to an empty list.
2984
+ const start = ts.next().start;
2985
+ // nameEnd (= start) / important (unset) keep their container defaults;
2986
+ // `value` is set unconditionally at step 5 below.
2987
+ const decl = /** @type {Declaration} */ (
2988
+ _makeContainer(T_DECLARATION, start, start)
2989
+ );
2990
+
2991
+ // 1. If the next token is an <ident-token>, consume a token from input and set decl's name to the returned token's value.
2992
+ // Otherwise, consume the remnants of a bad declaration from input, with nested, and return nothing.
2993
+ if (ts.next().type === TT_IDENTIFIER) {
2994
+ const head = ts.consume();
2995
+ _setName(decl, head.start, head.end);
2996
+ } else {
2997
+ consumeTheRemnantsOfABadDeclaration(ts, nested);
2998
+ return undefined;
2999
+ }
3000
+
3001
+ // 2. Discard whitespace from input.
3002
+ while (ts.next().type === TT_WHITESPACE) ts.advance();
3003
+
3004
+ // 3. If the next token is a <colon-token>, discard a token from input.
3005
+ // Otherwise, consume the remnants of a bad declaration from input, with nested, and return nothing.
3006
+ if (ts.next().type === TT_COLON) {
3007
+ ts.advance();
3008
+ } else {
3009
+ consumeTheRemnantsOfABadDeclaration(ts, nested);
3010
+ return undefined;
3011
+ }
3012
+
3013
+ // 4. Discard whitespace from input.
3014
+ while (ts.next().type === TT_WHITESPACE) ts.advance();
3015
+
3016
+ // Step 8's custom-property test, computed early so the value parse can bail.
3017
+ const isCustomProperty = input.startsWith("--", start);
3018
+
3019
+ // 5. Consume a list of component values from input, with nested, and with <semicolon-token> as the stop token, and set decl's value to the result.
3020
+ // A nested non-custom declaration bails on a top-level `{` — step 8 would
3021
+ // reject it and the caller restores its mark, so parsing the block (the
3022
+ // entire nested-rule body, re-parsed as a qualified rule after the
3023
+ // restore) would be pure waste.
3024
+ const value = consumeAListOfComponentValues(
3025
+ ts,
3026
+ TT_SEMICOLON,
3027
+ nested,
3028
+ nested && !isCustomProperty
3029
+ );
3030
+ if (value === null) return undefined;
3031
+ // `_setValue` waits until step 9: steps 6-8 still trim / scan the scratch,
3032
+ // and the store consumes it when sealing.
3033
+ _setEnd(decl, ts.next().start);
3034
+
3035
+ // 6. If the last two non-<whitespace-token>s in decl's value are a <delim-token> with the value "!" followed by an <ident-token> with a value that is an ASCII case-insensitive match for "important", remove them from decl's value and set decl's important flag.
3036
+ {
3037
+ let last = value.length - 1;
3038
+ while (last >= 0 && _nodeTypeOf(value[last]) === T_WHITESPACE) last--;
3039
+ let prev = last - 1;
3040
+ while (prev >= 0 && _nodeTypeOf(value[prev]) === T_WHITESPACE) prev--;
3041
+ // `!` delim first: it's almost always absent, and `_nodeValueOf` allocates
3042
+ // a slice — this order pays it only for genuine `!important` candidates.
3043
+ if (
3044
+ prev >= 0 &&
3045
+ _nodeTypeOf(value[prev]) === T_DELIM &&
3046
+ input.charCodeAt(_nodeStartOf(value[prev])) === CC_EXCLAMATION &&
3047
+ _nodeTypeOf(value[last]) === T_IDENT &&
3048
+ equalsLowerCase(_nodeValueOf(value[last]), "important")
3049
+ ) {
3050
+ _setImportant(decl);
3051
+ value.length = prev;
3052
+ }
3053
+ }
3054
+
3055
+ // 7. While the last item in decl's value is a <whitespace-token>, remove that token.
3056
+ while (
3057
+ value.length > 0 &&
3058
+ _nodeTypeOf(value[value.length - 1]) === T_WHITESPACE
3059
+ ) {
3060
+ value.pop();
3061
+ }
3062
+
3063
+ // 8. If decl's name starts with "--" (a custom property), it can contain any value (including a top-level `{}` block) — accept it.
3064
+ // Otherwise, if decl's value contains a top-level simple block with an associated token of <{-token>, return nothing.
3065
+ // (That is, a top-level {}-block is only allowed as the entire value of a non-custom property — for CSS Nesting, `consumeABlocksContents`'s `mark` / `restore a mark` will retry the input as a qualified rule.)
3066
+ // Otherwise, accept the declaration. (The spec also checks "contains any non-whitespace-tokens at the top level" → return nothing; we keep empty-value declarations because callers — e.g. `@value name:;` — rely on them.)
3067
+ if (!isCustomProperty) {
3068
+ for (let i = 0; i < value.length; i++) {
3069
+ const v = value[i];
3070
+ if (_nodeTypeOf(v) === T_SIMPLE_BLOCK && _nodeTokenOf(v) === "{") {
3071
+ return undefined;
3072
+ }
3073
+ }
3074
+ }
3075
+
3076
+ // 9. Return decl.
3077
+ _setValue(decl, value);
3078
+ return decl;
3079
+ };
3080
+
3081
+ /**
3082
+ * Consume a list of component values, CSS Syntax Level 3 [§5.4.7](https://drafts.csswg.org/css-syntax/#consume-list-of-components) — consumes component values until EOF, the optional `stopToken`, or — when `nested` — a top-level `}` (left in the stream); a non-nested `}` is a parse error appended as a token.
3083
+ * @param {TokenStream} ts token stream
3084
+ * @param {number=} stopToken token type that terminates the list (left unconsumed)
3085
+ * @param {boolean=} nested true inside a `{}` block — a top-level `}` ends the list (left unconsumed)
3086
+ * @param {boolean=} bailOnCurly abort with `null` on a top-level `{` (left unconsumed) — for callers that would reject the list anyway (consume-a-declaration step 8) and restore a mark
3087
+ * @returns {ComponentValue[] | null} consumed component values, or `null` when `bailOnCurly` hit
3088
+ */
3089
+ const consumeAListOfComponentValues = (
3090
+ ts,
3091
+ stopToken,
3092
+ nested = false,
3093
+ bailOnCurly = false
3094
+ ) => {
3095
+ const values = /** @type {ComponentValue[]} */ (_takeList());
3096
+ // Process input
3097
+ for (;;) {
3098
+ const t = ts.next();
3099
+
3100
+ // <eof-token>
3101
+ // stop token (if passed)
3102
+ // Return values.
3103
+ if (t.type === TT_EOF || t.type === stopToken) {
3104
+ return values;
3105
+ }
3106
+ // <}-token>
3107
+ // If nested is true, return values.
3108
+ // Otherwise, this is a parse error. Consume a token from input and append the result to values.
3109
+ if (t.type === TT_RIGHT_CURLY_BRACKET) {
3110
+ if (nested) return values;
3111
+ const closer = consumeATokenAsNode(ts);
3112
+ // Keep unless the type is explicitly marked skip (1); an out-of-range
3113
+ // lookup on a short `skip.types` yields `undefined`, which must not drop.
3114
+ if (!_skipActive || _skipTypes[_nodeTypeOf(closer)] !== 1) {
3115
+ values.push(closer);
3116
+ }
3117
+ continue;
3118
+ }
3119
+ // A top-level `{` dooms the list for a bailing caller — stop before the
3120
+ // whole block is parsed only to be thrown away on the caller's restore.
3121
+ if (bailOnCurly && t.type === TT_LEFT_CURLY_BRACKET) return null;
3122
+ // anything else
3123
+ // Consume a component value from input, and append the result to values.
3124
+ // Skipped leaf types short-circuit before materializing: no column slot is
3125
+ // written and no node is built (blocks / functions never skip here).
3126
+ const tt = t.type;
3127
+ if (
3128
+ _skipActive &&
3129
+ tt !== TT_FUNCTION &&
3130
+ !(tt >= TT_LEFT_PARENTHESIS && tt <= TT_LEFT_CURLY_BRACKET) &&
3131
+ _skipTypes[_ttToNodeType[tt]] === 1
3132
+ ) {
3133
+ // `t` was just peeked and is a skipped value leaf (never EOF).
3134
+ ts.advance();
3135
+ continue;
3136
+ }
3137
+ const node = consumeAComponentValue(ts, t);
3138
+ if (!_skipActive || _skipTypes[_nodeTypeOf(node)] !== 1) values.push(node);
3139
+ }
3140
+ };
3141
+
3142
+ /**
3143
+ * Consume a component value, CSS Syntax Level 3 [§5.4.8](https://drafts.csswg.org/css-syntax/#consume-component-value) — consumes the next value (simple block, function, or single token); callers guard against EOF before calling.
3144
+ * @param {TokenStream} ts token stream
3145
+ * @param {MutableToken=} t the next token, if the caller already peeked it (defaults to `ts.next()`)
3146
+ * @returns {SimpleBlock | FunctionNode | ComponentValue} the consumed component value
3147
+ */
3148
+ const consumeAComponentValue = (ts, t = ts.next()) => {
3149
+ // `t` is the next token; hot callers already peeked it and pass it in to
3150
+ // skip a redundant `ts.next()` per component value.
3151
+ // <{-token> / <[-token> / <(-token> (the three contiguous opening brackets)
3152
+ // Consume a simple block from input and return the result.
3153
+ if (t.type >= TT_LEFT_PARENTHESIS && t.type <= TT_LEFT_CURLY_BRACKET) {
3154
+ return /** @type {SimpleBlock} */ (consumeASimpleBlock(ts));
3155
+ }
3156
+ // <function-token>
3157
+ // Consume a function from input and return the result.
3158
+ if (t.type === TT_FUNCTION) {
3159
+ return /** @type {FunctionNode} */ (consumeAFunction(ts));
3160
+ }
3161
+ // anything else
3162
+ // Consume a token from input and return the result. (Asserted: not EOF.)
3163
+ // Inlined `consumeATokenAsNode`: `t` is already the peeked next token (and not
3164
+ // EOF), so `advance` past it and materialize it directly — no redundant
3165
+ // `next()` and one fewer call per leaf component value (the bulk of the nodes
3166
+ // on a large stylesheet).
3167
+ ts.advance();
3168
+ return /** @type {ComponentValue} */ (tokenToNode(t));
3169
+ };
3170
+
3171
+ /**
3172
+ * Consume a simple block, CSS Syntax Level 3 [§5.4.9](https://drafts.csswg.org/css-syntax/#consume-simple-block) — the next token must be `(`, `[`, or `{` (asserted); consumes component values via `consumeAComponentValue` until the mirror closing token (`)`, `]`, `}`) or EOF, returning the partial block on EOF (parse error).
3173
+ * @param {TokenStream} ts token stream
3174
+ * @returns {SimpleBlock | undefined} the parsed simple block
3175
+ */
3176
+ const consumeASimpleBlock = (ts) => {
3177
+ const open = ts.next();
3178
+ // Assert (spec): the next token of input is <{-token>, <[-token>, or <(-token>.
3179
+ // Mirror closing token (`opener + 3`) and the associated block char.
3180
+ const ending = open.type + 3;
3181
+ const token = BLOCK_TOKEN_CHAR[open.type - TT_LEFT_PARENTHESIS];
3182
+
3183
+ // Let block be a new simple block with its associated token set to the next token and with its value initially set to an empty list.
3184
+ const block = /** @type {SimpleBlock} */ (
3185
+ _makeContainer(T_SIMPLE_BLOCK, open.start, open.end)
3186
+ );
3187
+ _setToken(block, token);
3188
+ // Sealed (`_setValue`) at the return, once complete.
3189
+ const val = _takeList();
3190
+
3191
+ // Discard a token from input.
3192
+ ts.discard();
3193
+
3194
+ // Process input
3195
+ for (;;) {
3196
+ const t = ts.next();
3197
+
3198
+ // <eof-token>
3199
+ // ending token
3200
+ // Discard a token from input. Return block.
3201
+ if (t.type === TT_EOF || t.type === ending) {
3202
+ ts.discard();
3203
+ _setValue(block, val);
3204
+ _setEnd(block, t.end);
3205
+ return block;
3206
+ }
3207
+
3208
+ // anything else
3209
+ // Consume a component value from input and append the result to block’s value.
3210
+ val.push(consumeAComponentValue(ts, t));
3211
+ }
3212
+ };
3213
+
3214
+ /**
3215
+ * Consume a function, CSS Syntax Level 3 [§5.4.10](https://drafts.csswg.org/css-syntax/#consume-function) — consumes component values up to the matching `)` or EOF (the partial function on EOF is a parse error).
3216
+ * @param {TokenStream} ts token stream
3217
+ * @returns {FunctionNode | undefined} the consumed function node
3218
+ */
3219
+ const consumeAFunction = (ts) => {
3220
+ // Assert (spec): the next token is a <function-token>.
3221
+ // Consume a token from input, and let function be a new function with its name equal the returned token’s value, and a value set to an empty list.
3222
+ const tFn = ts.consume();
3223
+ const fn = /** @type {FunctionNode} */ (
3224
+ _makeContainer(T_FUNCTION, tFn.start, tFn.end)
3225
+ );
3226
+ _setName(fn, tFn.start, tFn.end - 1);
3227
+ // Sealed (`_setValue`) at the return, once complete.
3228
+ const val = _takeList();
3229
+
3230
+ // Process input
3231
+ for (;;) {
3232
+ const t = ts.next();
3233
+
3234
+ if (t.type === TT_EOF || t.type === TT_RIGHT_PARENTHESIS) {
3235
+ // <eof-token>
3236
+ // <)-token>
3237
+ // Discard a token from input. Return function.
3238
+ ts.discard();
3239
+ _setValue(fn, val);
3240
+ _setEnd(fn, t.end);
3241
+ return fn;
3242
+ }
3243
+
3244
+ // anything else
3245
+ // Consume a component value from input and append the result to function’s value.
3246
+ // Same pre-materialization skip as `consumeAListOfComponentValues`.
3247
+ const tt = t.type;
3248
+ if (
3249
+ _skipActive &&
3250
+ tt !== TT_FUNCTION &&
3251
+ !(tt >= TT_LEFT_PARENTHESIS && tt <= TT_LEFT_CURLY_BRACKET) &&
3252
+ _skipTypes[_ttToNodeType[tt]] === 1
3253
+ ) {
3254
+ // `t` was just peeked and is a skipped value leaf (never EOF).
3255
+ ts.advance();
3256
+ continue;
3257
+ }
3258
+ const node = consumeAComponentValue(ts, t);
3259
+ if (!_skipActive || _skipTypes[_nodeTypeOf(node)] !== 1) val.push(node);
3260
+ }
3261
+ };
3262
+
3263
+ // Identifier escape / unescape — operate on the raw text of an
3264
+ // `<ident-token>` (or any source slice that may carry CSS escape sequences).
3265
+ // `escapeIdentifier` produces a CSS-Syntax-3-conformant `<ident-token>` from
3266
+ // an arbitrary string (so the result can be re-tokenized as the same name);
3267
+ // `unescapeIdentifier` reverses tokenizer-time escapes per
3268
+ // https://www.w3.org/TR/css-syntax-3/#consume-escaped-code-point.
3269
+ // Both are pure string functions and have no dependency on the AST; they
3270
+ // live here so the AST module is a one-stop shop for CSS-syntax-level
3271
+ // utilities. `CssParser.js` re-exports them for back-compat with callers
3272
+ // that previously reached them via `getCssParser()`.
3273
+
3274
+ const regexSingleEscape = /[ -,./:-@[\]^`{-~]/;
3275
+ const regexExcessiveSpaces = /(^|\\+)?(\\[A-F0-9]{1,6}) (?![a-fA-F0-9 ])/g;
3276
+ // ASCII escape class per char code: 0 = pass through, 1 = `\<char>` single
3277
+ // escape, 2 = `\HEX ` (control chars). Built from the original predicates so
3278
+ // behaviour is identical; replaces two regex tests per character with one load.
3279
+ const ESCAPE_CLASS_HEX = 2;
3280
+ const ESCAPE_CLASS_SINGLE = 1;
3281
+ const _escapeClassTable = new Uint8Array(128);
3282
+ for (let i = 0; i < 128; i++) {
3283
+ const ch = String.fromCharCode(i);
3284
+ _escapeClassTable[i] = /[\t\n\f\r\v]/.test(ch)
3285
+ ? ESCAPE_CLASS_HEX
3286
+ : ch === "\\" || regexSingleEscape.test(ch)
3287
+ ? ESCAPE_CLASS_SINGLE
3288
+ : 0;
3289
+ }
3290
+
3291
+ /**
3292
+ * Returns escaped identifier.
3293
+ * @param {string} str string
3294
+ * @returns {string} escaped identifier
3295
+ */
3296
+ const _escapeIdentifier = (str) => {
3297
+ let output = "";
3298
+ // Flush safe runs in bulk: only escaped chars break the run, so an
3299
+ // identifier needing no escapes returns `str` unchanged (no allocation).
3300
+ let lastFlush = 0;
3301
+ let needSpaceFix = false;
3302
+ for (let i = 0; i < str.length; i++) {
3303
+ const cc = str.charCodeAt(i);
3304
+ const cls = cc < 128 ? _escapeClassTable[cc] : 0;
3305
+ if (cls === 0) continue;
3306
+ output += str.slice(lastFlush, i);
3307
+ if (cls === ESCAPE_CLASS_SINGLE) {
3308
+ output += `\\${str[i]}`;
3309
+ } else {
3310
+ output += `\\${cc.toString(16).toUpperCase()} `;
3311
+ needSpaceFix = true;
3312
+ }
3313
+ lastFlush = i + 1;
3314
+ }
3315
+ output = lastFlush === 0 ? str : output + str.slice(lastFlush);
3316
+
3317
+ // `-` and digits are class 0 (never escaped above), so testing `str`'s lead
3318
+ // char codes is equivalent to regexes over `output` — and keeps the common
3319
+ // nothing-to-do call regex-free.
3320
+ const first = str.charCodeAt(0);
3321
+ if (
3322
+ first === CC_HYPHEN_MINUS &&
3323
+ (str.charCodeAt(1) === CC_HYPHEN_MINUS || _isDigit(str.charCodeAt(1)))
3324
+ ) {
3325
+ output = `\\-${output.slice(1)}`;
3326
+ } else if (_isDigit(first)) {
3327
+ // A leading digit becomes `\3<digit> `, another `\HEX ` run to clean up.
3328
+ output = `\\3${str.charAt(0)} ${output.slice(1)}`;
3329
+ needSpaceFix = true;
3330
+ }
3331
+
3332
+ // Remove spaces after `\HEX` escapes that are not followed by a hex digit,
3333
+ // since they’re redundant. Only `\HEX ` runs (above) can produce them; plain
3334
+ // single escapes can't, so skip the scan when none were emitted. Note this is
3335
+ // only possible if the escape isn't preceded by an odd number of backslashes.
3336
+ if (needSpaceFix) {
3337
+ output = output.replace(regexExcessiveSpaces, ($0, $1, $2) => {
3338
+ /* istanbul ignore if -- @preserve: this escaper never emits an odd run of backslashes before a `\HEX` escape (literal `\` is doubled) */
3339
+ if ($1 && $1.length % 2) {
3340
+ // It’s not safe to remove the space, so don’t.
3341
+ return $0;
3342
+ }
3343
+
3344
+ // Strip the space.
3345
+ return ($1 || "") + $2;
3346
+ });
3347
+ }
3348
+
3349
+ return output;
3350
+ };
3351
+
3352
+ /**
3353
+ * Returns hex. Reads up to six hex digits from `str` starting at `start` —
3354
+ * indexed rather than sliced, and case-folded inline, so the common
3355
+ * non-hex escape (e.g. `\:` in `focus\:sr-only`) allocates nothing.
3356
+ * @param {string} str string
3357
+ * @param {number} start index just past the `\`
3358
+ * @returns {[string, number] | undefined} hex
3359
+ */
3360
+ const gobbleHex = (str, start) => {
3361
+ let hex = "";
3362
+
3363
+ for (let i = 0; i < 6; i++) {
3364
+ const code = str.charCodeAt(start + i);
3365
+ // valid hex char [0-9 | A-F | a-f]; out-of-range reads NaN -> invalid
3366
+ const valid =
3367
+ (code >= 48 && code <= 57) ||
3368
+ (code >= 65 && code <= 70) ||
3369
+ (code >= 97 && code <= 102);
3370
+ if (!valid) break;
3371
+ // parseInt below is case-insensitive, so keep the original char.
3372
+ hex += str[start + i];
3373
+ }
3374
+
3375
+ if (hex.length === 0) return undefined;
3376
+
3377
+ // One trailing whitespace terminates the escape, matching the tokenizer's
3378
+ // `_consumeAnEscapedCodePoint` — including after a full 6-digit escape, for
3379
+ // any CSS whitespace (not just space), plus the extra LF of a CRLF pair.
3380
+ // https://drafts.csswg.org/css-syntax/#consume-escaped-code-point
3381
+ let consumed = hex.length;
3382
+ const trail = str.charCodeAt(start + hex.length);
3383
+ if (_isWhiteSpace(trail)) {
3384
+ consumed = consumeExtraNewline(trail, str, start + hex.length + 1) - start;
3385
+ }
3386
+
3387
+ const codePoint = Number.parseInt(hex, 16);
3388
+ const isSurrogate = codePoint >= 0xd800 && codePoint <= 0xdfff;
3389
+
3390
+ // Add special case for
3391
+ // "If this number is zero, or is for a surrogate, or is greater than the maximum allowed code point"
3392
+ // https://drafts.csswg.org/css-syntax/#maximum-allowed-code-point
3393
+ if (isSurrogate || codePoint === 0x0000 || codePoint > 0x10ffff) {
3394
+ return ["�", consumed];
3395
+ }
3396
+
3397
+ return [String.fromCodePoint(codePoint), consumed];
3398
+ };
3399
+
3400
+ /**
3401
+ * Unescape identifier.
3402
+ * @param {string} str string
3403
+ * @returns {string} unescaped string
3404
+ */
3405
+ const _unescapeIdentifier = (str) => {
3406
+ // `indexOf` is the no-escape fast path and the start offset in one — the
3407
+ // leading safe run is skipped and an unescaped ident returns as-is.
3408
+ const first = str.indexOf("\\");
3409
+ if (first === -1) return str;
3410
+ let ret = "";
3411
+ // Flush safe runs in bulk instead of appending char by char.
3412
+ let lastFlush = 0;
3413
+ for (let i = first; i < str.length; i++) {
3414
+ if (str[i] !== "\\") continue;
3415
+ ret += str.slice(lastFlush, i);
3416
+ const gobbled = gobbleHex(str, i + 1);
3417
+ if (gobbled !== undefined) {
3418
+ ret += gobbled[0];
3419
+ i += gobbled[1];
3420
+ } else if (str[i + 1] === "\\") {
3421
+ // Retain one `\` of an escaped `\\` pair.
3422
+ // https://github.com/postcss/postcss-selector-parser/commit/268c9a7656fb53f543dc620aa5b73a30ec3ff20e
3423
+ ret += "\\";
3424
+ i += 1;
3425
+ } else if (str.length === i + 1) {
3426
+ // A trailing lone `\` is retained.
3427
+ // https://github.com/postcss/postcss-selector-parser/commit/01a6b346e3612ce1ab20219acc26abdc259ccefb
3428
+ ret += "\\";
3429
+ }
3430
+ // Otherwise the lone `\` is dropped; the next char flushes with its run.
3431
+ lastFlush = i + 1;
3432
+ }
3433
+ ret += str.slice(lastFlush);
3434
+
3435
+ return ret;
3436
+ };
3437
+
3438
+ // Cacheable per `compiler.root` — CssParser binds once per parse via
3439
+ // `.bindCache(...)` and reuses for every identifier.
3440
+ const escapeIdentifier = makeCacheable(_escapeIdentifier);
3441
+ const unescapeIdentifier = makeCacheable(_unescapeIdentifier);
3442
+
3443
+ // A url-token / url-string value's escaped newlines (`url("im\<newline>g.png")`).
3444
+ const STRING_MULTILINE = /\\[\n\r\f]/g;
3445
+ // Leading / trailing CSS whitespace inside a quoted url value.
3446
+ const TRIM_WHITE_SPACES = /(^[ \t\n\r\f]*|[ \t\n\r\f]*$)/g;
3447
+ // One CSS escape: `\` + up to 6 hex digits (+ optional whitespace) or any char.
3448
+ const UNESCAPE = /\\([0-9a-f]{1,6}[ \t\n\r\f]?|[\s\S])/gi;
3449
+
3450
+ /**
3451
+ * Normalize a url value (a url-token's content or a url string's body) into
3452
+ * the form requests are resolved from: escaped newlines removed (string form),
3453
+ * edge whitespace trimmed, CSS escapes and percent-encoding decoded
3454
+ * (`data:` URIs excepted).
3455
+ * @param {string} str url string
3456
+ * @param {boolean} isString is url wrapped in quotes
3457
+ * @returns {string} normalized url
3458
+ */
3459
+ const normalizeUrl = (str, isString) => {
3460
+ // Fast paths: skip the regex engine for the common URL with no escape and
3461
+ // no edge whitespace (e.g. `./img.png`). Each guard is equivalent to the
3462
+ // regex being a no-op.
3463
+ // Remove escaped newlines from a string-token url like `url("im\<newline>g.png")`.
3464
+ if (isString && str.includes("\\")) {
3465
+ str = str.replace(STRING_MULTILINE, "");
3466
+ }
3467
+
3468
+ // Remove unnecessary spaces from `url(" img.png ")`
3469
+ if (
3470
+ str.length !== 0 &&
3471
+ (_isWhiteSpace(str.charCodeAt(0)) ||
3472
+ _isWhiteSpace(str.charCodeAt(str.length - 1)))
3473
+ ) {
3474
+ str = str.replace(TRIM_WHITE_SPACES, "");
3475
+ }
3476
+
3477
+ // Unescape
3478
+ if (str.includes("\\")) {
3479
+ str = str.replace(UNESCAPE, (match) => {
3480
+ if (match.length > 2) {
3481
+ return String.fromCharCode(Number.parseInt(match.slice(1).trim(), 16));
3482
+ }
3483
+ return match[1];
3484
+ });
3485
+ }
3486
+
3487
+ // Char-code gate so the dominant non-`data:` url skips the regex test.
3488
+ if ((str.charCodeAt(0) | 0x20) === CC_LOWER_D && /^data:/i.test(str)) {
3489
+ return str;
3490
+ }
3491
+
3492
+ if (str.includes("%")) {
3493
+ // Convert `url('%2E/img.png')` -> `url('./img.png')`
3494
+ try {
3495
+ str = decodeURIComponent(str);
3496
+ } catch (_err) {
3497
+ // Ignore
3498
+ }
3499
+ }
3500
+
3501
+ return str;
3502
+ };
3503
+
3504
+ // CSS-typed views over the generic visitor machinery (`util/SourceProcessor`),
3505
+ // re-exported so consumers keep importing them from this module.
3506
+ /**
3507
+ * @typedef {import("../util/SourceProcessor").VisitorFn<CssPath>} VisitorFn
3508
+ * @typedef {import("../util/SourceProcessor").VisitorBucket<CssPath>} VisitorBucket
3509
+ * @typedef {import("../util/SourceProcessor").VisitorMap<CssPath>} VisitorMap
3510
+ * @typedef {import("../util/SourceProcessor").CompiledVisitorMap<CssPath>} CompiledVisitorMap
3511
+ */
3512
+
3513
+ /**
3514
+ * A CSS Syntax §5.4 top-level consumer that streams each top-level node it
3515
+ * produces to `onNode` (in source order) rather than collecting it. Every entry
3516
+ * in `TOP_LEVEL_CONSUMERS` shares this shape, so the walk's `grammar` drives any
3517
+ * `as` mode through one call — a future mode is just another map entry.
3518
+ * @typedef {(ts: TokenStream, onNode: (node: Rule | Declaration) => void) => void} TopLevelConsumer
3519
+ */
3520
+
3521
+ /**
3522
+ * `as` value → the §5.4 consumer that streams its top-level nodes. Keyed by the
3523
+ * public `CssParserOptions.as` enum.
3524
+ * @type {Record<string, TopLevelConsumer>}
3525
+ */
3526
+ const TOP_LEVEL_CONSUMERS = {
3527
+ stylesheet: /** @type {TopLevelConsumer} */ (consumeAStylesheetsContents),
3528
+ "block-contents": consumeABlocksContents
3529
+ };
3530
+
3531
+ /**
3532
+ * @typedef {object} CssProcessOptions
3533
+ * @property {LocConverter=} locConverter shared loc converter (default a fresh one over the input)
3534
+ * @property {boolean=} recurseBlocks walk into block bodies' nested rules (default true)
3535
+ * @property {("stylesheet" | "block-contents")=} as which top-level production to consume the source as (see `TOP_LEVEL_CONSUMERS`): `"stylesheet"` (default) or `"block-contents"` (a block's contents, e.g. an HTML `style` attribute)
3536
+ * @property {SkipOptions=} skip what the grammar may leave un-materialized to go faster — safe only for parts nothing reads in the active parse; default skip nothing
3537
+ */
3538
+
3539
+ /**
3540
+ * `CssProcessOptions.skip`: two independent axes, so each reads unambiguously.
3541
+ * @typedef {object} SkipOptions
3542
+ * @property {Uint8Array=} types component-value node types to drop from declaration value / function-arg lists (indexed by `NodeType`, 1 = skip; build with `buildSkipSet`)
3543
+ * @property {boolean=} selectorPrelude drop qualified-rule (selector) preludes — the rule and its block are still produced (default false)
3544
+ * @property {boolean=} atRulePrelude drop at-rule preludes — the at-rule and its block are still produced (default false)
3545
+ */
3546
+
3547
+ // Per-parse walk state in module slots (same pattern as `_skip*`) so the walk
3548
+ // functions below are module-level constants: one function identity across
3549
+ // parses keeps the recursive per-node call sites monomorphic and drops the
3550
+ // per-parse closure allocations.
3551
+ /** @typedef {import("../util/SourceProcessor").CompiledVisitorBucket<CssPath>} CompiledVisitorBucket */
3552
+ /** @type {CompiledVisitorMap} */
3553
+ let _visitors = /** @type {CompiledVisitorMap} */ (/** @type {unknown} */ ([]));
3554
+ let _recurseBlocks = true;
3555
+ /** @type {CompiledVisitorBucket | undefined} */
3556
+ let _commentBucket;
3557
+
3558
+ // Comments reach the visitor map through `NodeType.Comment` instead of a
3559
+ // side callback. They fire during tokenization — in source order among
3560
+ // comments, not interleaved with the node walk — on a transient store node so
3561
+ // `A.start`/`end`/`loc`/`source` work. No comment visitor → no callback →
3562
+ // the tokenizer skips comments with zero overhead.
3563
+ /** @type {(input: string, start: number, end: number) => number} */
3564
+ const _grammarOnComment = (_src, start, end) => {
3565
+ const node = _makeLeaf(T_COMMENT, start, end);
3566
+ _currentNode = node;
3567
+ _currentParent = null;
3568
+ _currentIndex = 0;
3569
+ const bucket = /** @type {CompiledVisitorBucket} */ (_commentBucket);
3570
+ const e = bucket.enter;
3571
+ for (let i = 0; i < e.length; i++) e[i](A);
3572
+ const x = bucket.exit;
3573
+ for (let i = 0; i < x.length; i++) x[i](A);
3574
+ return end;
3575
+ };
3576
+
3577
+ /**
3578
+ * Walk a component-value subtree; children are already materialized. Fetches
3579
+ * the node's visitor bucket once (reused for enter + exit) and uses index
3580
+ * loops — `for…of` would allocate an iterator per node on this hot path.
3581
+ * @param {Node} node component-value root
3582
+ * @param {Node | null} parent enclosing node
3583
+ * @param {number} index node's index within its sibling list
3584
+ */
3585
+ const _walkValue = (node, parent, index) => {
3586
+ const ty = _types[_nodeIndex(node)];
3587
+ const b = _visitors[ty];
3588
+ let skip = false;
3589
+ if (b !== undefined && b.enter.length !== 0) {
3590
+ _walkSkip = false;
3591
+ _currentNode = node;
3592
+ _currentParent = parent;
3593
+ _currentIndex = index;
3594
+ const e = b.enter;
3595
+ for (let i = 0; i < e.length; i++) e[i](A);
3596
+ skip = _walkSkip;
3597
+ _walkSkip = false;
3598
+ }
3599
+ if (!skip && (ty === T_FUNCTION || ty === T_SIMPLE_BLOCK)) {
3600
+ const i0 = _nodeIndex(node);
3601
+ const vs = _listStarts[i0];
3602
+ const ve = vs + _listLens[i0];
3603
+ for (let i = vs; i < ve; i++) _walkValue(_nodeRef(_flat[i]), node, i - vs);
3604
+ }
3605
+ if (b !== undefined) {
3606
+ // Rebind: descending into children moved the path.
3607
+ _currentNode = node;
3608
+ _currentParent = parent;
3609
+ _currentIndex = index;
3610
+ const x = b.exit;
3611
+ for (let i = 0; i < x.length; i++) x[i](A);
3612
+ }
3613
+ };
3614
+
3615
+ /**
3616
+ * Walk a structural subtree; an at-rule / qualified-rule's block was parsed
3617
+ * eagerly (§5.4.4), so its `value` holds the nested rules / declarations.
3618
+ * @param {Node} node structural-tree root
3619
+ * @param {Node | null} parent enclosing node
3620
+ * @param {number} index node's index within its sibling list (declarations and child rules index independently)
3621
+ */
3622
+ const _walkRule = (node, parent, index) => {
3623
+ const i0 = _nodeIndex(node);
3624
+ const ty = _types[i0];
3625
+ const b = _visitors[ty];
3626
+ let skip = false;
3627
+ if (b !== undefined && b.enter.length !== 0) {
3628
+ _walkSkip = false;
3629
+ _currentNode = node;
3630
+ _currentParent = parent;
3631
+ _currentIndex = index;
3632
+ const e = b.enter;
3633
+ for (let i = 0; i < e.length; i++) e[i](A);
3634
+ skip = _walkSkip;
3635
+ _walkSkip = false;
3636
+ }
3637
+ if (!skip) {
3638
+ if (ty === T_AT_RULE || ty === T_QUALIFIED_RULE) {
3639
+ const ps = _listStarts[i0];
3640
+ const pe = ps + _listLens[i0];
3641
+ for (let i = ps; i < pe; i++) {
3642
+ _walkValue(_nodeRef(_flat[i]), node, i - ps);
3643
+ }
3644
+ if (_recurseBlocks) {
3645
+ // Declarations then child rules — downstream consumers don't need them strictly interleaved in source order.
3646
+ const decls = _declarationLists[i0];
3647
+ if (decls) {
3648
+ for (let i = 0; i < decls.length; i++) _walkRule(decls[i], node, i);
3649
+ }
3650
+ const ch = _childRuleLists[i0];
3651
+ if (ch) for (let i = 0; i < ch.length; i++) _walkRule(ch[i], node, i);
3652
+ }
3653
+ } else if (ty === T_DECLARATION) {
3654
+ const vs = _listStarts[i0];
3655
+ const ve = vs + _listLens[i0];
3656
+ for (let i = vs; i < ve; i++) {
3657
+ _walkValue(_nodeRef(_flat[i]), node, i - vs);
3658
+ }
3659
+ }
3660
+ }
3661
+ if (b !== undefined) {
3662
+ // Rebind: descending into children moved the path.
3663
+ _currentNode = node;
3664
+ _currentParent = parent;
3665
+ _currentIndex = index;
3666
+ const x = b.exit;
3667
+ for (let i = 0; i < x.length; i++) x[i](A);
3668
+ }
3669
+ };
3670
+
3671
+ /**
3672
+ * The `grammar` streaming sink: walk one top-level node, then recycle the
3673
+ * buffers for the next.
3674
+ * @param {Rule | Declaration} node top-level node
3675
+ */
3676
+ const _walkTopLevel = (node) => {
3677
+ _walkRule(node, null, 0);
3678
+ if (_nodeCount > _peak) _peak = _nodeCount;
3679
+ if (_flatTop > _flatPeak) _flatPeak = _flatTop;
3680
+ _nodeCount = 0;
3681
+ _flatTop = 0;
3682
+ };
3683
+
3684
+ // The store buffers grow to the largest single top-level rule ever parsed and
3685
+ // live at module level; above this capacity they are re-shrunk after a parse
3686
+ // so one pathological rule can't pin megabytes for the process lifetime.
3687
+ const _SHRINK_CAPACITY = 65536;
3688
+
3689
+ /**
3690
+ * The CSS `SourceProcessor` grammar: consume top-level rules one at a time
3691
+ * (§5.4.1) and walk each immediately, firing `enter` / `exit` in source order
3692
+ * without building a whole-stylesheet array first. `recurseBlocks: false` skips
3693
+ * walking block bodies' (eagerly parsed) nested rules (caller drives nested
3694
+ * traversal itself).
3695
+ * @param {string} input source text
3696
+ * @param {CompiledVisitorMap} visitors compiled visitor map
3697
+ * @param {CssProcessOptions} options process options
3698
+ */
3699
+ const grammar = (input, visitors, options) => {
3700
+ const locConverter = options.locConverter || new LocConverter(input);
3701
+ _setupParse(input, locConverter);
3702
+ const skip = options.skip;
3703
+ _skipTypes = (skip && skip.types) || _NO_SKIP_TYPES;
3704
+ _skipActive = _skipTypes !== _NO_SKIP_TYPES;
3705
+ _skipSelectorPrelude = skip !== undefined && skip.selectorPrelude === true;
3706
+ _skipAtRulePrelude = skip !== undefined && skip.atRulePrelude === true;
3707
+ _recurseBlocks = options.recurseBlocks !== false;
3708
+ _visitors = visitors;
3709
+ _commentBucket = visitors[T_COMMENT];
3710
+
3711
+ // Stream each top-level node (selected by `as`) to the walker the moment it's
3712
+ // consumed, rather than collecting them first — so the whole AST is never
3713
+ // held at once; peak heap is ~one top-level node's subtree.
3714
+ const ts = new TokenStream(
3715
+ input,
3716
+ 0,
3717
+ locConverter,
3718
+ _commentBucket === undefined ? undefined : _grammarOnComment
3719
+ );
3720
+ const consume =
3721
+ TOP_LEVEL_CONSUMERS[options.as || "stylesheet"] ||
3722
+ consumeAStylesheetsContents;
3723
+ try {
3724
+ consume(ts, _walkTopLevel);
3725
+ } finally {
3726
+ // Drop the module-level column references so the last parsed source (and
3727
+ // its LocConverter / child lists / visitors) don't stay alive between
3728
+ // parses.
3729
+ _input = "";
3730
+ _locConverter = /** @type {LocConverter} */ (/** @type {unknown} */ (null));
3731
+ _declarationLists.length = 0;
3732
+ _childRuleLists.length = 0;
3733
+ _flatTop = 0;
3734
+ _listPool.length = 0;
3735
+ if (_flat.length > _SHRINK_CAPACITY) {
3736
+ _flatGrowHint = _flatPeak;
3737
+ _flat = new Int32Array(0);
3738
+ }
3739
+ _visitors = /** @type {CompiledVisitorMap} */ (/** @type {unknown} */ ([]));
3740
+ _commentBucket = undefined;
3741
+ if (_capacity > _SHRINK_CAPACITY) {
3742
+ // +1: node ids are 1-based and grow fires at `id >= capacity`.
3743
+ _growHint = _peak + 1;
3744
+ _capacity = 0;
3745
+ _types = new Uint8Array(0);
3746
+ _starts = new Int32Array(0);
3747
+ _ends = new Int32Array(0);
3748
+ _aux0 = new Int32Array(0);
3749
+ _aux1 = new Int32Array(0);
3750
+ _flags = new Uint8Array(0);
3751
+ _listStarts = new Int32Array(0);
3752
+ _listLens = new Int32Array(0);
3753
+ }
3754
+ _peak = 0;
3755
+ _flatPeak = 0;
3756
+ }
3757
+ };
3758
+
3759
+ /**
3760
+ * The generic visitor coordinator (`util/SourceProcessor`) bound to the CSS
3761
+ * `grammar`. Babel-style usage:
3762
+ *
3763
+ * ```
3764
+ * new SourceProcessor({ skip }).use({ [NodeType.AtRule]: (path) => {} }).process(source);
3765
+ * ```
3766
+ * @extends {GenericSourceProcessor<CssPath, CssProcessOptions>}
3767
+ */
3768
+ class SourceProcessor extends GenericSourceProcessor {
3769
+ /**
3770
+ * @param {CssProcessOptions=} options default process options (`skip`, `as`, …) for every `process` call
3771
+ */
3772
+ constructor(options) {
3773
+ super(grammar, options);
3774
+ }
3775
+ }
3776
+
3777
+ /**
3778
+ * Build a `SkipOptions.types` set (drop these component-value node types from
3779
+ * value / function-arg lists) from a list of `NodeType`s. Preludes are separate
3780
+ * (`SkipOptions.selectorPrelude` / `atRulePrelude`). The caller owns the safety
3781
+ * contract: only pass types nothing reads in the intended parse. Two
3782
+ * grammar-internal caveats beyond consumer needs: dropping both `Delim` and
3783
+ * `Ident` loses `!important` detection, and dropping `SimpleBlock` loses the
3784
+ * custom-property `{}`-value check (and its subtree). Precompute once per
3785
+ * configuration and reuse across parses.
3786
+ * @param {number[]} nodeTypes component-value node types to drop
3787
+ * @returns {Uint8Array} skip-types set indexed by `NodeType`
3788
+ */
3789
+ const buildSkipSet = (nodeTypes) => {
3790
+ const set = new Uint8Array(32);
3791
+ for (let i = 0; i < nodeTypes.length; i++) set[nodeTypes[i]] = 1;
3792
+ return set;
3793
+ };
3794
+
3795
+ /* eslint-disable jsdoc/require-template -- `A` below is the accessor const, not a type parameter */
3796
+ /**
3797
+ * The CSS path (Babel's `path` shape): the AST accessor with the walk's
3798
+ * current position on it — the single argument every visitor receives.
3799
+ * @typedef {typeof A} CssPath
3800
+ */
3801
+ /* eslint-enable jsdoc/require-template */
3802
+
3803
+ // A fresh (safely retainable) array view of a node's flat content span —
3804
+ // visitors that read `A.children` / `A.prelude` may keep the result.
3805
+ /** @type {(n: Node) => Node[]} */
3806
+ const _materializeList = (n) => {
3807
+ const i = _nodeIndex(n);
3808
+ const start = _listStarts[i];
3809
+ const len = _listLens[i];
3810
+ /** @type {Node[]} */
3811
+ const out = [];
3812
+ for (let k = 0; k < len; k++) out.push(_nodeRef(_flat[start + k]));
3813
+ return out;
3814
+ };
3815
+
3816
+ // Babel's `path.skip()`, children-only: set by `A.skipChildren()` during an
3817
+ // `enter` dispatch, consumed by the walk.
3818
+ let _walkSkip = false;
3819
+ // The walk's current position (`A.node` / `A.parent` read these; module-level
3820
+ // so the accessor methods' defaults avoid self-referential `this` typing).
3821
+ /** @type {Node} */
3822
+ let _currentNode = /** @type {Node} */ (/** @type {unknown} */ (0));
3823
+ /** @type {Node | null} */
3824
+ let _currentParent = null;
3825
+ // Index of the current node within its sibling list (a rule body's declarations
3826
+ // and child rules are separate lists, so each indexes from 0 independently).
3827
+ let _currentIndex = 0;
3828
+
3829
+ // AST field-access seam. Every AST-node field read by `CssParser` goes through
3830
+ // one of these accessors (`n` is an integer node id into the columns), so
3831
+ // the storage stays behind the accessor without any consumer edit. `value` is
3832
+ // the leaf-token string; container child lists are `children` / `prelude` /
3833
+ // `declarations` / `childRules`.
3834
+ const A = {
3835
+ // === path position (rebound by the walk before every visitor call) ===
3836
+ /**
3837
+ * @returns {Node} current node — only valid during a visitor callback
3838
+ */
3839
+ get node() {
3840
+ return _currentNode;
3841
+ },
3842
+ /**
3843
+ * @returns {Node | null} enclosing node (null = a top-level node)
3844
+ */
3845
+ get parent() {
3846
+ return _currentParent;
3847
+ },
3848
+ /**
3849
+ * @returns {number} index of the current node within its sibling list (0 for a top-level node) — only valid during a visitor callback
3850
+ */
3851
+ get index() {
3852
+ return _currentIndex;
3853
+ },
3854
+ /** Stop the walk descending into the current node (enter only). */
3855
+ skipChildren() {
3856
+ _walkSkip = true;
3857
+ },
3858
+ // === field reads — `n` defaults to the current node ===
3859
+ /**
3860
+ * @param {Node=} n node
3861
+ * @returns {number} node type
3862
+ */
3863
+ type(n = _currentNode) {
3864
+ return _types[_nodeIndex(n)];
3865
+ },
3866
+ /**
3867
+ * @param {Node=} n node
3868
+ * @returns {number} start offset
3869
+ */
3870
+ start(n = _currentNode) {
3871
+ return _starts[_nodeIndex(n)];
3872
+ },
3873
+ /**
3874
+ * @param {Node=} n node
3875
+ * @returns {number} end offset
3876
+ */
3877
+ end(n = _currentNode) {
3878
+ return _ends[_nodeIndex(n)];
3879
+ },
3880
+ /**
3881
+ * @param {Node=} n node
3882
+ * @returns {[number, number]} start / end offsets
3883
+ */
3884
+ range(n = _currentNode) {
3885
+ const i = _nodeIndex(n);
3886
+ return [_starts[i], _ends[i]];
3887
+ },
3888
+ /**
3889
+ * @param {Node=} n node
3890
+ * @returns {{ start: { line: number, column: number }, end: { line: number, column: number } }} source location
3891
+ */
3892
+ loc(n = _currentNode) {
3893
+ const i = _nodeIndex(n);
3894
+ const lc = _locConverter;
3895
+ const s = lc.get(_starts[i]);
3896
+ const sl = s.line;
3897
+ const sc = s.column;
3898
+ const e = lc.get(_ends[i]);
3899
+ return {
3900
+ start: { line: sl, column: sc },
3901
+ end: { line: e.line, column: e.column }
3902
+ };
3903
+ },
3904
+ /**
3905
+ * @param {Node=} n node
3906
+ * @returns {string} raw source slice
3907
+ */
3908
+ source(n = _currentNode) {
3909
+ const i = _nodeIndex(n);
3910
+ return _input.slice(_starts[i], _ends[i]);
3911
+ },
3912
+ /**
3913
+ * @param {Node=} n node
3914
+ * @returns {string} raw token value
3915
+ */
3916
+ value(n = _currentNode) {
3917
+ return _valueOf(_nodeIndex(n));
3918
+ },
3919
+ /**
3920
+ * @param {Node=} n node
3921
+ * @returns {string} unescaped token value
3922
+ */
3923
+ unescaped(n = _currentNode) {
3924
+ const i = _nodeIndex(n);
3925
+ const v = _valueOf(i);
3926
+ return _types[i] === T_STRING
3927
+ ? unescapeIdentifier(v.slice(1, -1))
3928
+ : unescapeIdentifier(v);
3929
+ },
3930
+ /**
3931
+ * @param {Node=} n node
3932
+ * @returns {string} hash / numeric type flag
3933
+ */
3934
+ typeFlag(n = _currentNode) {
3935
+ const i = _nodeIndex(n);
3936
+ if (_types[i] === T_HASH) {
3937
+ const input = _input;
3938
+ const p = _starts[i] + 1;
3939
+ return _ifThreeCodePointsWouldStartAnIdentSequence(
3940
+ input,
3941
+ p,
3942
+ input.charCodeAt(p),
3943
+ input.charCodeAt(p + 1),
3944
+ input.charCodeAt(p + 2)
3945
+ )
3946
+ ? "id"
3947
+ : "unrestricted";
3948
+ }
3949
+ const v = _valueOf(i);
3950
+ return _typeFlagOf(
3951
+ _types[i] === T_DIMENSION ? v.slice(0, _consumeANumber(v, 0)) : v
3952
+ );
3953
+ },
3954
+ /**
3955
+ * @param {Node=} n node
3956
+ * @returns {number} url content start offset
3957
+ */
3958
+ contentStart(n = _currentNode) {
3959
+ return _aux0[_nodeIndex(n)];
3960
+ },
3961
+ /**
3962
+ * @param {Node=} n node
3963
+ * @returns {number} url content end offset
3964
+ */
3965
+ contentEnd(n = _currentNode) {
3966
+ return _aux1[_nodeIndex(n)];
3967
+ },
3968
+ /**
3969
+ * @param {Node=} n node
3970
+ * @returns {string} rule / declaration / function name
3971
+ */
3972
+ name(n = _currentNode) {
3973
+ const i = _nodeIndex(n);
3974
+ return _types[i] === T_AT_RULE
3975
+ ? _input.slice(_starts[i] + 1, _aux0[i])
3976
+ : _input.slice(_starts[i], _aux0[i]);
3977
+ },
3978
+ /**
3979
+ * @param {Node=} n node
3980
+ * @returns {number} name start offset
3981
+ */
3982
+ nameStart(n = _currentNode) {
3983
+ return _starts[_nodeIndex(n)];
3984
+ },
3985
+ /**
3986
+ * @param {Node=} n node
3987
+ * @returns {number} name end offset
3988
+ */
3989
+ nameEnd(n = _currentNode) {
3990
+ return _aux0[_nodeIndex(n)];
3991
+ },
3992
+ /**
3993
+ * @param {Node=} n node
3994
+ * @returns {string} unescaped name
3995
+ */
3996
+ unescapedName(n = _currentNode) {
3997
+ return unescapeIdentifier(A.name(n));
3998
+ },
3999
+ /**
4000
+ * @param {Node=} n node
4001
+ * @returns {ComponentValue[]} function / block children
4002
+ */
4003
+ children(n = _currentNode) {
4004
+ return /** @type {ComponentValue[]} */ (_materializeList(n));
4005
+ },
4006
+ /**
4007
+ * @param {Node=} n node
4008
+ * @returns {ComponentValue[]} rule prelude
4009
+ */
4010
+ prelude(n = _currentNode) {
4011
+ return /** @type {ComponentValue[]} */ (_materializeList(n));
4012
+ },
4013
+ /**
4014
+ * @param {Node=} n node
4015
+ * @returns {number} number of children (value / prelude) without materializing the list
4016
+ */
4017
+ childCount(n = _currentNode) {
4018
+ return _listLens[_nodeIndex(n)];
4019
+ },
4020
+ /**
4021
+ * @param {Node} n node
4022
+ * @param {number} i child index (`0 <= i < childCount(n)`)
4023
+ * @returns {ComponentValue} i-th child (value / prelude) without materializing the list
4024
+ */
4025
+ childAt(n, i) {
4026
+ return /** @type {ComponentValue} */ (
4027
+ _nodeRef(_flat[_listStarts[_nodeIndex(n)] + i])
4028
+ );
4029
+ },
4030
+ /**
4031
+ * @param {Node=} n node
4032
+ * @returns {Declaration[] | null} block declarations
4033
+ */
4034
+ declarations(n = _currentNode) {
4035
+ // `_makeContainer` only populates this slot for rules; a non-rule node
4036
+ // reads `undefined`, normalized to `null` to keep the documented contract.
4037
+ return /** @type {Declaration[] | null} */ (
4038
+ _declarationLists[_nodeIndex(n)] || null
4039
+ );
4040
+ },
4041
+ /**
4042
+ * @param {Node=} n node
4043
+ * @returns {Rule[] | null} block child rules
4044
+ */
4045
+ childRules(n = _currentNode) {
4046
+ return /** @type {Rule[] | null} */ (
4047
+ _childRuleLists[_nodeIndex(n)] || null
4048
+ );
4049
+ },
4050
+ /**
4051
+ * @param {Node=} n node
4052
+ * @returns {number} block start offset
4053
+ */
4054
+ blockStart(n = _currentNode) {
4055
+ return _aux1[_nodeIndex(n)];
4056
+ },
4057
+ /**
4058
+ * @param {Node=} n node
4059
+ * @returns {number} block end offset
4060
+ */
4061
+ blockEnd(n = _currentNode) {
4062
+ const i = _nodeIndex(n);
4063
+ return _aux1[i] !== -1 ? _ends[i] : -1;
4064
+ },
4065
+ /**
4066
+ * @param {Node=} n node
4067
+ * @returns {boolean} `!important` flag
4068
+ */
4069
+ important(n = _currentNode) {
4070
+ return (_flags[_nodeIndex(n)] & 1) !== 0;
4071
+ },
4072
+ /**
4073
+ * @param {Node=} n node
4074
+ * @returns {SimpleBlockToken} block opening token
4075
+ */
4076
+ blockToken(n = _currentNode) {
4077
+ return /** @type {SimpleBlockToken} */ (_input[_starts[_nodeIndex(n)]]);
4078
+ },
4079
+ // Writers — `CssParser` rewrites a rule's end / block-end when it folds an
4080
+ // inline ICSS `:import` / `:export` body into a single dependency. A block
4081
+ // rule's `blockEnd` is its `end`, so `setBlockEnd` writes the same `end` slot.
4082
+ /**
4083
+ * @param {Node} n node
4084
+ * @param {number} v new end offset
4085
+ */
4086
+ setEnd(n, v) {
4087
+ _ends[_nodeIndex(n)] = v;
4088
+ },
4089
+ /**
4090
+ * @param {Node} n node
4091
+ * @param {number} v new block end offset
4092
+ */
4093
+ setBlockEnd(n, v) {
4094
+ _ends[_nodeIndex(n)] = v;
4095
+ }
4096
+ };
4097
+
4098
+ // The AST node shapes (`Node`, `Token`, and the container typedefs) are types
4099
+ // only — nodes are integer ids into the store, surfaced by the `A` visitor
4100
+ // accessor and the `parseA*` readers. Runtime exports: the `A` accessor, the
4101
+ // full CSS-Syntax-3 §5.3 `parseA*` entry-point surface, the `TokenStream` (so
4102
+ // callers can pass a pre-built stream to any `parseA*`), and the `escape` /
4103
+ // `unescapeIdentifier` string utils.
4104
+ module.exports.A = A;
4105
+ module.exports.NodeType = NodeType;
4106
+ module.exports.SourceProcessor = SourceProcessor;
4107
+ module.exports.TT_AT_KEYWORD = TT_AT_KEYWORD;
4108
+ module.exports.TT_BAD_STRING_TOKEN = TT_BAD_STRING_TOKEN;
4109
+ module.exports.TT_BAD_URL_TOKEN = TT_BAD_URL_TOKEN;
4110
+ module.exports.TT_CDC = TT_CDC;
4111
+ module.exports.TT_CDO = TT_CDO;
4112
+ module.exports.TT_COLON = TT_COLON;
4113
+ module.exports.TT_COMMA = TT_COMMA;
4114
+ module.exports.TT_COMMENT = TT_COMMENT;
4115
+ module.exports.TT_DELIM = TT_DELIM;
4116
+ module.exports.TT_DIMENSION = TT_DIMENSION;
4117
+ module.exports.TT_EOF = TT_EOF;
4118
+ module.exports.TT_FUNCTION = TT_FUNCTION;
4119
+ module.exports.TT_HASH = TT_HASH;
4120
+ module.exports.TT_IDENTIFIER = TT_IDENTIFIER;
4121
+ module.exports.TT_LEFT_CURLY_BRACKET = TT_LEFT_CURLY_BRACKET;
4122
+ module.exports.TT_LEFT_PARENTHESIS = TT_LEFT_PARENTHESIS;
4123
+ module.exports.TT_LEFT_SQUARE_BRACKET = TT_LEFT_SQUARE_BRACKET;
4124
+ module.exports.TT_NUMBER = TT_NUMBER;
4125
+ module.exports.TT_PERCENTAGE = TT_PERCENTAGE;
4126
+ module.exports.TT_RIGHT_CURLY_BRACKET = TT_RIGHT_CURLY_BRACKET;
4127
+ module.exports.TT_RIGHT_PARENTHESIS = TT_RIGHT_PARENTHESIS;
4128
+ module.exports.TT_RIGHT_SQUARE_BRACKET = TT_RIGHT_SQUARE_BRACKET;
4129
+ module.exports.TT_SEMICOLON = TT_SEMICOLON;
4130
+ module.exports.TT_STRING = TT_STRING;
4131
+ module.exports.TT_URL = TT_URL;
4132
+ module.exports.TT_WHITESPACE = TT_WHITESPACE;
4133
+ module.exports.TokenStream = TokenStream;
4134
+ module.exports.buildSkipSet = buildSkipSet;
4135
+ module.exports.equalsLowerCase = equalsLowerCase;
4136
+ module.exports.escapeIdentifier = escapeIdentifier;
4137
+ module.exports.isDashedIdentifier = isDashedIdentifier;
4138
+ // CSS Syntax §4.2 "whitespace" (space / tab / newline / CR / FF) — the
4139
+ // tokenizer's whitespace class, exported under the spec's name.
4140
+ module.exports.isWhitespace = _isWhiteSpace;
4141
+ module.exports.normalizeUrl = normalizeUrl;
4142
+ module.exports.parseABlocksContents = parseABlocksContents;
4143
+ module.exports.parseACommaSeparatedListOfComponentValues =
4144
+ parseACommaSeparatedListOfComponentValues;
4145
+ module.exports.parseAComponentValue = parseAComponentValue;
4146
+ module.exports.parseADeclaration = parseADeclaration;
4147
+ module.exports.parseAListOfComponentValues = parseAListOfComponentValues;
4148
+ module.exports.parseARule = parseARule;
4149
+ module.exports.parseAStylesheet = parseAStylesheet;
4150
+ module.exports.parseAStylesheetsContents = parseAStylesheetsContents;
4151
+ module.exports.rangeEquals = rangeEquals;
4152
+ module.exports.rangeEqualsLowerCase = rangeEqualsLowerCase;
4153
+ module.exports.readToken = readToken;
4154
+ module.exports.toLowerCaseIfNeeded = toLowerCaseIfNeeded;
4155
+ module.exports.unescapeIdentifier = unescapeIdentifier;