@tenphi/tasty 1.1.0 → 1.3.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 (257) hide show
  1. package/dist/_virtual/_rolldown/runtime.js +1 -2
  2. package/dist/chunks/cacheKey.d.ts +1 -0
  3. package/dist/chunks/cacheKey.js +1 -2
  4. package/dist/chunks/cacheKey.js.map +1 -1
  5. package/dist/chunks/definitions.js +1 -2
  6. package/dist/chunks/definitions.js.map +1 -1
  7. package/dist/chunks/index.d.ts +1 -0
  8. package/dist/chunks/renderChunk.d.ts +1 -0
  9. package/dist/chunks/renderChunk.js +1 -2
  10. package/dist/chunks/renderChunk.js.map +1 -1
  11. package/dist/compute-styles.d.ts +31 -0
  12. package/dist/compute-styles.js +356 -0
  13. package/dist/compute-styles.js.map +1 -0
  14. package/dist/config.d.ts +7 -1
  15. package/dist/config.js +25 -22
  16. package/dist/config.js.map +1 -1
  17. package/dist/core/index.d.ts +4 -4
  18. package/dist/core/index.js +6 -6
  19. package/dist/counter-style/index.js +1 -1
  20. package/dist/counter-style/index.js.map +1 -1
  21. package/dist/debug.js +1 -2
  22. package/dist/debug.js.map +1 -1
  23. package/dist/font-face/index.js +1 -1
  24. package/dist/font-face/index.js.map +1 -1
  25. package/dist/hooks/index.d.ts +7 -0
  26. package/dist/hooks/resolve-ssr-collector.js +1 -2
  27. package/dist/hooks/resolve-ssr-collector.js.map +1 -1
  28. package/dist/hooks/useCounterStyle.js +2 -3
  29. package/dist/hooks/useCounterStyle.js.map +1 -1
  30. package/dist/hooks/useFontFace.js +2 -3
  31. package/dist/hooks/useFontFace.js.map +1 -1
  32. package/dist/hooks/useGlobalStyles.js +4 -5
  33. package/dist/hooks/useGlobalStyles.js.map +1 -1
  34. package/dist/hooks/useKeyframes.js +3 -4
  35. package/dist/hooks/useKeyframes.js.map +1 -1
  36. package/dist/hooks/useProperty.js +2 -3
  37. package/dist/hooks/useProperty.js.map +1 -1
  38. package/dist/hooks/useRawCSS.js +2 -3
  39. package/dist/hooks/useRawCSS.js.map +1 -1
  40. package/dist/hooks/useStyles.d.ts +3 -8
  41. package/dist/hooks/useStyles.js +7 -214
  42. package/dist/hooks/useStyles.js.map +1 -1
  43. package/dist/index.d.ts +5 -5
  44. package/dist/index.js +7 -7
  45. package/dist/injector/index.d.ts +1 -18
  46. package/dist/injector/index.js +5 -19
  47. package/dist/injector/index.js.map +1 -1
  48. package/dist/injector/injector.js +1 -2
  49. package/dist/injector/injector.js.map +1 -1
  50. package/dist/injector/sheet-manager.js +1 -2
  51. package/dist/injector/sheet-manager.js.map +1 -1
  52. package/dist/keyframes/index.js +1 -1
  53. package/dist/parser/classify.js +1 -2
  54. package/dist/parser/classify.js.map +1 -1
  55. package/dist/parser/const.js +14 -3
  56. package/dist/parser/const.js.map +1 -1
  57. package/dist/parser/lru.js +1 -1
  58. package/dist/parser/lru.js.map +1 -1
  59. package/dist/parser/parser.js +1 -2
  60. package/dist/parser/parser.js.map +1 -1
  61. package/dist/parser/tokenizer.js +1 -1
  62. package/dist/parser/tokenizer.js.map +1 -1
  63. package/dist/parser/types.js +1 -1
  64. package/dist/parser/types.js.map +1 -1
  65. package/dist/pipeline/conditions.js +1 -1
  66. package/dist/pipeline/conditions.js.map +1 -1
  67. package/dist/pipeline/exclusive.js +1 -2
  68. package/dist/pipeline/exclusive.js.map +1 -1
  69. package/dist/pipeline/index.js +2 -3
  70. package/dist/pipeline/index.js.map +1 -1
  71. package/dist/pipeline/materialize.js +1 -2
  72. package/dist/pipeline/materialize.js.map +1 -1
  73. package/dist/pipeline/parseStateKey.js +1 -2
  74. package/dist/pipeline/parseStateKey.js.map +1 -1
  75. package/dist/pipeline/simplify.js +1 -2
  76. package/dist/pipeline/simplify.js.map +1 -1
  77. package/dist/pipeline/warnings.js +1 -1
  78. package/dist/plugins/index.d.ts +2 -0
  79. package/dist/plugins/okhsl-plugin.js +1 -2
  80. package/dist/plugins/okhsl-plugin.js.map +1 -1
  81. package/dist/properties/index.js +2 -3
  82. package/dist/properties/index.js.map +1 -1
  83. package/dist/properties/property-type-resolver.js +1 -2
  84. package/dist/properties/property-type-resolver.js.map +1 -1
  85. package/dist/ssr/astro.js +1 -2
  86. package/dist/ssr/astro.js.map +1 -1
  87. package/dist/ssr/async-storage.js +1 -2
  88. package/dist/ssr/async-storage.js.map +1 -1
  89. package/dist/ssr/collect-auto-properties.js +1 -2
  90. package/dist/ssr/collect-auto-properties.js.map +1 -1
  91. package/dist/ssr/collector.js +4 -12
  92. package/dist/ssr/collector.js.map +1 -1
  93. package/dist/ssr/context.d.ts +2 -2
  94. package/dist/ssr/context.js +1 -2
  95. package/dist/ssr/context.js.map +1 -1
  96. package/dist/ssr/format-global-rules.js +1 -1
  97. package/dist/ssr/format-keyframes.js +1 -2
  98. package/dist/ssr/format-keyframes.js.map +1 -1
  99. package/dist/ssr/format-property.js +1 -2
  100. package/dist/ssr/format-property.js.map +1 -1
  101. package/dist/ssr/format-rules.js +1 -1
  102. package/dist/ssr/hydrate.js +1 -2
  103. package/dist/ssr/hydrate.js.map +1 -1
  104. package/dist/ssr/index.js +1 -2
  105. package/dist/ssr/index.js.map +1 -1
  106. package/dist/ssr/next.d.ts +2 -2
  107. package/dist/ssr/next.js +9 -5
  108. package/dist/ssr/next.js.map +1 -1
  109. package/dist/ssr/ssr-collector-ref.js +1 -1
  110. package/dist/states/index.js +1 -2
  111. package/dist/states/index.js.map +1 -1
  112. package/dist/static/index.js +1 -2
  113. package/dist/static/inject.d.ts +5 -0
  114. package/dist/static/inject.js +17 -0
  115. package/dist/static/inject.js.map +1 -0
  116. package/dist/static/tastyStatic.js +1 -2
  117. package/dist/static/tastyStatic.js.map +1 -1
  118. package/dist/static/types.js +1 -1
  119. package/dist/styles/border.d.ts +1 -1
  120. package/dist/styles/border.js +28 -22
  121. package/dist/styles/border.js.map +1 -1
  122. package/dist/styles/color.d.ts +1 -1
  123. package/dist/styles/color.js +2 -3
  124. package/dist/styles/color.js.map +1 -1
  125. package/dist/styles/const.js +17 -0
  126. package/dist/styles/const.js.map +1 -0
  127. package/dist/styles/createStyle.js +4 -5
  128. package/dist/styles/createStyle.js.map +1 -1
  129. package/dist/styles/dimension.js +15 -3
  130. package/dist/styles/dimension.js.map +1 -1
  131. package/dist/styles/directional.js +133 -0
  132. package/dist/styles/directional.js.map +1 -0
  133. package/dist/styles/display.d.ts +3 -10
  134. package/dist/styles/display.js +45 -39
  135. package/dist/styles/display.js.map +1 -1
  136. package/dist/styles/fade.d.ts +1 -1
  137. package/dist/styles/fade.js +9 -5
  138. package/dist/styles/fade.js.map +1 -1
  139. package/dist/styles/fill.d.ts +2 -2
  140. package/dist/styles/fill.js +3 -4
  141. package/dist/styles/fill.js.map +1 -1
  142. package/dist/styles/flow.js +1 -1
  143. package/dist/styles/gap.d.ts +1 -1
  144. package/dist/styles/gap.js +4 -3
  145. package/dist/styles/gap.js.map +1 -1
  146. package/dist/styles/height.d.ts +1 -1
  147. package/dist/styles/height.js +1 -2
  148. package/dist/styles/height.js.map +1 -1
  149. package/dist/styles/index.d.ts +0 -1
  150. package/dist/styles/index.js +3 -4
  151. package/dist/styles/index.js.map +1 -1
  152. package/dist/styles/inset.d.ts +1 -29
  153. package/dist/styles/inset.js +19 -135
  154. package/dist/styles/inset.js.map +1 -1
  155. package/dist/styles/list.d.ts +5 -5
  156. package/dist/styles/list.js +4 -2
  157. package/dist/styles/list.js.map +1 -1
  158. package/dist/styles/margin.d.ts +1 -1
  159. package/dist/styles/margin.js +17 -89
  160. package/dist/styles/margin.js.map +1 -1
  161. package/dist/styles/outline.d.ts +1 -1
  162. package/dist/styles/outline.js +6 -16
  163. package/dist/styles/outline.js.map +1 -1
  164. package/dist/styles/padding.d.ts +1 -1
  165. package/dist/styles/padding.js +17 -89
  166. package/dist/styles/padding.js.map +1 -1
  167. package/dist/styles/placement.d.ts +37 -0
  168. package/dist/styles/placement.js +74 -0
  169. package/dist/styles/placement.js.map +1 -0
  170. package/dist/styles/predefined.d.ts +4 -4
  171. package/dist/styles/predefined.js +8 -9
  172. package/dist/styles/predefined.js.map +1 -1
  173. package/dist/styles/preset.d.ts +1 -1
  174. package/dist/styles/preset.js +7 -7
  175. package/dist/styles/preset.js.map +1 -1
  176. package/dist/styles/radius.d.ts +1 -3
  177. package/dist/styles/radius.js +38 -6
  178. package/dist/styles/radius.js.map +1 -1
  179. package/dist/styles/scrollMargin.d.ts +24 -0
  180. package/dist/styles/scrollMargin.js +32 -0
  181. package/dist/styles/scrollMargin.js.map +1 -0
  182. package/dist/styles/scrollbar.d.ts +1 -1
  183. package/dist/styles/scrollbar.js +8 -5
  184. package/dist/styles/scrollbar.js.map +1 -1
  185. package/dist/styles/shadow.d.ts +1 -1
  186. package/dist/styles/shadow.js +4 -3
  187. package/dist/styles/shadow.js.map +1 -1
  188. package/dist/styles/shared.js +17 -0
  189. package/dist/styles/shared.js.map +1 -0
  190. package/dist/styles/transition.d.ts +1 -1
  191. package/dist/styles/transition.js +5 -4
  192. package/dist/styles/transition.js.map +1 -1
  193. package/dist/styles/types.d.ts +24 -7
  194. package/dist/styles/width.d.ts +1 -1
  195. package/dist/styles/width.js +1 -2
  196. package/dist/styles/width.js.map +1 -1
  197. package/dist/tasty.d.ts +29 -14
  198. package/dist/tasty.js +70 -62
  199. package/dist/tasty.js.map +1 -1
  200. package/dist/utils/cache-wrapper.js +1 -2
  201. package/dist/utils/cache-wrapper.js.map +1 -1
  202. package/dist/utils/case-converter.js +1 -1
  203. package/dist/utils/color-math.js +1 -1
  204. package/dist/utils/color-math.js.map +1 -1
  205. package/dist/utils/color-space.js +1 -2
  206. package/dist/utils/color-space.js.map +1 -1
  207. package/dist/utils/colors.js +1 -2
  208. package/dist/utils/colors.js.map +1 -1
  209. package/dist/utils/dotize.js +1 -1
  210. package/dist/utils/dotize.js.map +1 -1
  211. package/dist/utils/filter-base-props.js +1 -1
  212. package/dist/utils/get-display-name.js +1 -1
  213. package/dist/utils/has-keys.js +1 -1
  214. package/dist/utils/is-dev-env.js +1 -1
  215. package/dist/utils/is-dev-env.js.map +1 -1
  216. package/dist/utils/is-valid-element-type.js +1 -1
  217. package/dist/utils/merge-styles.js +1 -2
  218. package/dist/utils/merge-styles.js.map +1 -1
  219. package/dist/utils/mod-attrs.d.ts +0 -2
  220. package/dist/utils/mod-attrs.js +1 -2
  221. package/dist/utils/mod-attrs.js.map +1 -1
  222. package/dist/utils/process-tokens.d.ts +1 -5
  223. package/dist/utils/process-tokens.js +3 -11
  224. package/dist/utils/process-tokens.js.map +1 -1
  225. package/dist/utils/resolve-recipes.js +1 -2
  226. package/dist/utils/resolve-recipes.js.map +1 -1
  227. package/dist/utils/selector-transform.js +1 -1
  228. package/dist/utils/string.js +1 -1
  229. package/dist/utils/styles.d.ts +1 -1
  230. package/dist/utils/styles.js +2 -3
  231. package/dist/utils/styles.js.map +1 -1
  232. package/dist/utils/typography.js +1 -1
  233. package/dist/utils/typography.js.map +1 -1
  234. package/dist/utils/warnings.js +1 -1
  235. package/dist/zero/babel.d.ts +17 -2
  236. package/dist/zero/babel.js +105 -41
  237. package/dist/zero/babel.js.map +1 -1
  238. package/dist/zero/css-writer.js +1 -2
  239. package/dist/zero/css-writer.js.map +1 -1
  240. package/dist/zero/extractor.js +1 -2
  241. package/dist/zero/extractor.js.map +1 -1
  242. package/dist/zero/index.js +1 -2
  243. package/dist/zero/next.d.ts +12 -0
  244. package/dist/zero/next.js +5 -4
  245. package/dist/zero/next.js.map +1 -1
  246. package/docs/methodology.md +50 -1
  247. package/docs/runtime.md +90 -3
  248. package/docs/ssr.md +10 -10
  249. package/docs/styles.md +17 -0
  250. package/docs/tasty-static.md +87 -0
  251. package/package.json +12 -7
  252. package/dist/styles/align.d.ts +0 -15
  253. package/dist/styles/align.js +0 -14
  254. package/dist/styles/align.js.map +0 -1
  255. package/dist/styles/justify.d.ts +0 -15
  256. package/dist/styles/justify.js +0 -14
  257. package/dist/styles/justify.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"classify.js","names":[],"sources":["../../src/parser/classify.ts"],"sourcesContent":["import { getColorSpaceFunc, getColorSpaceSuffix } from '../utils/color-space';\nimport { getGlobalPredefinedTokens } from '../utils/styles';\n\nimport {\n COLOR_FUNCS,\n RE_HEX,\n RE_NUMBER,\n RE_RAW_UNIT,\n RE_UNIT_NUM,\n VALUE_KEYWORDS,\n canonicalFuncName,\n} from './const';\nimport { StyleParser } from './parser';\nimport type { ParserOptions, ProcessedStyle } from './types';\nimport { Bucket } from './types';\n\n/**\n * Re-parses a value through the parser until it stabilizes (no changes)\n * or max iterations reached. This allows units to reference other units.\n * Example: { x: '8px', y: '2x' } -> '1y' resolves to '16px'\n */\nfunction resolveUntilStable(\n value: string,\n opts: ParserOptions,\n recurse: (str: string) => ProcessedStyle,\n maxIterations = 10,\n): string {\n let current = value;\n for (let i = 0; i < maxIterations; i++) {\n // Check if the current value contains a custom unit that needs resolution\n const unitMatch = current.match(RE_UNIT_NUM);\n if (!unitMatch) break; // Not a unit number, no resolution needed\n\n const unitName = unitMatch[1];\n // Only recurse if the unit is a custom unit we know about\n // Any unit not in opts.units is assumed to be a native CSS unit\n if (!opts.units || !(unitName in opts.units)) break;\n\n const result = recurse(current);\n if (result.output === current) break; // Stable\n current = result.output;\n }\n return current;\n}\n\nexport function classify(\n raw: string,\n opts: ParserOptions,\n recurse: (str: string) => ProcessedStyle,\n): { bucket: Bucket; processed: string } {\n const token = raw.trim();\n if (!token) return { bucket: Bucket.Mod, processed: '' };\n\n // Early-out: if the token contains unmatched parentheses treat it as invalid\n // and skip it. This avoids cases like `drop-shadow(` that are missing a\n // closing parenthesis (e.g., a user-typo in CSS). We count paren depth while\n // ignoring everything inside string literals to avoid false positives.\n {\n let depth = 0;\n let inQuote: string | 0 = 0;\n for (let i = 0; i < token.length; i++) {\n const ch = token[i];\n\n // track quote context so parentheses inside quotes are ignored\n if (inQuote) {\n if (ch === inQuote && token[i - 1] !== '\\\\') inQuote = 0;\n continue;\n }\n if (ch === '\"' || ch === \"'\") {\n inQuote = ch;\n continue;\n }\n\n if (ch === '(') depth++;\n else if (ch === ')') depth = Math.max(0, depth - 1);\n }\n\n if (depth !== 0) {\n // Unbalanced parens → treat as invalid token (skipped).\n console.warn(\n 'tasty: skipped invalid function token with unmatched parentheses:',\n token,\n );\n return { bucket: Bucket.Mod, processed: '' };\n }\n }\n\n // Quoted string literals should be treated as value tokens (e.g., \"\" for content)\n if (\n (token.startsWith('\"') && token.endsWith('\"')) ||\n (token.startsWith(\"'\") && token.endsWith(\"'\"))\n ) {\n return { bucket: Bucket.Value, processed: token };\n }\n\n // 0. Double prefix for literal CSS property names ($$name -> --name, ##name -> --name-color)\n // Used in transitions and animations to reference the property name itself, not its value\n if (token.startsWith('$$')) {\n const name = token.slice(2);\n if (/^[a-z_][a-z0-9-_]*$/i.test(name)) {\n return { bucket: Bucket.Value, processed: `--${name}` };\n }\n }\n if (token.startsWith('##')) {\n const name = token.slice(2);\n if (/^[a-z_][a-z0-9-_]*$/i.test(name)) {\n return { bucket: Bucket.Value, processed: `--${name}-color` };\n }\n }\n\n // 0b. Special handling for #current (reserved keyword, cannot be overridden by predefined tokens)\n // #current maps to CSS currentcolor keyword\n if (token === '#current') {\n return { bucket: Bucket.Color, processed: 'currentcolor' };\n }\n\n // #current with opacity: #current.5 or #current.$opacity\n // Uses color-mix since currentcolor doesn't support rgb() alpha syntax\n const currentAlphaMatch = token.match(\n /^#current\\.(\\$[a-z_][a-z0-9-_]*|[0-9]+)$/i,\n );\n if (currentAlphaMatch) {\n const rawAlpha = currentAlphaMatch[1];\n let percentage: string;\n if (rawAlpha.startsWith('$')) {\n // Custom property: $disabled -> calc(var(--disabled) * 100%)\n const propName = rawAlpha.slice(1);\n percentage = `calc(var(--${propName}) * 100%)`;\n } else if (rawAlpha === '0') {\n percentage = '0%';\n } else {\n // Convert .5 -> 50%, .05 -> 5%\n percentage = `${parseFloat('.' + rawAlpha) * 100}%`;\n }\n return {\n bucket: Bucket.Color,\n processed: `color-mix(in oklab, currentcolor ${percentage}, transparent)`,\n };\n }\n\n // 0c. Check for predefined tokens (configured via configure({ replaceTokens: {...} }))\n // Must happen before default $ and # handling to allow overriding\n if (token[0] === '$' || token[0] === '#') {\n const predefinedTokens = getGlobalPredefinedTokens();\n if (predefinedTokens) {\n // Exact match\n if (token in predefinedTokens) {\n const tokenValue = predefinedTokens[token];\n // Lowercase the token value to match parser behavior (parser lowercases input)\n return classify(tokenValue.toLowerCase(), opts, recurse);\n }\n // Check for color token with alpha suffix: #token.alpha or #token.$prop\n if (token[0] === '#') {\n const alphaMatch = token.match(\n /^(#[a-z0-9-]+)\\.(\\$[a-z_][a-z0-9-_]*|[0-9]+)$/i,\n );\n if (alphaMatch) {\n const [, baseToken, rawAlpha] = alphaMatch;\n if (baseToken in predefinedTokens) {\n const resolvedValue = predefinedTokens[baseToken];\n\n // If resolved value starts with # (color token), use standard alpha syntax\n if (resolvedValue.startsWith('#')) {\n // Lowercase to match parser behavior\n return classify(\n `${resolvedValue.toLowerCase()}.${rawAlpha}`,\n opts,\n recurse,\n );\n }\n\n // For color functions like rgb(), rgba(), hsl(), hwb(), etc., inject alpha\n // Includes all standard CSS color functions plus okhsl (plugin)\n const funcMatch = resolvedValue.match(\n /^(rgba?|hsla?|hwb|oklab|oklch|lab|lch|color|okhsl|device-cmyk|gray|color-mix|color-contrast)\\((.+)\\)$/i,\n );\n if (funcMatch) {\n const [, funcName, args] = funcMatch;\n // Handle $prop syntax for custom property alpha\n let alpha: string;\n if (rawAlpha.startsWith('$')) {\n const propName = rawAlpha.slice(1);\n alpha = `var(--${propName})`;\n } else {\n alpha = rawAlpha === '0' ? '0' : `.${rawAlpha}`;\n }\n // Normalize function name: rgba->rgb, hsla->hsl (modern syntax doesn't need 'a' suffix)\n const normalizedFunc = funcName.replace(/a$/i, '').toLowerCase();\n // Normalize to modern syntax: replace top-level commas with spaces\n // Preserves commas inside nested functions like min(), max(), clamp()\n const normalizeArgs = (a: string) => {\n let result = '';\n let depth = 0;\n for (let i = 0; i < a.length; i++) {\n const c = a[i];\n if (c === '(') {\n depth++;\n result += c;\n } else if (c === ')') {\n depth = Math.max(0, depth - 1);\n result += c;\n } else if (c === ',' && depth === 0) {\n // Skip comma and any following whitespace at top level\n while (i + 1 < a.length && /\\s/.test(a[i + 1])) i++;\n result += ' ';\n } else {\n result += c;\n }\n }\n return result;\n };\n // Helper: find last top-level occurrence of a character (ignores parentheses)\n const findLastTopLevel = (str: string, ch: string) => {\n let depth = 0;\n for (let i = str.length - 1; i >= 0; i--) {\n const c = str[i];\n if (c === ')') depth++;\n else if (c === '(') depth = Math.max(0, depth - 1);\n else if (c === ch && depth === 0) return i;\n }\n return -1;\n };\n\n // Check if already has alpha:\n // - Modern syntax: has `/` separator at top level (works with dynamic alpha like var()/calc())\n // - Legacy syntax: function ends with 'a' (rgba, hsla) and has exactly 4 top-level comma-separated values\n const slashIdx = findLastTopLevel(args, '/');\n const hasModernAlpha = slashIdx !== -1;\n\n // Count top-level commas to avoid commas inside nested functions\n let topLevelCommaCount = 0;\n let lastTopLevelComma = -1;\n {\n let depth = 0;\n for (let i = 0; i < args.length; i++) {\n const c = args[i];\n if (c === '(') depth++;\n else if (c === ')') depth = Math.max(0, depth - 1);\n else if (c === ',' && depth === 0) {\n topLevelCommaCount++;\n lastTopLevelComma = i;\n }\n }\n }\n\n const hasLegacyAlpha =\n !hasModernAlpha &&\n /a$/i.test(funcName) &&\n topLevelCommaCount === 3;\n\n const colorArgs =\n hasModernAlpha || hasLegacyAlpha\n ? normalizeArgs(\n hasModernAlpha\n ? args.slice(0, slashIdx).trim()\n : args.slice(0, lastTopLevelComma).trim(),\n )\n : normalizeArgs(args);\n\n const constructed = `${normalizedFunc}(${colorArgs} / ${alpha})`;\n\n // Custom functions (not native CSS) must be re-classified\n // so the function handler can convert them to valid CSS\n if (\n !COLOR_FUNCS.has(normalizedFunc) &&\n opts.funcs &&\n normalizedFunc in opts.funcs\n ) {\n return classify(constructed, opts, recurse);\n }\n\n return { bucket: Bucket.Color, processed: constructed };\n }\n\n // Fallback: try appending .alpha (may not work for all cases)\n return classify(`${resolvedValue}.${rawAlpha}`, opts, recurse);\n }\n }\n }\n }\n }\n\n // 0. Direct var(--*-color) token\n const varColorMatch = token.match(/^var\\(--([a-z0-9-]+)-color\\)$/);\n if (varColorMatch) {\n return { bucket: Bucket.Color, processed: token };\n }\n\n // 1. URL\n if (token.startsWith('url(')) {\n return { bucket: Bucket.Value, processed: token };\n }\n\n // 2. Custom property\n if (token[0] === '$') {\n const identMatch = token.match(/^\\$([a-z_][a-z0-9-_]*)$/);\n if (identMatch) {\n const name = identMatch[1];\n const processed = `var(--${name})`;\n const bucketType = name.endsWith('-color') ? Bucket.Color : Bucket.Value;\n return {\n bucket: bucketType,\n processed,\n };\n }\n // invalid custom property → modifier\n }\n\n // 3. Hash colors (with optional alpha suffix e.g., #purple.5 or #purple.$disabled)\n if (token[0] === '#' && token.length > 1) {\n // alpha form: #name.alpha or #name.$prop\n const alphaMatch = token.match(\n /^#([a-z0-9-]+)\\.(\\$[a-z_][a-z0-9-_]*|[0-9]+)$/i,\n );\n if (alphaMatch) {\n const [, base, rawAlpha] = alphaMatch;\n let alpha: string;\n if (rawAlpha.startsWith('$')) {\n // Custom property: $disabled -> var(--disabled)\n const propName = rawAlpha.slice(1);\n alpha = `var(--${propName})`;\n } else if (rawAlpha === '0') {\n alpha = '0';\n } else {\n alpha = `.${rawAlpha}`;\n }\n return {\n bucket: Bucket.Color,\n processed: `${getColorSpaceFunc()}(var(--${base}-color-${getColorSpaceSuffix()}) / ${alpha})`,\n };\n }\n\n // hyphenated names like #dark-05 should keep full name\n\n const name = token.slice(1);\n // valid hex → treat as hex literal with fallback\n if (RE_HEX.test(name)) {\n return {\n bucket: Bucket.Color,\n processed: `var(--${name}-color, #${name})`,\n };\n }\n // simple color name token → css variable lookup with rgb fallback\n return { bucket: Bucket.Color, processed: `var(--${name}-color)` };\n }\n\n // 4 & 5. Functions\n const openIdx = token.indexOf('(');\n if (openIdx > 0 && token.endsWith(')')) {\n const fname = token.slice(0, openIdx);\n const inner = token.slice(openIdx + 1, -1); // without ()\n\n if (COLOR_FUNCS.has(fname)) {\n // Process inner to expand nested colors or units.\n const argProcessed = recurse(inner).output.replace(/,\\s+/g, ','); // color funcs expect no spaces after commas\n return {\n bucket: Bucket.Color,\n processed: `${canonicalFuncName(fname)}(${argProcessed})`,\n };\n }\n\n // user function (provided via opts)\n if (opts.funcs && fname in opts.funcs) {\n // split by top-level commas within inner\n const tmp = new StyleParser(opts).process(inner); // fresh parser w/ same opts but no cache share issues\n const funcResult = opts.funcs[fname](tmp.groups);\n // Re-classify the result to determine proper bucket (e.g., if it returns a color)\n // Pass funcs: undefined to prevent infinite recursion if result matches a function pattern\n return classify(funcResult, { ...opts, funcs: undefined }, recurse);\n }\n\n // generic: process inner and rebuild\n const argProcessed = recurse(inner).output;\n return {\n bucket: Bucket.Value,\n processed: `${canonicalFuncName(fname)}(${argProcessed})`,\n };\n }\n\n // 6. Color fallback syntax: (#name, fallback)\n if (token.startsWith('(') && token.endsWith(')')) {\n const inner = token.slice(1, -1);\n const colorMatch = inner.match(/^#([a-z0-9-]+)\\s*,\\s*(.*)$/i);\n if (colorMatch) {\n const [, name, fallback] = colorMatch;\n const processedFallback = recurse(fallback).output;\n return {\n bucket: Bucket.Color,\n processed: `var(--${name}-color, ${processedFallback})`,\n };\n }\n }\n\n // 7. Custom property with fallback syntax: ($prop, fallback)\n if (token.startsWith('(') && token.endsWith(')')) {\n const inner = token.slice(1, -1);\n const match = inner.match(/^\\$([a-z_][a-z0-9-_]*)\\s*,\\s*(.*)$/);\n if (match) {\n const [, name, fallback] = match;\n const processedFallback = recurse(fallback).output;\n const bucketType = name.endsWith('-color') ? Bucket.Color : Bucket.Value;\n return {\n bucket: bucketType,\n processed: `var(--${name}, ${processedFallback})`,\n };\n }\n }\n\n // 8. Auto-calc group\n if (token[0] === '(' && token[token.length - 1] === ')') {\n const inner = token.slice(1, -1);\n const innerProcessed = recurse(inner).output;\n return { bucket: Bucket.Value, processed: `calc(${innerProcessed})` };\n }\n\n // 9. Unit number\n const um = token.match(RE_UNIT_NUM);\n if (um) {\n const unit = um[1];\n const numericPart = parseFloat(token.slice(0, -unit.length));\n const handler = opts.units && opts.units[unit];\n if (handler) {\n if (typeof handler === 'string') {\n // Check if this is a raw CSS unit (e.g., \"8px\", \"1rem\")\n const rawMatch = handler.match(RE_RAW_UNIT);\n if (rawMatch) {\n // Raw unit: calculate directly instead of using calc()\n const [, baseNum, cssUnit] = rawMatch;\n const result = numericPart * parseFloat(baseNum);\n const processed = `${result}${cssUnit}`;\n // Re-parse to resolve any nested units (e.g., units referencing other units)\n const resolved = resolveUntilStable(processed, opts, recurse);\n return { bucket: Bucket.Value, processed: resolved };\n }\n\n // Non-raw handler (e.g., \"var(--gap)\", \"calc(...)\"): use calc() wrapping\n const base = handler;\n if (numericPart === 1) {\n return { bucket: Bucket.Value, processed: base };\n }\n return {\n bucket: Bucket.Value,\n processed: `calc(${numericPart} * ${base})`,\n };\n } else {\n // Function units return complete CSS expressions, no wrapping needed\n const inner = handler(numericPart);\n return {\n bucket: Bucket.Value,\n processed: inner,\n };\n }\n }\n }\n\n // 9b. Unknown numeric+unit → treat as literal value (e.g., 1fr)\n if (/^[+-]?(?:\\d*\\.\\d+|\\d+)[a-z%]+$/.test(token)) {\n return { bucket: Bucket.Value, processed: token };\n }\n\n // 9c. Plain unit-less numbers should be treated as value tokens (e.g.,\n // numeric arguments in custom style handlers).\n if (RE_NUMBER.test(token)) {\n return { bucket: Bucket.Value, processed: token };\n }\n\n // 10. Literal value keywords\n if (VALUE_KEYWORDS.has(token)) {\n return { bucket: Bucket.Value, processed: token };\n }\n\n // 10b. Special keyword colors\n if (token === 'transparent' || token === 'currentcolor') {\n return { bucket: Bucket.Color, processed: token };\n }\n\n // 11. Fallback modifier\n return { bucket: Bucket.Mod, processed: token };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"classify.js","names":[],"sources":["../../src/parser/classify.ts"],"sourcesContent":["import { getColorSpaceFunc, getColorSpaceSuffix } from '../utils/color-space';\nimport { getGlobalPredefinedTokens } from '../utils/styles';\n\nimport {\n COLOR_FUNCS,\n RE_HEX,\n RE_NUMBER,\n RE_RAW_UNIT,\n RE_UNIT_NUM,\n VALUE_KEYWORDS,\n canonicalFuncName,\n} from './const';\nimport { StyleParser } from './parser';\nimport type { ParserOptions, ProcessedStyle } from './types';\nimport { Bucket } from './types';\n\n/**\n * Re-parses a value through the parser until it stabilizes (no changes)\n * or max iterations reached. This allows units to reference other units.\n * Example: { x: '8px', y: '2x' } -> '1y' resolves to '16px'\n */\nfunction resolveUntilStable(\n value: string,\n opts: ParserOptions,\n recurse: (str: string) => ProcessedStyle,\n maxIterations = 10,\n): string {\n let current = value;\n for (let i = 0; i < maxIterations; i++) {\n // Check if the current value contains a custom unit that needs resolution\n const unitMatch = current.match(RE_UNIT_NUM);\n if (!unitMatch) break; // Not a unit number, no resolution needed\n\n const unitName = unitMatch[1];\n // Only recurse if the unit is a custom unit we know about\n // Any unit not in opts.units is assumed to be a native CSS unit\n if (!opts.units || !(unitName in opts.units)) break;\n\n const result = recurse(current);\n if (result.output === current) break; // Stable\n current = result.output;\n }\n return current;\n}\n\nexport function classify(\n raw: string,\n opts: ParserOptions,\n recurse: (str: string) => ProcessedStyle,\n): { bucket: Bucket; processed: string } {\n const token = raw.trim();\n if (!token) return { bucket: Bucket.Mod, processed: '' };\n\n // Early-out: if the token contains unmatched parentheses treat it as invalid\n // and skip it. This avoids cases like `drop-shadow(` that are missing a\n // closing parenthesis (e.g., a user-typo in CSS). We count paren depth while\n // ignoring everything inside string literals to avoid false positives.\n {\n let depth = 0;\n let inQuote: string | 0 = 0;\n for (let i = 0; i < token.length; i++) {\n const ch = token[i];\n\n // track quote context so parentheses inside quotes are ignored\n if (inQuote) {\n if (ch === inQuote && token[i - 1] !== '\\\\') inQuote = 0;\n continue;\n }\n if (ch === '\"' || ch === \"'\") {\n inQuote = ch;\n continue;\n }\n\n if (ch === '(') depth++;\n else if (ch === ')') depth = Math.max(0, depth - 1);\n }\n\n if (depth !== 0) {\n // Unbalanced parens → treat as invalid token (skipped).\n console.warn(\n 'tasty: skipped invalid function token with unmatched parentheses:',\n token,\n );\n return { bucket: Bucket.Mod, processed: '' };\n }\n }\n\n // Quoted string literals should be treated as value tokens (e.g., \"\" for content)\n if (\n (token.startsWith('\"') && token.endsWith('\"')) ||\n (token.startsWith(\"'\") && token.endsWith(\"'\"))\n ) {\n return { bucket: Bucket.Value, processed: token };\n }\n\n // 0. Double prefix for literal CSS property names ($$name -> --name, ##name -> --name-color)\n // Used in transitions and animations to reference the property name itself, not its value\n if (token.startsWith('$$')) {\n const name = token.slice(2);\n if (/^[a-z_][a-z0-9-_]*$/i.test(name)) {\n return { bucket: Bucket.Value, processed: `--${name}` };\n }\n }\n if (token.startsWith('##')) {\n const name = token.slice(2);\n if (/^[a-z_][a-z0-9-_]*$/i.test(name)) {\n return { bucket: Bucket.Value, processed: `--${name}-color` };\n }\n }\n\n // 0b. Special handling for #current (reserved keyword, cannot be overridden by predefined tokens)\n // #current maps to CSS currentcolor keyword\n if (token === '#current') {\n return { bucket: Bucket.Color, processed: 'currentcolor' };\n }\n\n // #current with opacity: #current.5 or #current.$opacity\n // Uses color-mix since currentcolor doesn't support rgb() alpha syntax\n const currentAlphaMatch = token.match(\n /^#current\\.(\\$[a-z_][a-z0-9-_]*|[0-9]+)$/i,\n );\n if (currentAlphaMatch) {\n const rawAlpha = currentAlphaMatch[1];\n let percentage: string;\n if (rawAlpha.startsWith('$')) {\n // Custom property: $disabled -> calc(var(--disabled) * 100%)\n const propName = rawAlpha.slice(1);\n percentage = `calc(var(--${propName}) * 100%)`;\n } else if (rawAlpha === '0') {\n percentage = '0%';\n } else {\n // Convert .5 -> 50%, .05 -> 5%\n percentage = `${parseFloat('.' + rawAlpha) * 100}%`;\n }\n return {\n bucket: Bucket.Color,\n processed: `color-mix(in oklab, currentcolor ${percentage}, transparent)`,\n };\n }\n\n // 0c. Check for predefined tokens (configured via configure({ replaceTokens: {...} }))\n // Must happen before default $ and # handling to allow overriding\n if (token[0] === '$' || token[0] === '#') {\n const predefinedTokens = getGlobalPredefinedTokens();\n if (predefinedTokens) {\n // Exact match\n if (token in predefinedTokens) {\n const tokenValue = predefinedTokens[token];\n // Lowercase the token value to match parser behavior (parser lowercases input)\n return classify(tokenValue.toLowerCase(), opts, recurse);\n }\n // Check for color token with alpha suffix: #token.alpha or #token.$prop\n if (token[0] === '#') {\n const alphaMatch = token.match(\n /^(#[a-z0-9-]+)\\.(\\$[a-z_][a-z0-9-_]*|[0-9]+)$/i,\n );\n if (alphaMatch) {\n const [, baseToken, rawAlpha] = alphaMatch;\n if (baseToken in predefinedTokens) {\n const resolvedValue = predefinedTokens[baseToken];\n\n // If resolved value starts with # (color token), use standard alpha syntax\n if (resolvedValue.startsWith('#')) {\n // Lowercase to match parser behavior\n return classify(\n `${resolvedValue.toLowerCase()}.${rawAlpha}`,\n opts,\n recurse,\n );\n }\n\n // For color functions like rgb(), rgba(), hsl(), hwb(), etc., inject alpha\n // Includes all standard CSS color functions plus okhsl (plugin)\n const funcMatch = resolvedValue.match(\n /^(rgba?|hsla?|hwb|oklab|oklch|lab|lch|color|okhsl|device-cmyk|gray|color-mix|color-contrast)\\((.+)\\)$/i,\n );\n if (funcMatch) {\n const [, funcName, args] = funcMatch;\n // Handle $prop syntax for custom property alpha\n let alpha: string;\n if (rawAlpha.startsWith('$')) {\n const propName = rawAlpha.slice(1);\n alpha = `var(--${propName})`;\n } else {\n alpha = rawAlpha === '0' ? '0' : `.${rawAlpha}`;\n }\n // Normalize function name: rgba->rgb, hsla->hsl (modern syntax doesn't need 'a' suffix)\n const normalizedFunc = funcName.replace(/a$/i, '').toLowerCase();\n // Normalize to modern syntax: replace top-level commas with spaces\n // Preserves commas inside nested functions like min(), max(), clamp()\n const normalizeArgs = (a: string) => {\n let result = '';\n let depth = 0;\n for (let i = 0; i < a.length; i++) {\n const c = a[i];\n if (c === '(') {\n depth++;\n result += c;\n } else if (c === ')') {\n depth = Math.max(0, depth - 1);\n result += c;\n } else if (c === ',' && depth === 0) {\n // Skip comma and any following whitespace at top level\n while (i + 1 < a.length && /\\s/.test(a[i + 1])) i++;\n result += ' ';\n } else {\n result += c;\n }\n }\n return result;\n };\n // Helper: find last top-level occurrence of a character (ignores parentheses)\n const findLastTopLevel = (str: string, ch: string) => {\n let depth = 0;\n for (let i = str.length - 1; i >= 0; i--) {\n const c = str[i];\n if (c === ')') depth++;\n else if (c === '(') depth = Math.max(0, depth - 1);\n else if (c === ch && depth === 0) return i;\n }\n return -1;\n };\n\n // Check if already has alpha:\n // - Modern syntax: has `/` separator at top level (works with dynamic alpha like var()/calc())\n // - Legacy syntax: function ends with 'a' (rgba, hsla) and has exactly 4 top-level comma-separated values\n const slashIdx = findLastTopLevel(args, '/');\n const hasModernAlpha = slashIdx !== -1;\n\n // Count top-level commas to avoid commas inside nested functions\n let topLevelCommaCount = 0;\n let lastTopLevelComma = -1;\n {\n let depth = 0;\n for (let i = 0; i < args.length; i++) {\n const c = args[i];\n if (c === '(') depth++;\n else if (c === ')') depth = Math.max(0, depth - 1);\n else if (c === ',' && depth === 0) {\n topLevelCommaCount++;\n lastTopLevelComma = i;\n }\n }\n }\n\n const hasLegacyAlpha =\n !hasModernAlpha &&\n /a$/i.test(funcName) &&\n topLevelCommaCount === 3;\n\n const colorArgs =\n hasModernAlpha || hasLegacyAlpha\n ? normalizeArgs(\n hasModernAlpha\n ? args.slice(0, slashIdx).trim()\n : args.slice(0, lastTopLevelComma).trim(),\n )\n : normalizeArgs(args);\n\n const constructed = `${normalizedFunc}(${colorArgs} / ${alpha})`;\n\n // Custom functions (not native CSS) must be re-classified\n // so the function handler can convert them to valid CSS\n if (\n !COLOR_FUNCS.has(normalizedFunc) &&\n opts.funcs &&\n normalizedFunc in opts.funcs\n ) {\n return classify(constructed, opts, recurse);\n }\n\n return { bucket: Bucket.Color, processed: constructed };\n }\n\n // Fallback: try appending .alpha (may not work for all cases)\n return classify(`${resolvedValue}.${rawAlpha}`, opts, recurse);\n }\n }\n }\n }\n }\n\n // 0. Direct var(--*-color) token\n const varColorMatch = token.match(/^var\\(--([a-z0-9-]+)-color\\)$/);\n if (varColorMatch) {\n return { bucket: Bucket.Color, processed: token };\n }\n\n // 1. URL\n if (token.startsWith('url(')) {\n return { bucket: Bucket.Value, processed: token };\n }\n\n // 2. Custom property\n if (token[0] === '$') {\n const identMatch = token.match(/^\\$([a-z_][a-z0-9-_]*)$/);\n if (identMatch) {\n const name = identMatch[1];\n const processed = `var(--${name})`;\n const bucketType = name.endsWith('-color') ? Bucket.Color : Bucket.Value;\n return {\n bucket: bucketType,\n processed,\n };\n }\n // invalid custom property → modifier\n }\n\n // 3. Hash colors (with optional alpha suffix e.g., #purple.5 or #purple.$disabled)\n if (token[0] === '#' && token.length > 1) {\n // alpha form: #name.alpha or #name.$prop\n const alphaMatch = token.match(\n /^#([a-z0-9-]+)\\.(\\$[a-z_][a-z0-9-_]*|[0-9]+)$/i,\n );\n if (alphaMatch) {\n const [, base, rawAlpha] = alphaMatch;\n let alpha: string;\n if (rawAlpha.startsWith('$')) {\n // Custom property: $disabled -> var(--disabled)\n const propName = rawAlpha.slice(1);\n alpha = `var(--${propName})`;\n } else if (rawAlpha === '0') {\n alpha = '0';\n } else {\n alpha = `.${rawAlpha}`;\n }\n return {\n bucket: Bucket.Color,\n processed: `${getColorSpaceFunc()}(var(--${base}-color-${getColorSpaceSuffix()}) / ${alpha})`,\n };\n }\n\n // hyphenated names like #dark-05 should keep full name\n\n const name = token.slice(1);\n // valid hex → treat as hex literal with fallback\n if (RE_HEX.test(name)) {\n return {\n bucket: Bucket.Color,\n processed: `var(--${name}-color, #${name})`,\n };\n }\n // simple color name token → css variable lookup with rgb fallback\n return { bucket: Bucket.Color, processed: `var(--${name}-color)` };\n }\n\n // 4 & 5. Functions\n const openIdx = token.indexOf('(');\n if (openIdx > 0 && token.endsWith(')')) {\n const fname = token.slice(0, openIdx);\n const inner = token.slice(openIdx + 1, -1); // without ()\n\n if (COLOR_FUNCS.has(fname)) {\n // Process inner to expand nested colors or units.\n const argProcessed = recurse(inner).output.replace(/,\\s+/g, ','); // color funcs expect no spaces after commas\n return {\n bucket: Bucket.Color,\n processed: `${canonicalFuncName(fname)}(${argProcessed})`,\n };\n }\n\n // user function (provided via opts)\n if (opts.funcs && fname in opts.funcs) {\n // split by top-level commas within inner\n const tmp = new StyleParser(opts).process(inner); // fresh parser w/ same opts but no cache share issues\n const funcResult = opts.funcs[fname](tmp.groups);\n // Re-classify the result to determine proper bucket (e.g., if it returns a color)\n // Pass funcs: undefined to prevent infinite recursion if result matches a function pattern\n return classify(funcResult, { ...opts, funcs: undefined }, recurse);\n }\n\n // generic: process inner and rebuild\n const argProcessed = recurse(inner).output;\n return {\n bucket: Bucket.Value,\n processed: `${canonicalFuncName(fname)}(${argProcessed})`,\n };\n }\n\n // 6. Color fallback syntax: (#name, fallback)\n if (token.startsWith('(') && token.endsWith(')')) {\n const inner = token.slice(1, -1);\n const colorMatch = inner.match(/^#([a-z0-9-]+)\\s*,\\s*(.*)$/i);\n if (colorMatch) {\n const [, name, fallback] = colorMatch;\n const processedFallback = recurse(fallback).output;\n return {\n bucket: Bucket.Color,\n processed: `var(--${name}-color, ${processedFallback})`,\n };\n }\n }\n\n // 7. Custom property with fallback syntax: ($prop, fallback)\n if (token.startsWith('(') && token.endsWith(')')) {\n const inner = token.slice(1, -1);\n const match = inner.match(/^\\$([a-z_][a-z0-9-_]*)\\s*,\\s*(.*)$/);\n if (match) {\n const [, name, fallback] = match;\n const processedFallback = recurse(fallback).output;\n const bucketType = name.endsWith('-color') ? Bucket.Color : Bucket.Value;\n return {\n bucket: bucketType,\n processed: `var(--${name}, ${processedFallback})`,\n };\n }\n }\n\n // 8. Auto-calc group\n if (token[0] === '(' && token[token.length - 1] === ')') {\n const inner = token.slice(1, -1);\n const innerProcessed = recurse(inner).output;\n return { bucket: Bucket.Value, processed: `calc(${innerProcessed})` };\n }\n\n // 9. Unit number\n const um = token.match(RE_UNIT_NUM);\n if (um) {\n const unit = um[1];\n const numericPart = parseFloat(token.slice(0, -unit.length));\n const handler = opts.units && opts.units[unit];\n if (handler) {\n if (typeof handler === 'string') {\n // Check if this is a raw CSS unit (e.g., \"8px\", \"1rem\")\n const rawMatch = handler.match(RE_RAW_UNIT);\n if (rawMatch) {\n // Raw unit: calculate directly instead of using calc()\n const [, baseNum, cssUnit] = rawMatch;\n const result = numericPart * parseFloat(baseNum);\n const processed = `${result}${cssUnit}`;\n // Re-parse to resolve any nested units (e.g., units referencing other units)\n const resolved = resolveUntilStable(processed, opts, recurse);\n return { bucket: Bucket.Value, processed: resolved };\n }\n\n // Non-raw handler (e.g., \"var(--gap)\", \"calc(...)\"): use calc() wrapping\n const base = handler;\n if (numericPart === 1) {\n return { bucket: Bucket.Value, processed: base };\n }\n return {\n bucket: Bucket.Value,\n processed: `calc(${numericPart} * ${base})`,\n };\n } else {\n // Function units return complete CSS expressions, no wrapping needed\n const inner = handler(numericPart);\n return {\n bucket: Bucket.Value,\n processed: inner,\n };\n }\n }\n }\n\n // 9b. Unknown numeric+unit → treat as literal value (e.g., 1fr)\n if (/^[+-]?(?:\\d*\\.\\d+|\\d+)[a-z%]+$/.test(token)) {\n return { bucket: Bucket.Value, processed: token };\n }\n\n // 9c. Plain unit-less numbers should be treated as value tokens (e.g.,\n // numeric arguments in custom style handlers).\n if (RE_NUMBER.test(token)) {\n return { bucket: Bucket.Value, processed: token };\n }\n\n // 10. Literal value keywords\n if (VALUE_KEYWORDS.has(token)) {\n return { bucket: Bucket.Value, processed: token };\n }\n\n // 10b. Special keyword colors\n if (token === 'transparent' || token === 'currentcolor') {\n return { bucket: Bucket.Color, processed: token };\n }\n\n // 11. Fallback modifier\n return { bucket: Bucket.Mod, processed: token };\n}\n"],"mappings":"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"}
@@ -5,7 +5,18 @@ const VALUE_KEYWORDS = new Set([
5
5
  "min-content",
6
6
  "fit-content",
7
7
  "stretch",
8
- "initial"
8
+ "initial",
9
+ "inherit",
10
+ "revert",
11
+ "unset",
12
+ "revert-layer"
13
+ ]);
14
+ const CSS_WIDE_KEYWORDS = new Set([
15
+ "initial",
16
+ "inherit",
17
+ "revert",
18
+ "unset",
19
+ "revert-layer"
9
20
  ]);
10
21
  const COLOR_FUNCS = new Set([
11
22
  "rgb",
@@ -43,7 +54,7 @@ const CANONICAL_FUNC_CASE = new Map([
43
54
  function canonicalFuncName(lowered) {
44
55
  return CANONICAL_FUNC_CASE.get(lowered) ?? lowered;
45
56
  }
46
-
47
57
  //#endregion
48
- export { COLOR_FUNCS, RE_HEX, RE_NUMBER, RE_RAW_UNIT, RE_UNIT_NUM, VALUE_KEYWORDS, canonicalFuncName };
58
+ export { COLOR_FUNCS, CSS_WIDE_KEYWORDS, RE_HEX, RE_NUMBER, RE_RAW_UNIT, RE_UNIT_NUM, VALUE_KEYWORDS, canonicalFuncName };
59
+
49
60
  //# sourceMappingURL=const.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"const.js","names":[],"sources":["../../src/parser/const.ts"],"sourcesContent":["export const VALUE_KEYWORDS = new Set([\n 'auto',\n 'max-content',\n 'min-content',\n 'fit-content',\n 'stretch',\n 'initial',\n]);\n\nexport const COLOR_FUNCS = new Set([\n 'rgb',\n 'rgba',\n 'hsl',\n 'hsla',\n 'hwb',\n 'lab',\n 'lch',\n 'oklab',\n 'oklch',\n 'color',\n 'device-cmyk',\n 'gray',\n 'color-mix',\n 'color-contrast',\n]);\n\nexport const RE_UNIT_NUM = /^[+-]?(?:\\d*\\.\\d+|\\d+)([a-z][a-z0-9]*)$/;\nexport const RE_NUMBER = /^[+-]?(?:\\d*\\.\\d+|\\d+)$/;\nexport const RE_HEX = /^(?:[0-9a-f]{3,4}|[0-9a-f]{6}(?:[0-9a-f]{2})?)$/;\n// Matches raw CSS unit values like \"8px\", \"1rem\", \"0.5em\" - captures number and unit separately\nexport const RE_RAW_UNIT = /^([+-]?(?:\\d*\\.\\d+|\\d+))([a-z%]+)$/;\n\nconst CANONICAL_FUNC_CASE = new Map([\n ['translatex', 'translateX'],\n ['translatey', 'translateY'],\n ['translatez', 'translateZ'],\n ['scalex', 'scaleX'],\n ['scaley', 'scaleY'],\n ['scalez', 'scaleZ'],\n ['rotatex', 'rotateX'],\n ['rotatey', 'rotateY'],\n ['rotatez', 'rotateZ'],\n ['skewx', 'skewX'],\n ['skewy', 'skewY'],\n]);\n\nexport function canonicalFuncName(lowered: string): string {\n return CANONICAL_FUNC_CASE.get(lowered) ?? lowered;\n}\n"],"mappings":";AAAA,MAAa,iBAAiB,IAAI,IAAI;CACpC;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,MAAa,cAAc,IAAI,IAAI;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,MAAa,cAAc;AAC3B,MAAa,YAAY;AACzB,MAAa,SAAS;AAEtB,MAAa,cAAc;AAE3B,MAAM,sBAAsB,IAAI,IAAI;CAClC,CAAC,cAAc,aAAa;CAC5B,CAAC,cAAc,aAAa;CAC5B,CAAC,cAAc,aAAa;CAC5B,CAAC,UAAU,SAAS;CACpB,CAAC,UAAU,SAAS;CACpB,CAAC,UAAU,SAAS;CACpB,CAAC,WAAW,UAAU;CACtB,CAAC,WAAW,UAAU;CACtB,CAAC,WAAW,UAAU;CACtB,CAAC,SAAS,QAAQ;CAClB,CAAC,SAAS,QAAQ;CACnB,CAAC;AAEF,SAAgB,kBAAkB,SAAyB;AACzD,QAAO,oBAAoB,IAAI,QAAQ,IAAI"}
1
+ {"version":3,"file":"const.js","names":[],"sources":["../../src/parser/const.ts"],"sourcesContent":["export const VALUE_KEYWORDS = new Set([\n 'auto',\n 'max-content',\n 'min-content',\n 'fit-content',\n 'stretch',\n 'initial',\n 'inherit',\n 'revert',\n 'unset',\n 'revert-layer',\n]);\n\nexport const CSS_WIDE_KEYWORDS = new Set([\n 'initial',\n 'inherit',\n 'revert',\n 'unset',\n 'revert-layer',\n]);\n\nexport const COLOR_FUNCS = new Set([\n 'rgb',\n 'rgba',\n 'hsl',\n 'hsla',\n 'hwb',\n 'lab',\n 'lch',\n 'oklab',\n 'oklch',\n 'color',\n 'device-cmyk',\n 'gray',\n 'color-mix',\n 'color-contrast',\n]);\n\nexport const RE_UNIT_NUM = /^[+-]?(?:\\d*\\.\\d+|\\d+)([a-z][a-z0-9]*)$/;\nexport const RE_NUMBER = /^[+-]?(?:\\d*\\.\\d+|\\d+)$/;\nexport const RE_HEX = /^(?:[0-9a-f]{3,4}|[0-9a-f]{6}(?:[0-9a-f]{2})?)$/;\n// Matches raw CSS unit values like \"8px\", \"1rem\", \"0.5em\" - captures number and unit separately\nexport const RE_RAW_UNIT = /^([+-]?(?:\\d*\\.\\d+|\\d+))([a-z%]+)$/;\n\nconst CANONICAL_FUNC_CASE = new Map([\n ['translatex', 'translateX'],\n ['translatey', 'translateY'],\n ['translatez', 'translateZ'],\n ['scalex', 'scaleX'],\n ['scaley', 'scaleY'],\n ['scalez', 'scaleZ'],\n ['rotatex', 'rotateX'],\n ['rotatey', 'rotateY'],\n ['rotatez', 'rotateZ'],\n ['skewx', 'skewX'],\n ['skewy', 'skewY'],\n]);\n\nexport function canonicalFuncName(lowered: string): string {\n return CANONICAL_FUNC_CASE.get(lowered) ?? lowered;\n}\n"],"mappings":";AAAA,MAAa,iBAAiB,IAAI,IAAI;CACpC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,MAAa,oBAAoB,IAAI,IAAI;CACvC;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,MAAa,cAAc,IAAI,IAAI;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,MAAa,cAAc;AAC3B,MAAa,YAAY;AACzB,MAAa,SAAS;AAEtB,MAAa,cAAc;AAE3B,MAAM,sBAAsB,IAAI,IAAI;CAClC,CAAC,cAAc,aAAa;CAC5B,CAAC,cAAc,aAAa;CAC5B,CAAC,cAAc,aAAa;CAC5B,CAAC,UAAU,SAAS;CACpB,CAAC,UAAU,SAAS;CACpB,CAAC,UAAU,SAAS;CACpB,CAAC,WAAW,UAAU;CACtB,CAAC,WAAW,UAAU;CACtB,CAAC,WAAW,UAAU;CACtB,CAAC,SAAS,QAAQ;CAClB,CAAC,SAAS,QAAQ;CACnB,CAAC;AAEF,SAAgB,kBAAkB,SAAyB;AACzD,QAAO,oBAAoB,IAAI,QAAQ,IAAI"}
@@ -103,7 +103,7 @@ var Lru = class {
103
103
  this.head = this.tail = null;
104
104
  }
105
105
  };
106
-
107
106
  //#endregion
108
107
  export { Lru };
108
+
109
109
  //# sourceMappingURL=lru.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"lru.js","names":[],"sources":["../../src/parser/lru.ts"],"sourcesContent":["export class Lru<K, V> {\n private map = new Map<K, { prev: K | null; next: K | null; value: V }>();\n private head: K | null = null;\n private tail: K | null = null;\n private onEvict?: (key: K, value: V) => void;\n\n constructor(\n private limit = 1000,\n onEvict?: (key: K, value: V) => void,\n ) {\n // Normalize limit; fall back to sensible default (1000) to keep caching enabled\n let normalized = Number.isFinite(this.limit)\n ? Math.floor(this.limit)\n : 1000;\n if (normalized <= 0) normalized = 1000;\n this.limit = normalized;\n this.onEvict = onEvict;\n }\n\n setOnEvict(fn?: (key: K, value: V) => void) {\n this.onEvict = fn;\n }\n\n get(key: K): V | undefined {\n const node = this.map.get(key);\n if (!node) return undefined;\n this.touch(key, node);\n return node.value;\n }\n\n set(key: K, value: V) {\n let node = this.map.get(key);\n if (node) {\n node.value = value;\n this.touch(key, node);\n return;\n }\n node = { prev: null, next: this.head, value };\n if (this.head) {\n const headNode = this.map.get(this.head);\n if (headNode) headNode.prev = key;\n }\n this.head = key;\n if (!this.tail) this.tail = key;\n this.map.set(key, node);\n if (this.map.size > this.limit) this.evict();\n }\n\n delete(key: K) {\n const node = this.map.get(key);\n if (!node) return;\n if (node.prev) {\n const prevNode = this.map.get(node.prev);\n if (prevNode) prevNode.next = node.next;\n }\n if (node.next) {\n const nextNode = this.map.get(node.next);\n if (nextNode) nextNode.prev = node.prev;\n }\n if (this.head === key) this.head = node.next;\n if (this.tail === key) this.tail = node.prev;\n this.map.delete(key);\n }\n\n keys(): IterableIterator<K> {\n return this.map.keys();\n }\n\n private touch(key: K, node: { prev: K | null; next: K | null; value: V }) {\n if (this.head === key) return; // already MRU\n\n // detach\n if (node.prev) {\n const prevNode = this.map.get(node.prev);\n if (prevNode) prevNode.next = node.next;\n }\n if (node.next) {\n const nextNode = this.map.get(node.next);\n if (nextNode) nextNode.prev = node.prev;\n }\n if (this.tail === key) this.tail = node.prev;\n\n // move to head\n node.prev = null;\n node.next = this.head;\n if (this.head) {\n const headNode = this.map.get(this.head);\n if (headNode) headNode.prev = key;\n }\n this.head = key;\n }\n\n private evict() {\n const old = this.tail;\n if (!old) return;\n const node = this.map.get(old);\n if (!node) {\n // Tail pointer is stale; reset pointers conservatively\n if (this.head === old) this.head = null;\n this.tail = null;\n return;\n }\n if (node.prev) {\n const prevNode = this.map.get(node.prev);\n if (prevNode) prevNode.next = null;\n }\n this.tail = node.prev;\n if (this.head === old) this.head = null;\n this.map.delete(old);\n\n if (this.onEvict) {\n try {\n this.onEvict(old, node.value);\n } catch {\n // ignore user callback errors\n }\n }\n }\n\n clear() {\n this.map.clear();\n this.head = this.tail = null;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"lru.js","names":[],"sources":["../../src/parser/lru.ts"],"sourcesContent":["export class Lru<K, V> {\n private map = new Map<K, { prev: K | null; next: K | null; value: V }>();\n private head: K | null = null;\n private tail: K | null = null;\n private onEvict?: (key: K, value: V) => void;\n\n constructor(\n private limit = 1000,\n onEvict?: (key: K, value: V) => void,\n ) {\n // Normalize limit; fall back to sensible default (1000) to keep caching enabled\n let normalized = Number.isFinite(this.limit)\n ? Math.floor(this.limit)\n : 1000;\n if (normalized <= 0) normalized = 1000;\n this.limit = normalized;\n this.onEvict = onEvict;\n }\n\n setOnEvict(fn?: (key: K, value: V) => void) {\n this.onEvict = fn;\n }\n\n get(key: K): V | undefined {\n const node = this.map.get(key);\n if (!node) return undefined;\n this.touch(key, node);\n return node.value;\n }\n\n set(key: K, value: V) {\n let node = this.map.get(key);\n if (node) {\n node.value = value;\n this.touch(key, node);\n return;\n }\n node = { prev: null, next: this.head, value };\n if (this.head) {\n const headNode = this.map.get(this.head);\n if (headNode) headNode.prev = key;\n }\n this.head = key;\n if (!this.tail) this.tail = key;\n this.map.set(key, node);\n if (this.map.size > this.limit) this.evict();\n }\n\n delete(key: K) {\n const node = this.map.get(key);\n if (!node) return;\n if (node.prev) {\n const prevNode = this.map.get(node.prev);\n if (prevNode) prevNode.next = node.next;\n }\n if (node.next) {\n const nextNode = this.map.get(node.next);\n if (nextNode) nextNode.prev = node.prev;\n }\n if (this.head === key) this.head = node.next;\n if (this.tail === key) this.tail = node.prev;\n this.map.delete(key);\n }\n\n keys(): IterableIterator<K> {\n return this.map.keys();\n }\n\n private touch(key: K, node: { prev: K | null; next: K | null; value: V }) {\n if (this.head === key) return; // already MRU\n\n // detach\n if (node.prev) {\n const prevNode = this.map.get(node.prev);\n if (prevNode) prevNode.next = node.next;\n }\n if (node.next) {\n const nextNode = this.map.get(node.next);\n if (nextNode) nextNode.prev = node.prev;\n }\n if (this.tail === key) this.tail = node.prev;\n\n // move to head\n node.prev = null;\n node.next = this.head;\n if (this.head) {\n const headNode = this.map.get(this.head);\n if (headNode) headNode.prev = key;\n }\n this.head = key;\n }\n\n private evict() {\n const old = this.tail;\n if (!old) return;\n const node = this.map.get(old);\n if (!node) {\n // Tail pointer is stale; reset pointers conservatively\n if (this.head === old) this.head = null;\n this.tail = null;\n return;\n }\n if (node.prev) {\n const prevNode = this.map.get(node.prev);\n if (prevNode) prevNode.next = null;\n }\n this.tail = node.prev;\n if (this.head === old) this.head = null;\n this.map.delete(old);\n\n if (this.onEvict) {\n try {\n this.onEvict(old, node.value);\n } catch {\n // ignore user callback errors\n }\n }\n }\n\n clear() {\n this.map.clear();\n this.head = this.tail = null;\n }\n}\n"],"mappings":"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"}
@@ -2,7 +2,6 @@ import { Lru } from "./lru.js";
2
2
  import { Bucket, finalizeGroup, finalizePart, makeEmptyDetails, makeEmptyPart } from "./types.js";
3
3
  import { classify } from "./classify.js";
4
4
  import { scan } from "./tokenizer.js";
5
-
6
5
  //#region src/parser/parser.ts
7
6
  var StyleParser = class {
8
7
  cache;
@@ -110,7 +109,7 @@ var StyleParser = class {
110
109
  return this.opts.units;
111
110
  }
112
111
  };
113
-
114
112
  //#endregion
115
113
  export { StyleParser };
114
+
116
115
  //# sourceMappingURL=parser.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"parser.js","names":[],"sources":["../../src/parser/parser.ts"],"sourcesContent":["import { classify } from './classify';\nimport { Lru } from './lru';\nimport { scan } from './tokenizer';\nimport type {\n ParserOptions,\n ProcessedStyle,\n StyleDetails,\n StyleDetailsPart,\n} from './types';\nimport {\n Bucket,\n finalizeGroup,\n finalizePart,\n makeEmptyDetails,\n makeEmptyPart,\n} from './types';\n\nexport class StyleParser {\n private cache: Lru<string, ProcessedStyle>;\n constructor(private opts: ParserOptions = {}) {\n this.cache = new Lru<string, ProcessedStyle>(this.opts.cacheSize ?? 1000);\n }\n\n /* ---------------- Public API ---------------- */\n process(src: string): ProcessedStyle {\n const key = String(src);\n const hit = this.cache.get(key);\n if (hit) return hit;\n\n // strip comments & lower-case once\n const stripped = src\n .replace(/\\/\\*[^*]*\\*+(?:[^/*][^*]*\\*+)*\\//g, '')\n .toLowerCase();\n\n const groups: StyleDetails[] = [];\n let currentGroup = makeEmptyDetails();\n let currentPart = makeEmptyPart();\n let parts: StyleDetailsPart[] = [];\n\n const pushToken = (bucket: Bucket, processed: string) => {\n if (!processed) return;\n\n // If the previous token was a url(...) value, merge this token into it so that\n // background layer segments like \"url(img) no-repeat center/cover\" are kept\n // as a single value entry.\n const mergeIntoPrevUrl = () => {\n const lastIdx = currentPart.values.length - 1;\n currentPart.values[lastIdx] += ` ${processed}`;\n const lastAllIdx = currentPart.all.length - 1;\n currentPart.all[lastAllIdx] += ` ${processed}`;\n };\n\n const prevIsUrlValue =\n currentPart.values.length > 0 &&\n currentPart.values[currentPart.values.length - 1].startsWith('url(');\n\n if (prevIsUrlValue) {\n // Extend the existing url(...) value regardless of current bucket.\n mergeIntoPrevUrl();\n // Additionally, for non-value buckets we need to remove their own storage.\n // So early return.\n return;\n }\n\n switch (bucket) {\n case Bucket.Color:\n currentPart.colors.push(processed);\n break;\n case Bucket.Value:\n currentPart.values.push(processed);\n break;\n case Bucket.Mod:\n currentPart.mods.push(processed);\n break;\n }\n currentPart.all.push(processed);\n };\n\n const endPart = () => {\n // Only add non-empty parts\n if (currentPart.all.length > 0) {\n finalizePart(currentPart);\n parts.push(currentPart);\n }\n currentPart = makeEmptyPart();\n };\n\n const endGroup = () => {\n endPart(); // finalize last part\n\n // Ensure at least one part exists (even if empty) for backward compat\n if (parts.length === 0) {\n parts.push(makeEmptyPart());\n finalizePart(parts[0]);\n }\n\n finalizeGroup(currentGroup, parts);\n groups.push(currentGroup);\n\n // Reset for next group\n currentGroup = makeEmptyDetails();\n parts = [];\n currentPart = makeEmptyPart();\n };\n\n scan(stripped, (tok, isComma, isSlash, _prevChar) => {\n if (tok) {\n // Accumulate raw token into currentGroup.input\n if (currentGroup.input) {\n currentGroup.input += ` ${tok}`;\n } else {\n currentGroup.input = tok;\n }\n\n const { bucket, processed } = classify(tok, this.opts, (sub) =>\n this.process(sub),\n );\n pushToken(bucket, processed);\n }\n if (isSlash) endPart();\n if (isComma) endGroup();\n });\n\n // push final group if not already\n if (currentPart.all.length || parts.length || !groups.length) endGroup();\n\n const output = groups.map((g) => g.output).join(', ');\n const result: ProcessedStyle = { output, groups };\n Object.freeze(result);\n this.cache.set(key, result);\n return result;\n }\n\n setFuncs(funcs: Required<ParserOptions>['funcs']): void {\n this.opts.funcs = funcs;\n this.cache.clear();\n }\n\n setUnits(units: Required<ParserOptions>['units']): void {\n this.opts.units = units;\n this.cache.clear();\n }\n\n updateOptions(patch: Partial<ParserOptions>): void {\n Object.assign(this.opts, patch);\n if (patch.cacheSize)\n this.cache = new Lru<string, ProcessedStyle>(patch.cacheSize);\n else this.cache.clear();\n }\n\n /**\n * Clear the parser cache.\n * Call this when external state that affects parsing results has changed\n * (e.g., predefined tokens).\n */\n clearCache(): void {\n this.cache.clear();\n }\n\n /**\n * Get the current units configuration.\n */\n getUnits(): ParserOptions['units'] {\n return this.opts.units;\n }\n}\n\n// Re-export\nexport type { StyleDetails, ProcessedStyle } from './types';\n"],"mappings":";;;;;;AAiBA,IAAa,cAAb,MAAyB;CACvB,AAAQ;CACR,YAAY,AAAQ,OAAsB,EAAE,EAAE;EAA1B;AAClB,OAAK,QAAQ,IAAI,IAA4B,KAAK,KAAK,aAAa,IAAK;;CAI3E,QAAQ,KAA6B;EACnC,MAAM,MAAM,OAAO,IAAI;EACvB,MAAM,MAAM,KAAK,MAAM,IAAI,IAAI;AAC/B,MAAI,IAAK,QAAO;EAGhB,MAAM,WAAW,IACd,QAAQ,qCAAqC,GAAG,CAChD,aAAa;EAEhB,MAAM,SAAyB,EAAE;EACjC,IAAI,eAAe,kBAAkB;EACrC,IAAI,cAAc,eAAe;EACjC,IAAI,QAA4B,EAAE;EAElC,MAAM,aAAa,QAAgB,cAAsB;AACvD,OAAI,CAAC,UAAW;GAKhB,MAAM,yBAAyB;IAC7B,MAAM,UAAU,YAAY,OAAO,SAAS;AAC5C,gBAAY,OAAO,YAAY,IAAI;IACnC,MAAM,aAAa,YAAY,IAAI,SAAS;AAC5C,gBAAY,IAAI,eAAe,IAAI;;AAOrC,OAHE,YAAY,OAAO,SAAS,KAC5B,YAAY,OAAO,YAAY,OAAO,SAAS,GAAG,WAAW,OAAO,EAElD;AAElB,sBAAkB;AAGlB;;AAGF,WAAQ,QAAR;IACE,KAAK,OAAO;AACV,iBAAY,OAAO,KAAK,UAAU;AAClC;IACF,KAAK,OAAO;AACV,iBAAY,OAAO,KAAK,UAAU;AAClC;IACF,KAAK,OAAO;AACV,iBAAY,KAAK,KAAK,UAAU;AAChC;;AAEJ,eAAY,IAAI,KAAK,UAAU;;EAGjC,MAAM,gBAAgB;AAEpB,OAAI,YAAY,IAAI,SAAS,GAAG;AAC9B,iBAAa,YAAY;AACzB,UAAM,KAAK,YAAY;;AAEzB,iBAAc,eAAe;;EAG/B,MAAM,iBAAiB;AACrB,YAAS;AAGT,OAAI,MAAM,WAAW,GAAG;AACtB,UAAM,KAAK,eAAe,CAAC;AAC3B,iBAAa,MAAM,GAAG;;AAGxB,iBAAc,cAAc,MAAM;AAClC,UAAO,KAAK,aAAa;AAGzB,kBAAe,kBAAkB;AACjC,WAAQ,EAAE;AACV,iBAAc,eAAe;;AAG/B,OAAK,WAAW,KAAK,SAAS,SAAS,cAAc;AACnD,OAAI,KAAK;AAEP,QAAI,aAAa,MACf,cAAa,SAAS,IAAI;QAE1B,cAAa,QAAQ;IAGvB,MAAM,EAAE,QAAQ,cAAc,SAAS,KAAK,KAAK,OAAO,QACtD,KAAK,QAAQ,IAAI,CAClB;AACD,cAAU,QAAQ,UAAU;;AAE9B,OAAI,QAAS,UAAS;AACtB,OAAI,QAAS,WAAU;IACvB;AAGF,MAAI,YAAY,IAAI,UAAU,MAAM,UAAU,CAAC,OAAO,OAAQ,WAAU;EAGxE,MAAM,SAAyB;GAAE,QADlB,OAAO,KAAK,MAAM,EAAE,OAAO,CAAC,KAAK,KAAK;GACZ;GAAQ;AACjD,SAAO,OAAO,OAAO;AACrB,OAAK,MAAM,IAAI,KAAK,OAAO;AAC3B,SAAO;;CAGT,SAAS,OAA+C;AACtD,OAAK,KAAK,QAAQ;AAClB,OAAK,MAAM,OAAO;;CAGpB,SAAS,OAA+C;AACtD,OAAK,KAAK,QAAQ;AAClB,OAAK,MAAM,OAAO;;CAGpB,cAAc,OAAqC;AACjD,SAAO,OAAO,KAAK,MAAM,MAAM;AAC/B,MAAI,MAAM,UACR,MAAK,QAAQ,IAAI,IAA4B,MAAM,UAAU;MAC1D,MAAK,MAAM,OAAO;;;;;;;CAQzB,aAAmB;AACjB,OAAK,MAAM,OAAO;;;;;CAMpB,WAAmC;AACjC,SAAO,KAAK,KAAK"}
1
+ {"version":3,"file":"parser.js","names":[],"sources":["../../src/parser/parser.ts"],"sourcesContent":["import { classify } from './classify';\nimport { Lru } from './lru';\nimport { scan } from './tokenizer';\nimport type {\n ParserOptions,\n ProcessedStyle,\n StyleDetails,\n StyleDetailsPart,\n} from './types';\nimport {\n Bucket,\n finalizeGroup,\n finalizePart,\n makeEmptyDetails,\n makeEmptyPart,\n} from './types';\n\nexport class StyleParser {\n private cache: Lru<string, ProcessedStyle>;\n constructor(private opts: ParserOptions = {}) {\n this.cache = new Lru<string, ProcessedStyle>(this.opts.cacheSize ?? 1000);\n }\n\n /* ---------------- Public API ---------------- */\n process(src: string): ProcessedStyle {\n const key = String(src);\n const hit = this.cache.get(key);\n if (hit) return hit;\n\n // strip comments & lower-case once\n const stripped = src\n .replace(/\\/\\*[^*]*\\*+(?:[^/*][^*]*\\*+)*\\//g, '')\n .toLowerCase();\n\n const groups: StyleDetails[] = [];\n let currentGroup = makeEmptyDetails();\n let currentPart = makeEmptyPart();\n let parts: StyleDetailsPart[] = [];\n\n const pushToken = (bucket: Bucket, processed: string) => {\n if (!processed) return;\n\n // If the previous token was a url(...) value, merge this token into it so that\n // background layer segments like \"url(img) no-repeat center/cover\" are kept\n // as a single value entry.\n const mergeIntoPrevUrl = () => {\n const lastIdx = currentPart.values.length - 1;\n currentPart.values[lastIdx] += ` ${processed}`;\n const lastAllIdx = currentPart.all.length - 1;\n currentPart.all[lastAllIdx] += ` ${processed}`;\n };\n\n const prevIsUrlValue =\n currentPart.values.length > 0 &&\n currentPart.values[currentPart.values.length - 1].startsWith('url(');\n\n if (prevIsUrlValue) {\n // Extend the existing url(...) value regardless of current bucket.\n mergeIntoPrevUrl();\n // Additionally, for non-value buckets we need to remove their own storage.\n // So early return.\n return;\n }\n\n switch (bucket) {\n case Bucket.Color:\n currentPart.colors.push(processed);\n break;\n case Bucket.Value:\n currentPart.values.push(processed);\n break;\n case Bucket.Mod:\n currentPart.mods.push(processed);\n break;\n }\n currentPart.all.push(processed);\n };\n\n const endPart = () => {\n // Only add non-empty parts\n if (currentPart.all.length > 0) {\n finalizePart(currentPart);\n parts.push(currentPart);\n }\n currentPart = makeEmptyPart();\n };\n\n const endGroup = () => {\n endPart(); // finalize last part\n\n // Ensure at least one part exists (even if empty) for backward compat\n if (parts.length === 0) {\n parts.push(makeEmptyPart());\n finalizePart(parts[0]);\n }\n\n finalizeGroup(currentGroup, parts);\n groups.push(currentGroup);\n\n // Reset for next group\n currentGroup = makeEmptyDetails();\n parts = [];\n currentPart = makeEmptyPart();\n };\n\n scan(stripped, (tok, isComma, isSlash, _prevChar) => {\n if (tok) {\n // Accumulate raw token into currentGroup.input\n if (currentGroup.input) {\n currentGroup.input += ` ${tok}`;\n } else {\n currentGroup.input = tok;\n }\n\n const { bucket, processed } = classify(tok, this.opts, (sub) =>\n this.process(sub),\n );\n pushToken(bucket, processed);\n }\n if (isSlash) endPart();\n if (isComma) endGroup();\n });\n\n // push final group if not already\n if (currentPart.all.length || parts.length || !groups.length) endGroup();\n\n const output = groups.map((g) => g.output).join(', ');\n const result: ProcessedStyle = { output, groups };\n Object.freeze(result);\n this.cache.set(key, result);\n return result;\n }\n\n setFuncs(funcs: Required<ParserOptions>['funcs']): void {\n this.opts.funcs = funcs;\n this.cache.clear();\n }\n\n setUnits(units: Required<ParserOptions>['units']): void {\n this.opts.units = units;\n this.cache.clear();\n }\n\n updateOptions(patch: Partial<ParserOptions>): void {\n Object.assign(this.opts, patch);\n if (patch.cacheSize)\n this.cache = new Lru<string, ProcessedStyle>(patch.cacheSize);\n else this.cache.clear();\n }\n\n /**\n * Clear the parser cache.\n * Call this when external state that affects parsing results has changed\n * (e.g., predefined tokens).\n */\n clearCache(): void {\n this.cache.clear();\n }\n\n /**\n * Get the current units configuration.\n */\n getUnits(): ParserOptions['units'] {\n return this.opts.units;\n }\n}\n\n// Re-export\nexport type { StyleDetails, ProcessedStyle } from './types';\n"],"mappings":";;;;;AAiBA,IAAa,cAAb,MAAyB;CACvB;CACA,YAAY,OAA8B,EAAE,EAAE;AAA1B,OAAA,OAAA;AAClB,OAAK,QAAQ,IAAI,IAA4B,KAAK,KAAK,aAAa,IAAK;;CAI3E,QAAQ,KAA6B;EACnC,MAAM,MAAM,OAAO,IAAI;EACvB,MAAM,MAAM,KAAK,MAAM,IAAI,IAAI;AAC/B,MAAI,IAAK,QAAO;EAGhB,MAAM,WAAW,IACd,QAAQ,qCAAqC,GAAG,CAChD,aAAa;EAEhB,MAAM,SAAyB,EAAE;EACjC,IAAI,eAAe,kBAAkB;EACrC,IAAI,cAAc,eAAe;EACjC,IAAI,QAA4B,EAAE;EAElC,MAAM,aAAa,QAAgB,cAAsB;AACvD,OAAI,CAAC,UAAW;GAKhB,MAAM,yBAAyB;IAC7B,MAAM,UAAU,YAAY,OAAO,SAAS;AAC5C,gBAAY,OAAO,YAAY,IAAI;IACnC,MAAM,aAAa,YAAY,IAAI,SAAS;AAC5C,gBAAY,IAAI,eAAe,IAAI;;AAOrC,OAHE,YAAY,OAAO,SAAS,KAC5B,YAAY,OAAO,YAAY,OAAO,SAAS,GAAG,WAAW,OAAO,EAElD;AAElB,sBAAkB;AAGlB;;AAGF,WAAQ,QAAR;IACE,KAAK,OAAO;AACV,iBAAY,OAAO,KAAK,UAAU;AAClC;IACF,KAAK,OAAO;AACV,iBAAY,OAAO,KAAK,UAAU;AAClC;IACF,KAAK,OAAO;AACV,iBAAY,KAAK,KAAK,UAAU;AAChC;;AAEJ,eAAY,IAAI,KAAK,UAAU;;EAGjC,MAAM,gBAAgB;AAEpB,OAAI,YAAY,IAAI,SAAS,GAAG;AAC9B,iBAAa,YAAY;AACzB,UAAM,KAAK,YAAY;;AAEzB,iBAAc,eAAe;;EAG/B,MAAM,iBAAiB;AACrB,YAAS;AAGT,OAAI,MAAM,WAAW,GAAG;AACtB,UAAM,KAAK,eAAe,CAAC;AAC3B,iBAAa,MAAM,GAAG;;AAGxB,iBAAc,cAAc,MAAM;AAClC,UAAO,KAAK,aAAa;AAGzB,kBAAe,kBAAkB;AACjC,WAAQ,EAAE;AACV,iBAAc,eAAe;;AAG/B,OAAK,WAAW,KAAK,SAAS,SAAS,cAAc;AACnD,OAAI,KAAK;AAEP,QAAI,aAAa,MACf,cAAa,SAAS,IAAI;QAE1B,cAAa,QAAQ;IAGvB,MAAM,EAAE,QAAQ,cAAc,SAAS,KAAK,KAAK,OAAO,QACtD,KAAK,QAAQ,IAAI,CAClB;AACD,cAAU,QAAQ,UAAU;;AAE9B,OAAI,QAAS,UAAS;AACtB,OAAI,QAAS,WAAU;IACvB;AAGF,MAAI,YAAY,IAAI,UAAU,MAAM,UAAU,CAAC,OAAO,OAAQ,WAAU;EAGxE,MAAM,SAAyB;GAAE,QADlB,OAAO,KAAK,MAAM,EAAE,OAAO,CAAC,KAAK,KAAK;GACZ;GAAQ;AACjD,SAAO,OAAO,OAAO;AACrB,OAAK,MAAM,IAAI,KAAK,OAAO;AAC3B,SAAO;;CAGT,SAAS,OAA+C;AACtD,OAAK,KAAK,QAAQ;AAClB,OAAK,MAAM,OAAO;;CAGpB,SAAS,OAA+C;AACtD,OAAK,KAAK,QAAQ;AAClB,OAAK,MAAM,OAAO;;CAGpB,cAAc,OAAqC;AACjD,SAAO,OAAO,KAAK,MAAM,MAAM;AAC/B,MAAI,MAAM,UACR,MAAK,QAAQ,IAAI,IAA4B,MAAM,UAAU;MAC1D,MAAK,MAAM,OAAO;;;;;;;CAQzB,aAAmB;AACjB,OAAK,MAAM,OAAO;;;;;CAMpB,WAAmC;AACjC,SAAO,KAAK,KAAK"}
@@ -63,7 +63,7 @@ function scan(src, cb) {
63
63
  }
64
64
  flush(false, false);
65
65
  }
66
-
67
66
  //#endregion
68
67
  export { scan };
68
+
69
69
  //# sourceMappingURL=tokenizer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tokenizer.js","names":[],"sources":["../../src/parser/tokenizer.ts"],"sourcesContent":["export type TokenCallback = (\n token: string,\n isComma: boolean,\n isSlash: boolean,\n precedingChar: string | null,\n) => void;\n\nconst isWhitespace = (ch: string | undefined): boolean =>\n ch === ' ' || ch === '\\n' || ch === '\\t' || ch === '\\r' || ch === '\\f';\n\nexport function scan(src: string, cb: TokenCallback) {\n let depth = 0;\n let inUrl = false;\n let inQuote: string | 0 = 0;\n let start = 0;\n let i = 0;\n // Track if we just saw a standalone slash separator (whitespace before, whitespace after)\n let pendingSlash = false;\n\n const flush = (isComma: boolean, isSlash: boolean) => {\n // If we have a pending slash, emit the part break\n const actualSlash = isSlash || pendingSlash;\n pendingSlash = false;\n\n if (start < i) {\n const prevChar = start > 0 ? src[start - 1] : null;\n cb(src.slice(start, i), isComma, actualSlash, prevChar);\n } else if (isComma) {\n cb('', true, false, null); // empty token followed by comma => group break.\n } else if (actualSlash) {\n cb('', false, true, null); // empty token followed by slash => part break.\n }\n start = i + 1;\n };\n\n for (; i < src.length; i++) {\n const ch = src[i];\n\n // quote mode\n if (inQuote) {\n if (ch === inQuote && src[i - 1] !== '\\\\') inQuote = 0;\n continue;\n }\n if (ch === '\"' || ch === \"'\") {\n inQuote = ch;\n continue;\n }\n\n // paren & url tracking (not inside quotes)\n if (ch === '(') {\n // detect url(\n if (!depth) {\n const maybe = src.slice(Math.max(0, i - 3), i + 1);\n if (maybe === 'url(') inUrl = true;\n }\n depth++;\n continue;\n }\n if (ch === ')') {\n depth = Math.max(0, depth - 1);\n if (inUrl && depth === 0) inUrl = false;\n continue;\n }\n\n if (inUrl) continue; // inside url(...) treat everything as part of token\n\n if (!depth) {\n if (ch === ',') {\n flush(true, false);\n continue;\n }\n // Slash is only a separator when surrounded by whitespace (e.g., \"a / b\")\n // This preserves CSS patterns like \"center/cover\" as single tokens\n if (ch === '/') {\n const prevIsWhitespace = isWhitespace(src[i - 1]);\n const nextIsWhitespace = isWhitespace(src[i + 1]);\n if (prevIsWhitespace && nextIsWhitespace) {\n // Already flushed by whitespace before, mark pending slash\n pendingSlash = true;\n start = i + 1; // skip the slash character\n continue;\n }\n // Not surrounded by whitespace - treat as part of token\n continue;\n }\n if (isWhitespace(ch)) {\n flush(false, false);\n continue;\n }\n }\n }\n flush(false, false); // tail\n}\n"],"mappings":";AAOA,MAAM,gBAAgB,OACpB,OAAO,OAAO,OAAO,QAAQ,OAAO,OAAQ,OAAO,QAAQ,OAAO;AAEpE,SAAgB,KAAK,KAAa,IAAmB;CACnD,IAAI,QAAQ;CACZ,IAAI,QAAQ;CACZ,IAAI,UAAsB;CAC1B,IAAI,QAAQ;CACZ,IAAI,IAAI;CAER,IAAI,eAAe;CAEnB,MAAM,SAAS,SAAkB,YAAqB;EAEpD,MAAM,cAAc,WAAW;AAC/B,iBAAe;AAEf,MAAI,QAAQ,GAAG;GACb,MAAM,WAAW,QAAQ,IAAI,IAAI,QAAQ,KAAK;AAC9C,MAAG,IAAI,MAAM,OAAO,EAAE,EAAE,SAAS,aAAa,SAAS;aAC9C,QACT,IAAG,IAAI,MAAM,OAAO,KAAK;WAChB,YACT,IAAG,IAAI,OAAO,MAAM,KAAK;AAE3B,UAAQ,IAAI;;AAGd,QAAO,IAAI,IAAI,QAAQ,KAAK;EAC1B,MAAM,KAAK,IAAI;AAGf,MAAI,SAAS;AACX,OAAI,OAAO,WAAW,IAAI,IAAI,OAAO,KAAM,WAAU;AACrD;;AAEF,MAAI,OAAO,QAAO,OAAO,KAAK;AAC5B,aAAU;AACV;;AAIF,MAAI,OAAO,KAAK;AAEd,OAAI,CAAC,OAEH;QADc,IAAI,MAAM,KAAK,IAAI,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KACpC,OAAQ,SAAQ;;AAEhC;AACA;;AAEF,MAAI,OAAO,KAAK;AACd,WAAQ,KAAK,IAAI,GAAG,QAAQ,EAAE;AAC9B,OAAI,SAAS,UAAU,EAAG,SAAQ;AAClC;;AAGF,MAAI,MAAO;AAEX,MAAI,CAAC,OAAO;AACV,OAAI,OAAO,KAAK;AACd,UAAM,MAAM,MAAM;AAClB;;AAIF,OAAI,OAAO,KAAK;IACd,MAAM,mBAAmB,aAAa,IAAI,IAAI,GAAG;IACjD,MAAM,mBAAmB,aAAa,IAAI,IAAI,GAAG;AACjD,QAAI,oBAAoB,kBAAkB;AAExC,oBAAe;AACf,aAAQ,IAAI;AACZ;;AAGF;;AAEF,OAAI,aAAa,GAAG,EAAE;AACpB,UAAM,OAAO,MAAM;AACnB;;;;AAIN,OAAM,OAAO,MAAM"}
1
+ {"version":3,"file":"tokenizer.js","names":[],"sources":["../../src/parser/tokenizer.ts"],"sourcesContent":["export type TokenCallback = (\n token: string,\n isComma: boolean,\n isSlash: boolean,\n precedingChar: string | null,\n) => void;\n\nconst isWhitespace = (ch: string | undefined): boolean =>\n ch === ' ' || ch === '\\n' || ch === '\\t' || ch === '\\r' || ch === '\\f';\n\nexport function scan(src: string, cb: TokenCallback) {\n let depth = 0;\n let inUrl = false;\n let inQuote: string | 0 = 0;\n let start = 0;\n let i = 0;\n // Track if we just saw a standalone slash separator (whitespace before, whitespace after)\n let pendingSlash = false;\n\n const flush = (isComma: boolean, isSlash: boolean) => {\n // If we have a pending slash, emit the part break\n const actualSlash = isSlash || pendingSlash;\n pendingSlash = false;\n\n if (start < i) {\n const prevChar = start > 0 ? src[start - 1] : null;\n cb(src.slice(start, i), isComma, actualSlash, prevChar);\n } else if (isComma) {\n cb('', true, false, null); // empty token followed by comma => group break.\n } else if (actualSlash) {\n cb('', false, true, null); // empty token followed by slash => part break.\n }\n start = i + 1;\n };\n\n for (; i < src.length; i++) {\n const ch = src[i];\n\n // quote mode\n if (inQuote) {\n if (ch === inQuote && src[i - 1] !== '\\\\') inQuote = 0;\n continue;\n }\n if (ch === '\"' || ch === \"'\") {\n inQuote = ch;\n continue;\n }\n\n // paren & url tracking (not inside quotes)\n if (ch === '(') {\n // detect url(\n if (!depth) {\n const maybe = src.slice(Math.max(0, i - 3), i + 1);\n if (maybe === 'url(') inUrl = true;\n }\n depth++;\n continue;\n }\n if (ch === ')') {\n depth = Math.max(0, depth - 1);\n if (inUrl && depth === 0) inUrl = false;\n continue;\n }\n\n if (inUrl) continue; // inside url(...) treat everything as part of token\n\n if (!depth) {\n if (ch === ',') {\n flush(true, false);\n continue;\n }\n // Slash is only a separator when surrounded by whitespace (e.g., \"a / b\")\n // This preserves CSS patterns like \"center/cover\" as single tokens\n if (ch === '/') {\n const prevIsWhitespace = isWhitespace(src[i - 1]);\n const nextIsWhitespace = isWhitespace(src[i + 1]);\n if (prevIsWhitespace && nextIsWhitespace) {\n // Already flushed by whitespace before, mark pending slash\n pendingSlash = true;\n start = i + 1; // skip the slash character\n continue;\n }\n // Not surrounded by whitespace - treat as part of token\n continue;\n }\n if (isWhitespace(ch)) {\n flush(false, false);\n continue;\n }\n }\n }\n flush(false, false); // tail\n}\n"],"mappings":";AAOA,MAAM,gBAAgB,OACpB,OAAO,OAAO,OAAO,QAAQ,OAAO,OAAQ,OAAO,QAAQ,OAAO;AAEpE,SAAgB,KAAK,KAAa,IAAmB;CACnD,IAAI,QAAQ;CACZ,IAAI,QAAQ;CACZ,IAAI,UAAsB;CAC1B,IAAI,QAAQ;CACZ,IAAI,IAAI;CAER,IAAI,eAAe;CAEnB,MAAM,SAAS,SAAkB,YAAqB;EAEpD,MAAM,cAAc,WAAW;AAC/B,iBAAe;AAEf,MAAI,QAAQ,GAAG;GACb,MAAM,WAAW,QAAQ,IAAI,IAAI,QAAQ,KAAK;AAC9C,MAAG,IAAI,MAAM,OAAO,EAAE,EAAE,SAAS,aAAa,SAAS;aAC9C,QACT,IAAG,IAAI,MAAM,OAAO,KAAK;WAChB,YACT,IAAG,IAAI,OAAO,MAAM,KAAK;AAE3B,UAAQ,IAAI;;AAGd,QAAO,IAAI,IAAI,QAAQ,KAAK;EAC1B,MAAM,KAAK,IAAI;AAGf,MAAI,SAAS;AACX,OAAI,OAAO,WAAW,IAAI,IAAI,OAAO,KAAM,WAAU;AACrD;;AAEF,MAAI,OAAO,QAAO,OAAO,KAAK;AAC5B,aAAU;AACV;;AAIF,MAAI,OAAO,KAAK;AAEd,OAAI,CAAC;QACW,IAAI,MAAM,KAAK,IAAI,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KACpC,OAAQ,SAAQ;;AAEhC;AACA;;AAEF,MAAI,OAAO,KAAK;AACd,WAAQ,KAAK,IAAI,GAAG,QAAQ,EAAE;AAC9B,OAAI,SAAS,UAAU,EAAG,SAAQ;AAClC;;AAGF,MAAI,MAAO;AAEX,MAAI,CAAC,OAAO;AACV,OAAI,OAAO,KAAK;AACd,UAAM,MAAM,MAAM;AAClB;;AAIF,OAAI,OAAO,KAAK;IACd,MAAM,mBAAmB,aAAa,IAAI,IAAI,GAAG;IACjD,MAAM,mBAAmB,aAAa,IAAI,IAAI,GAAG;AACjD,QAAI,oBAAoB,kBAAkB;AAExC,oBAAe;AACf,aAAQ,IAAI;AACZ;;AAGF;;AAEF,OAAI,aAAa,GAAG,EAAE;AACpB,UAAM,OAAO,MAAM;AACnB;;;;AAIN,OAAM,OAAO,MAAM"}
@@ -40,7 +40,7 @@ const finalizeGroup = (d, parts) => {
40
40
  d.output = parts.map((p) => p.output).join(" / ");
41
41
  return d;
42
42
  };
43
-
44
43
  //#endregion
45
44
  export { Bucket, finalizeGroup, finalizePart, makeEmptyDetails, makeEmptyPart };
45
+
46
46
  //# sourceMappingURL=types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","names":[],"sources":["../../src/parser/types.ts"],"sourcesContent":["export enum Bucket {\n Color,\n Value,\n Mod,\n}\n\n/**\n * A part within a group, representing a slash-separated segment.\n * For example, in `'2px solid #red / 4px'`, there are two parts:\n * - Part 0: `2px solid #red`\n * - Part 1: `4px`\n */\nexport interface StyleDetailsPart {\n mods: string[];\n values: string[];\n colors: string[];\n all: string[];\n output: string;\n}\n\n/**\n * A group of style details, representing a comma-separated segment.\n * Contains aggregated values from all parts for backward compatibility,\n * plus the structured `parts` array for handlers that need slash separation.\n */\nexport interface StyleDetails {\n input: string;\n output: string;\n /** Aggregated mods from all parts (backward compatible) */\n mods: string[];\n /** Aggregated values from all parts (backward compatible) */\n values: string[];\n /** Aggregated colors from all parts (backward compatible) */\n colors: string[];\n /** Aggregated all tokens from all parts (backward compatible) */\n all: string[];\n /** Slash-separated parts within this group */\n parts: StyleDetailsPart[];\n}\n\nexport interface ProcessedStyle {\n output: string;\n groups: StyleDetails[];\n}\n\nexport type UnitHandler = (scalar: number) => string;\n\nexport interface ParserOptions {\n funcs?: Record<string, (parsed: StyleDetails[]) => string>;\n units?: Record<string, string | UnitHandler>;\n cacheSize?: number;\n}\n\nexport const makeEmptyPart = (): StyleDetailsPart => ({\n mods: [],\n values: [],\n colors: [],\n all: [],\n output: '',\n});\n\nexport const makeEmptyDetails = (): StyleDetails => ({\n input: '',\n output: '',\n mods: [],\n values: [],\n colors: [],\n all: [],\n parts: [],\n});\n\nexport const finalizePart = (p: StyleDetailsPart): StyleDetailsPart => {\n p.output = p.all.join(' ');\n return p;\n};\n\n/**\n * Aggregate parts into a StyleDetails group.\n * Combines all parts' arrays into group-level arrays for backward compatibility.\n */\nexport const finalizeGroup = (\n d: StyleDetails,\n parts: StyleDetailsPart[],\n): StyleDetails => {\n // Store parts\n d.parts = parts;\n\n // Aggregate all parts into group-level arrays\n for (const part of parts) {\n d.mods.push(...part.mods);\n d.values.push(...part.values);\n d.colors.push(...part.colors);\n d.all.push(...part.all);\n }\n\n // Join parts' outputs with ' / ' for the group output\n d.output = parts.map((p) => p.output).join(' / ');\n\n return d;\n};\n"],"mappings":";AAAA,IAAY,0CAAL;AACL;AACA;AACA;;;AAkDF,MAAa,uBAAyC;CACpD,MAAM,EAAE;CACR,QAAQ,EAAE;CACV,QAAQ,EAAE;CACV,KAAK,EAAE;CACP,QAAQ;CACT;AAED,MAAa,0BAAwC;CACnD,OAAO;CACP,QAAQ;CACR,MAAM,EAAE;CACR,QAAQ,EAAE;CACV,QAAQ,EAAE;CACV,KAAK,EAAE;CACP,OAAO,EAAE;CACV;AAED,MAAa,gBAAgB,MAA0C;AACrE,GAAE,SAAS,EAAE,IAAI,KAAK,IAAI;AAC1B,QAAO;;;;;;AAOT,MAAa,iBACX,GACA,UACiB;AAEjB,GAAE,QAAQ;AAGV,MAAK,MAAM,QAAQ,OAAO;AACxB,IAAE,KAAK,KAAK,GAAG,KAAK,KAAK;AACzB,IAAE,OAAO,KAAK,GAAG,KAAK,OAAO;AAC7B,IAAE,OAAO,KAAK,GAAG,KAAK,OAAO;AAC7B,IAAE,IAAI,KAAK,GAAG,KAAK,IAAI;;AAIzB,GAAE,SAAS,MAAM,KAAK,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM;AAEjD,QAAO"}
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../src/parser/types.ts"],"sourcesContent":["export enum Bucket {\n Color,\n Value,\n Mod,\n}\n\n/**\n * A part within a group, representing a slash-separated segment.\n * For example, in `'2px solid #red / 4px'`, there are two parts:\n * - Part 0: `2px solid #red`\n * - Part 1: `4px`\n */\nexport interface StyleDetailsPart {\n mods: string[];\n values: string[];\n colors: string[];\n all: string[];\n output: string;\n}\n\n/**\n * A group of style details, representing a comma-separated segment.\n * Contains aggregated values from all parts for backward compatibility,\n * plus the structured `parts` array for handlers that need slash separation.\n */\nexport interface StyleDetails {\n input: string;\n output: string;\n /** Aggregated mods from all parts (backward compatible) */\n mods: string[];\n /** Aggregated values from all parts (backward compatible) */\n values: string[];\n /** Aggregated colors from all parts (backward compatible) */\n colors: string[];\n /** Aggregated all tokens from all parts (backward compatible) */\n all: string[];\n /** Slash-separated parts within this group */\n parts: StyleDetailsPart[];\n}\n\nexport interface ProcessedStyle {\n output: string;\n groups: StyleDetails[];\n}\n\nexport type UnitHandler = (scalar: number) => string;\n\nexport interface ParserOptions {\n funcs?: Record<string, (parsed: StyleDetails[]) => string>;\n units?: Record<string, string | UnitHandler>;\n cacheSize?: number;\n}\n\nexport const makeEmptyPart = (): StyleDetailsPart => ({\n mods: [],\n values: [],\n colors: [],\n all: [],\n output: '',\n});\n\nexport const makeEmptyDetails = (): StyleDetails => ({\n input: '',\n output: '',\n mods: [],\n values: [],\n colors: [],\n all: [],\n parts: [],\n});\n\nexport const finalizePart = (p: StyleDetailsPart): StyleDetailsPart => {\n p.output = p.all.join(' ');\n return p;\n};\n\n/**\n * Aggregate parts into a StyleDetails group.\n * Combines all parts' arrays into group-level arrays for backward compatibility.\n */\nexport const finalizeGroup = (\n d: StyleDetails,\n parts: StyleDetailsPart[],\n): StyleDetails => {\n // Store parts\n d.parts = parts;\n\n // Aggregate all parts into group-level arrays\n for (const part of parts) {\n d.mods.push(...part.mods);\n d.values.push(...part.values);\n d.colors.push(...part.colors);\n d.all.push(...part.all);\n }\n\n // Join parts' outputs with ' / ' for the group output\n d.output = parts.map((p) => p.output).join(' / ');\n\n return d;\n};\n"],"mappings":";AAAA,IAAY,SAAL,yBAAA,QAAA;AACL,QAAA,OAAA,WAAA,KAAA;AACA,QAAA,OAAA,WAAA,KAAA;AACA,QAAA,OAAA,SAAA,KAAA;;KACD;AAiDD,MAAa,uBAAyC;CACpD,MAAM,EAAE;CACR,QAAQ,EAAE;CACV,QAAQ,EAAE;CACV,KAAK,EAAE;CACP,QAAQ;CACT;AAED,MAAa,0BAAwC;CACnD,OAAO;CACP,QAAQ;CACR,MAAM,EAAE;CACR,QAAQ,EAAE;CACV,QAAQ,EAAE;CACV,KAAK,EAAE;CACP,OAAO,EAAE;CACV;AAED,MAAa,gBAAgB,MAA0C;AACrE,GAAE,SAAS,EAAE,IAAI,KAAK,IAAI;AAC1B,QAAO;;;;;;AAOT,MAAa,iBACX,GACA,UACiB;AAEjB,GAAE,QAAQ;AAGV,MAAK,MAAM,QAAQ,OAAO;AACxB,IAAE,KAAK,KAAK,GAAG,KAAK,KAAK;AACzB,IAAE,OAAO,KAAK,GAAG,KAAK,OAAO;AAC7B,IAAE,OAAO,KAAK,GAAG,KAAK,OAAO;AAC7B,IAAE,IAAI,KAAK,GAAG,KAAK,IAAI;;AAIzB,GAAE,SAAS,MAAM,KAAK,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM;AAEjD,QAAO"}
@@ -400,7 +400,7 @@ function getConditionUniqueId(node) {
400
400
  uniqueIdCache.set(node, id);
401
401
  return id;
402
402
  }
403
-
404
403
  //#endregion
405
404
  export { and, createContainerDimensionCondition, createContainerRawCondition, createContainerStyleCondition, createMediaDimensionCondition, createMediaFeatureCondition, createMediaTypeCondition, createModifierCondition, createOwnCondition, createParentCondition, createPseudoCondition, createRootCondition, createStartingCondition, createSupportsCondition, falseCondition, getConditionUniqueId, isCompoundCondition, not, or, trueCondition };
405
+
406
406
  //# sourceMappingURL=conditions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"conditions.js","names":[],"sources":["../../src/pipeline/conditions.ts"],"sourcesContent":["/**\n * ConditionNode Types and Helpers\n *\n * Core data structures for representing style conditions as an abstract syntax tree.\n * Used throughout the pipeline for parsing, simplification, and CSS generation.\n */\n\n// ============================================================================\n// Core ConditionNode Types\n// ============================================================================\n\n/**\n * Base interface for all state conditions (leaf nodes)\n */\ninterface BaseStateCondition {\n kind: 'state';\n negated: boolean;\n raw: string; // Original string for debugging/caching\n uniqueId: string; // Normalized ID for comparison (built from props)\n}\n\n/**\n * Modifier condition: [data-attr] or [data-attr=\"value\"]\n */\nexport interface ModifierCondition extends BaseStateCondition {\n type: 'modifier';\n attribute: string; // e.g., 'data-theme', 'data-size'\n value?: string; // e.g., 'danger', 'large' (undefined = boolean attr)\n operator?: '=' | '^=' | '$=' | '*='; // Attribute match operator\n}\n\n/**\n * Pseudo-class condition: :hover, :focus-visible\n */\nexport interface PseudoCondition extends BaseStateCondition {\n type: 'pseudo';\n pseudo: string; // e.g., ':hover', ':focus-visible', ':nth-child(2n)'\n}\n\n/**\n * Numeric bound for dimension queries\n */\nexport interface NumericBound {\n value: string; // e.g., '768px', 'calc(var(--gap) * 40)'\n valueNumeric: number | null; // Parsed numeric value for comparison\n inclusive: boolean; // true for >=/<= , false for >/<\n}\n\n/**\n * Media query condition\n */\nexport interface MediaCondition extends BaseStateCondition {\n type: 'media';\n subtype: 'dimension' | 'feature' | 'type';\n\n // For dimension queries: @media(w < 768px), @media(600px <= w < 1200px)\n dimension?: 'width' | 'height' | 'inline-size' | 'block-size';\n lowerBound?: NumericBound; // >= or >\n upperBound?: NumericBound; // <= or <\n\n // For feature queries: @media(prefers-contrast: high)\n feature?: string; // e.g., 'prefers-contrast', 'prefers-color-scheme'\n featureValue?: string; // e.g., 'high', 'dark' (undefined = boolean feature)\n\n // For type queries: @media:print\n mediaType?: 'print' | 'screen' | 'all' | 'speech';\n}\n\n/**\n * Container query condition\n */\nexport interface ContainerCondition extends BaseStateCondition {\n type: 'container';\n subtype: 'dimension' | 'style' | 'raw';\n containerName?: string; // e.g., 'layout', 'sidebar' (undefined = nearest)\n\n // For dimension queries: @(w < 600px), @(layout, w < 600px)\n dimension?: 'width' | 'height' | 'inline-size' | 'block-size';\n lowerBound?: NumericBound;\n upperBound?: NumericBound;\n\n // For style queries: @(layout, $variant=danger), @($theme)\n property?: string; // CSS custom property name (without --)\n propertyValue?: string; // e.g., 'danger' (undefined = existence check)\n\n // For raw function queries: @(scroll-state(stuck: top)), @(style(display: flex))\n rawCondition?: string; // Verbatim CSS condition string\n}\n\n/**\n * Root state condition: @root(theme=dark)\n */\nexport interface RootCondition extends BaseStateCondition {\n type: 'root';\n innerCondition: ConditionNode;\n}\n\n/**\n * Parent state condition: @parent(hovered), @parent(theme=dark, >)\n */\nexport interface ParentCondition extends BaseStateCondition {\n type: 'parent';\n innerCondition: ConditionNode;\n direct: boolean; // true for @parent(..., >) — direct parent only\n}\n\n/**\n * Own state condition: @own(hovered)\n */\nexport interface OwnCondition extends BaseStateCondition {\n type: 'own';\n innerCondition: ConditionNode; // The parsed inner condition\n}\n\n/**\n * Starting style condition: @starting\n */\nexport interface StartingCondition extends BaseStateCondition {\n type: 'starting';\n}\n\n/**\n * Supports query condition: @supports(display: grid), @supports($, :has(*))\n */\nexport interface SupportsCondition extends BaseStateCondition {\n type: 'supports';\n subtype: 'feature' | 'selector';\n // The raw condition string (e.g., \"display: grid\" or \":has(*)\")\n condition: string;\n}\n\n/**\n * Union of all state condition types\n */\nexport type StateCondition =\n | ModifierCondition\n | PseudoCondition\n | MediaCondition\n | ContainerCondition\n | RootCondition\n | ParentCondition\n | OwnCondition\n | StartingCondition\n | SupportsCondition;\n\n/**\n * Compound node: combines conditions with AND/OR\n */\nexport interface CompoundCondition {\n kind: 'compound';\n operator: 'AND' | 'OR';\n children: ConditionNode[];\n}\n\n/**\n * True condition (matches everything)\n */\nexport interface TrueCondition {\n kind: 'true';\n}\n\n/**\n * False condition (matches nothing - skip this rule)\n */\nexport interface FalseCondition {\n kind: 'false';\n}\n\n/**\n * Union of all condition node types\n */\nexport type ConditionNode =\n | StateCondition\n | CompoundCondition\n | TrueCondition\n | FalseCondition;\n\n// ============================================================================\n// Constructor Functions\n// ============================================================================\n\n/**\n * Create a TRUE condition (matches everything)\n */\nexport function trueCondition(): TrueCondition {\n return { kind: 'true' };\n}\n\n/**\n * Create a FALSE condition (matches nothing)\n */\nexport function falseCondition(): FalseCondition {\n return { kind: 'false' };\n}\n\n/**\n * Create an AND compound condition\n */\nexport function and(...children: ConditionNode[]): ConditionNode {\n const filtered: ConditionNode[] = [];\n\n for (const child of children) {\n // Short-circuit on FALSE\n if (child.kind === 'false') {\n return falseCondition();\n }\n // Skip TRUE (identity for AND)\n if (child.kind === 'true') {\n continue;\n }\n // Flatten nested ANDs\n if (child.kind === 'compound' && child.operator === 'AND') {\n filtered.push(...child.children);\n } else {\n filtered.push(child);\n }\n }\n\n if (filtered.length === 0) {\n return trueCondition();\n }\n if (filtered.length === 1) {\n return filtered[0];\n }\n\n return {\n kind: 'compound',\n operator: 'AND',\n children: filtered,\n };\n}\n\n/**\n * Create an OR compound condition\n */\nexport function or(...children: ConditionNode[]): ConditionNode {\n const filtered: ConditionNode[] = [];\n\n for (const child of children) {\n // Short-circuit on TRUE\n if (child.kind === 'true') {\n return trueCondition();\n }\n // Skip FALSE (identity for OR)\n if (child.kind === 'false') {\n continue;\n }\n // Flatten nested ORs\n if (child.kind === 'compound' && child.operator === 'OR') {\n filtered.push(...child.children);\n } else {\n filtered.push(child);\n }\n }\n\n if (filtered.length === 0) {\n return falseCondition();\n }\n if (filtered.length === 1) {\n return filtered[0];\n }\n\n return {\n kind: 'compound',\n operator: 'OR',\n children: filtered,\n };\n}\n\n/**\n * Negate a condition\n */\nexport function not(node: ConditionNode): ConditionNode {\n // NOT(TRUE) = FALSE\n if (node.kind === 'true') {\n return falseCondition();\n }\n\n // NOT(FALSE) = TRUE\n if (node.kind === 'false') {\n return trueCondition();\n }\n\n // NOT(state) = toggle negated flag\n if (node.kind === 'state') {\n return {\n ...node,\n negated: !node.negated,\n uniqueId: node.negated\n ? node.uniqueId.replace(/^!/, '')\n : `!${node.uniqueId}`,\n };\n }\n\n // NOT(AND(a, b, ...)) = OR(NOT(a), NOT(b), ...) - De Morgan's law\n if (node.kind === 'compound' && node.operator === 'AND') {\n return or(...node.children.map((c) => not(c)));\n }\n\n // NOT(OR(a, b, ...)) = AND(NOT(a), NOT(b), ...) - De Morgan's law\n if (node.kind === 'compound' && node.operator === 'OR') {\n return and(...node.children.map((c) => not(c)));\n }\n\n // Fallback - should not reach here\n return node;\n}\n\n// ============================================================================\n// Condition Type Checking\n// ============================================================================\n\n/**\n * Check if a condition is a compound condition\n */\nexport function isCompoundCondition(\n node: ConditionNode,\n): node is CompoundCondition {\n return node.kind === 'compound';\n}\n\n// ============================================================================\n// UniqueId Generation\n// ============================================================================\n\n/**\n * Generate a normalized unique ID for a modifier condition\n */\nexport function modifierUniqueId(\n attribute: string,\n value?: string,\n operator = '=',\n negated = false,\n): string {\n const base = value\n ? `mod:${attribute}${operator}${value}`\n : `mod:${attribute}`;\n return negated ? `!${base}` : base;\n}\n\n/**\n * Generate a normalized unique ID for a pseudo condition\n */\nexport function pseudoUniqueId(pseudo: string, negated = false): string {\n const base = `pseudo:${pseudo}`;\n return negated ? `!${base}` : base;\n}\n\n/**\n * Generate a normalized unique ID for a media condition\n */\nexport function mediaUniqueId(\n subtype: 'dimension' | 'feature' | 'type',\n props: {\n dimension?: string;\n lowerBound?: NumericBound;\n upperBound?: NumericBound;\n feature?: string;\n featureValue?: string;\n mediaType?: string;\n },\n negated = false,\n): string {\n let base: string;\n\n if (subtype === 'dimension') {\n const parts = ['media', 'dim', props.dimension];\n if (props.lowerBound) {\n parts.push(props.lowerBound.inclusive ? '>=' : '>');\n parts.push(props.lowerBound.value);\n }\n if (props.upperBound) {\n parts.push(props.upperBound.inclusive ? '<=' : '<');\n parts.push(props.upperBound.value);\n }\n base = parts.join(':');\n } else if (subtype === 'feature') {\n base = props.featureValue\n ? `media:feat:${props.feature}:${props.featureValue}`\n : `media:feat:${props.feature}`;\n } else {\n base = `media:type:${props.mediaType}`;\n }\n\n return negated ? `!${base}` : base;\n}\n\n/**\n * Generate a normalized unique ID for a container condition\n */\nexport function containerUniqueId(\n subtype: 'dimension' | 'style' | 'raw',\n props: {\n containerName?: string;\n dimension?: string;\n lowerBound?: NumericBound;\n upperBound?: NumericBound;\n property?: string;\n propertyValue?: string;\n rawCondition?: string;\n },\n negated = false,\n): string {\n let base: string;\n const name = props.containerName || '_';\n\n if (subtype === 'dimension') {\n const parts = ['container', 'dim', name, props.dimension];\n if (props.lowerBound) {\n parts.push(props.lowerBound.inclusive ? '>=' : '>');\n parts.push(props.lowerBound.value);\n }\n if (props.upperBound) {\n parts.push(props.upperBound.inclusive ? '<=' : '<');\n parts.push(props.upperBound.value);\n }\n base = parts.join(':');\n } else if (subtype === 'raw') {\n base = `container:raw:${name}:${props.rawCondition}`;\n } else {\n base = props.propertyValue\n ? `container:style:${name}:--${props.property}:${props.propertyValue}`\n : `container:style:${name}:--${props.property}`;\n }\n\n return negated ? `!${base}` : base;\n}\n\n/**\n * Generate a normalized unique ID for a root condition\n */\nexport function rootUniqueId(innerUniqueId: string, negated = false): string {\n const base = `root:${innerUniqueId}`;\n return negated ? `!${base}` : base;\n}\n\n/**\n * Generate a normalized unique ID for a parent condition\n */\nexport function parentUniqueId(\n innerUniqueId: string,\n direct: boolean,\n negated = false,\n): string {\n const base = `parent:${direct ? '>' : ''}${innerUniqueId}`;\n return negated ? `!${base}` : base;\n}\n\n/**\n * Generate a normalized unique ID for an own condition\n */\nexport function ownUniqueId(innerUniqueId: string, negated = false): string {\n const base = `own:${innerUniqueId}`;\n return negated ? `!${base}` : base;\n}\n\n/**\n * Generate a normalized unique ID for a starting condition\n */\nexport function startingUniqueId(negated = false): string {\n return negated ? '!starting' : 'starting';\n}\n\n/**\n * Generate a normalized unique ID for a supports condition\n */\nexport function supportsUniqueId(\n subtype: 'feature' | 'selector',\n condition: string,\n negated = false,\n): string {\n const base = `supports:${subtype}:${condition}`;\n return negated ? `!${base}` : base;\n}\n\n// ============================================================================\n// Condition Creation Helpers\n// ============================================================================\n\n/**\n * Create a modifier condition\n */\nexport function createModifierCondition(\n attribute: string,\n value?: string,\n operator: '=' | '^=' | '$=' | '*=' = '=',\n negated = false,\n raw?: string,\n): ModifierCondition {\n return {\n kind: 'state',\n type: 'modifier',\n negated,\n raw: raw || (value ? `${attribute}${operator}${value}` : attribute),\n uniqueId: modifierUniqueId(attribute, value, operator, negated),\n attribute,\n value,\n operator: value ? operator : undefined,\n };\n}\n\n/**\n * Create a pseudo condition\n */\nexport function createPseudoCondition(\n pseudo: string,\n negated = false,\n raw?: string,\n): PseudoCondition {\n return {\n kind: 'state',\n type: 'pseudo',\n negated,\n raw: raw || pseudo,\n uniqueId: pseudoUniqueId(pseudo, negated),\n pseudo,\n };\n}\n\n/**\n * Create a media dimension condition\n */\nexport function createMediaDimensionCondition(\n dimension: 'width' | 'height' | 'inline-size' | 'block-size',\n lowerBound?: NumericBound,\n upperBound?: NumericBound,\n negated = false,\n raw?: string,\n): MediaCondition {\n return {\n kind: 'state',\n type: 'media',\n subtype: 'dimension',\n negated,\n raw: raw || `@media(${dimension})`,\n uniqueId: mediaUniqueId(\n 'dimension',\n { dimension, lowerBound, upperBound },\n negated,\n ),\n dimension,\n lowerBound,\n upperBound,\n };\n}\n\n/**\n * Create a media feature condition\n */\nexport function createMediaFeatureCondition(\n feature: string,\n featureValue?: string,\n negated = false,\n raw?: string,\n): MediaCondition {\n return {\n kind: 'state',\n type: 'media',\n subtype: 'feature',\n negated,\n raw: raw || `@media(${feature}${featureValue ? `: ${featureValue}` : ''})`,\n uniqueId: mediaUniqueId('feature', { feature, featureValue }, negated),\n feature,\n featureValue,\n };\n}\n\n/**\n * Create a media type condition\n */\nexport function createMediaTypeCondition(\n mediaType: 'print' | 'screen' | 'all' | 'speech',\n negated = false,\n raw?: string,\n): MediaCondition {\n return {\n kind: 'state',\n type: 'media',\n subtype: 'type',\n negated,\n raw: raw || `@media:${mediaType}`,\n uniqueId: mediaUniqueId('type', { mediaType }, negated),\n mediaType,\n };\n}\n\n/**\n * Create a container dimension condition\n */\nexport function createContainerDimensionCondition(\n dimension: 'width' | 'height' | 'inline-size' | 'block-size',\n lowerBound?: NumericBound,\n upperBound?: NumericBound,\n containerName?: string,\n negated = false,\n raw?: string,\n): ContainerCondition {\n return {\n kind: 'state',\n type: 'container',\n subtype: 'dimension',\n negated,\n raw: raw || `@(${containerName ? containerName + ', ' : ''}${dimension})`,\n uniqueId: containerUniqueId(\n 'dimension',\n { containerName, dimension, lowerBound, upperBound },\n negated,\n ),\n containerName,\n dimension,\n lowerBound,\n upperBound,\n };\n}\n\n/**\n * Create a container style condition\n */\nexport function createContainerStyleCondition(\n property: string,\n propertyValue?: string,\n containerName?: string,\n negated = false,\n raw?: string,\n): ContainerCondition {\n return {\n kind: 'state',\n type: 'container',\n subtype: 'style',\n negated,\n raw:\n raw ||\n `@(${containerName ? containerName + ', ' : ''}$${property}${propertyValue ? '=' + propertyValue : ''})`,\n uniqueId: containerUniqueId(\n 'style',\n { containerName, property, propertyValue },\n negated,\n ),\n containerName,\n property,\n propertyValue,\n };\n}\n\n/**\n * Create a container raw function condition (e.g., scroll-state(), style(), etc.)\n * The condition string is passed through to CSS verbatim.\n */\nexport function createContainerRawCondition(\n rawCondition: string,\n containerName?: string,\n negated = false,\n raw?: string,\n): ContainerCondition {\n return {\n kind: 'state',\n type: 'container',\n subtype: 'raw',\n negated,\n raw:\n raw || `@(${containerName ? containerName + ', ' : ''}${rawCondition})`,\n uniqueId: containerUniqueId(\n 'raw',\n { containerName, rawCondition },\n negated,\n ),\n containerName,\n rawCondition,\n };\n}\n\n/**\n * Create a root condition\n */\nexport function createRootCondition(\n innerCondition: ConditionNode,\n negated = false,\n raw?: string,\n): RootCondition {\n const innerUniqueId = getConditionUniqueId(innerCondition);\n return {\n kind: 'state',\n type: 'root',\n negated,\n raw: raw || `@root(${innerUniqueId})`,\n uniqueId: rootUniqueId(innerUniqueId, negated),\n innerCondition,\n };\n}\n\n/**\n * Create a parent condition\n */\nexport function createParentCondition(\n innerCondition: ConditionNode,\n direct: boolean,\n negated = false,\n raw?: string,\n): ParentCondition {\n const innerUniqueId = getConditionUniqueId(innerCondition);\n return {\n kind: 'state',\n type: 'parent',\n negated,\n raw: raw || `@parent(${innerUniqueId})`,\n uniqueId: parentUniqueId(innerUniqueId, direct, negated),\n innerCondition,\n direct,\n };\n}\n\n/**\n * Create an own condition\n */\nexport function createOwnCondition(\n innerCondition: ConditionNode,\n negated = false,\n raw?: string,\n): OwnCondition {\n const innerUniqueId = getConditionUniqueId(innerCondition);\n return {\n kind: 'state',\n type: 'own',\n negated,\n raw: raw || `@own(...)`,\n uniqueId: ownUniqueId(innerUniqueId, negated),\n innerCondition,\n };\n}\n\n/**\n * Create a starting condition\n */\nexport function createStartingCondition(\n negated = false,\n raw?: string,\n): StartingCondition {\n return {\n kind: 'state',\n type: 'starting',\n negated,\n raw: raw || '@starting',\n uniqueId: startingUniqueId(negated),\n };\n}\n\n/**\n * Create a supports condition\n *\n * @param subtype 'feature' for @supports(display: grid), 'selector' for @supports($, :has(*))\n * @param condition The condition string (e.g., \"display: grid\" or \":has(*)\")\n */\nexport function createSupportsCondition(\n subtype: 'feature' | 'selector',\n condition: string,\n negated = false,\n raw?: string,\n): SupportsCondition {\n return {\n kind: 'state',\n type: 'supports',\n subtype,\n negated,\n raw: raw || `@supports(${condition})`,\n uniqueId: supportsUniqueId(subtype, condition, negated),\n condition,\n };\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\nconst uniqueIdCache = new WeakMap<ConditionNode, string>();\n\n/**\n * Get the unique ID for any condition node.\n * Results are memoized via WeakMap since condition nodes are immutable.\n */\nexport function getConditionUniqueId(node: ConditionNode): string {\n const cached = uniqueIdCache.get(node);\n if (cached !== undefined) return cached;\n\n let id: string;\n if (node.kind === 'true') {\n id = 'TRUE';\n } else if (node.kind === 'false') {\n id = 'FALSE';\n } else if (node.kind === 'state') {\n id = node.uniqueId;\n } else if (node.kind === 'compound') {\n const childIds = node.children.map(getConditionUniqueId).sort();\n id = `${node.operator}(${childIds.join(',')})`;\n } else {\n id = 'UNKNOWN';\n }\n\n uniqueIdCache.set(node, id);\n return id;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"conditions.js","names":[],"sources":["../../src/pipeline/conditions.ts"],"sourcesContent":["/**\n * ConditionNode Types and Helpers\n *\n * Core data structures for representing style conditions as an abstract syntax tree.\n * Used throughout the pipeline for parsing, simplification, and CSS generation.\n */\n\n// ============================================================================\n// Core ConditionNode Types\n// ============================================================================\n\n/**\n * Base interface for all state conditions (leaf nodes)\n */\ninterface BaseStateCondition {\n kind: 'state';\n negated: boolean;\n raw: string; // Original string for debugging/caching\n uniqueId: string; // Normalized ID for comparison (built from props)\n}\n\n/**\n * Modifier condition: [data-attr] or [data-attr=\"value\"]\n */\nexport interface ModifierCondition extends BaseStateCondition {\n type: 'modifier';\n attribute: string; // e.g., 'data-theme', 'data-size'\n value?: string; // e.g., 'danger', 'large' (undefined = boolean attr)\n operator?: '=' | '^=' | '$=' | '*='; // Attribute match operator\n}\n\n/**\n * Pseudo-class condition: :hover, :focus-visible\n */\nexport interface PseudoCondition extends BaseStateCondition {\n type: 'pseudo';\n pseudo: string; // e.g., ':hover', ':focus-visible', ':nth-child(2n)'\n}\n\n/**\n * Numeric bound for dimension queries\n */\nexport interface NumericBound {\n value: string; // e.g., '768px', 'calc(var(--gap) * 40)'\n valueNumeric: number | null; // Parsed numeric value for comparison\n inclusive: boolean; // true for >=/<= , false for >/<\n}\n\n/**\n * Media query condition\n */\nexport interface MediaCondition extends BaseStateCondition {\n type: 'media';\n subtype: 'dimension' | 'feature' | 'type';\n\n // For dimension queries: @media(w < 768px), @media(600px <= w < 1200px)\n dimension?: 'width' | 'height' | 'inline-size' | 'block-size';\n lowerBound?: NumericBound; // >= or >\n upperBound?: NumericBound; // <= or <\n\n // For feature queries: @media(prefers-contrast: high)\n feature?: string; // e.g., 'prefers-contrast', 'prefers-color-scheme'\n featureValue?: string; // e.g., 'high', 'dark' (undefined = boolean feature)\n\n // For type queries: @media:print\n mediaType?: 'print' | 'screen' | 'all' | 'speech';\n}\n\n/**\n * Container query condition\n */\nexport interface ContainerCondition extends BaseStateCondition {\n type: 'container';\n subtype: 'dimension' | 'style' | 'raw';\n containerName?: string; // e.g., 'layout', 'sidebar' (undefined = nearest)\n\n // For dimension queries: @(w < 600px), @(layout, w < 600px)\n dimension?: 'width' | 'height' | 'inline-size' | 'block-size';\n lowerBound?: NumericBound;\n upperBound?: NumericBound;\n\n // For style queries: @(layout, $variant=danger), @($theme)\n property?: string; // CSS custom property name (without --)\n propertyValue?: string; // e.g., 'danger' (undefined = existence check)\n\n // For raw function queries: @(scroll-state(stuck: top)), @(style(display: flex))\n rawCondition?: string; // Verbatim CSS condition string\n}\n\n/**\n * Root state condition: @root(theme=dark)\n */\nexport interface RootCondition extends BaseStateCondition {\n type: 'root';\n innerCondition: ConditionNode;\n}\n\n/**\n * Parent state condition: @parent(hovered), @parent(theme=dark, >)\n */\nexport interface ParentCondition extends BaseStateCondition {\n type: 'parent';\n innerCondition: ConditionNode;\n direct: boolean; // true for @parent(..., >) — direct parent only\n}\n\n/**\n * Own state condition: @own(hovered)\n */\nexport interface OwnCondition extends BaseStateCondition {\n type: 'own';\n innerCondition: ConditionNode; // The parsed inner condition\n}\n\n/**\n * Starting style condition: @starting\n */\nexport interface StartingCondition extends BaseStateCondition {\n type: 'starting';\n}\n\n/**\n * Supports query condition: @supports(display: grid), @supports($, :has(*))\n */\nexport interface SupportsCondition extends BaseStateCondition {\n type: 'supports';\n subtype: 'feature' | 'selector';\n // The raw condition string (e.g., \"display: grid\" or \":has(*)\")\n condition: string;\n}\n\n/**\n * Union of all state condition types\n */\nexport type StateCondition =\n | ModifierCondition\n | PseudoCondition\n | MediaCondition\n | ContainerCondition\n | RootCondition\n | ParentCondition\n | OwnCondition\n | StartingCondition\n | SupportsCondition;\n\n/**\n * Compound node: combines conditions with AND/OR\n */\nexport interface CompoundCondition {\n kind: 'compound';\n operator: 'AND' | 'OR';\n children: ConditionNode[];\n}\n\n/**\n * True condition (matches everything)\n */\nexport interface TrueCondition {\n kind: 'true';\n}\n\n/**\n * False condition (matches nothing - skip this rule)\n */\nexport interface FalseCondition {\n kind: 'false';\n}\n\n/**\n * Union of all condition node types\n */\nexport type ConditionNode =\n | StateCondition\n | CompoundCondition\n | TrueCondition\n | FalseCondition;\n\n// ============================================================================\n// Constructor Functions\n// ============================================================================\n\n/**\n * Create a TRUE condition (matches everything)\n */\nexport function trueCondition(): TrueCondition {\n return { kind: 'true' };\n}\n\n/**\n * Create a FALSE condition (matches nothing)\n */\nexport function falseCondition(): FalseCondition {\n return { kind: 'false' };\n}\n\n/**\n * Create an AND compound condition\n */\nexport function and(...children: ConditionNode[]): ConditionNode {\n const filtered: ConditionNode[] = [];\n\n for (const child of children) {\n // Short-circuit on FALSE\n if (child.kind === 'false') {\n return falseCondition();\n }\n // Skip TRUE (identity for AND)\n if (child.kind === 'true') {\n continue;\n }\n // Flatten nested ANDs\n if (child.kind === 'compound' && child.operator === 'AND') {\n filtered.push(...child.children);\n } else {\n filtered.push(child);\n }\n }\n\n if (filtered.length === 0) {\n return trueCondition();\n }\n if (filtered.length === 1) {\n return filtered[0];\n }\n\n return {\n kind: 'compound',\n operator: 'AND',\n children: filtered,\n };\n}\n\n/**\n * Create an OR compound condition\n */\nexport function or(...children: ConditionNode[]): ConditionNode {\n const filtered: ConditionNode[] = [];\n\n for (const child of children) {\n // Short-circuit on TRUE\n if (child.kind === 'true') {\n return trueCondition();\n }\n // Skip FALSE (identity for OR)\n if (child.kind === 'false') {\n continue;\n }\n // Flatten nested ORs\n if (child.kind === 'compound' && child.operator === 'OR') {\n filtered.push(...child.children);\n } else {\n filtered.push(child);\n }\n }\n\n if (filtered.length === 0) {\n return falseCondition();\n }\n if (filtered.length === 1) {\n return filtered[0];\n }\n\n return {\n kind: 'compound',\n operator: 'OR',\n children: filtered,\n };\n}\n\n/**\n * Negate a condition\n */\nexport function not(node: ConditionNode): ConditionNode {\n // NOT(TRUE) = FALSE\n if (node.kind === 'true') {\n return falseCondition();\n }\n\n // NOT(FALSE) = TRUE\n if (node.kind === 'false') {\n return trueCondition();\n }\n\n // NOT(state) = toggle negated flag\n if (node.kind === 'state') {\n return {\n ...node,\n negated: !node.negated,\n uniqueId: node.negated\n ? node.uniqueId.replace(/^!/, '')\n : `!${node.uniqueId}`,\n };\n }\n\n // NOT(AND(a, b, ...)) = OR(NOT(a), NOT(b), ...) - De Morgan's law\n if (node.kind === 'compound' && node.operator === 'AND') {\n return or(...node.children.map((c) => not(c)));\n }\n\n // NOT(OR(a, b, ...)) = AND(NOT(a), NOT(b), ...) - De Morgan's law\n if (node.kind === 'compound' && node.operator === 'OR') {\n return and(...node.children.map((c) => not(c)));\n }\n\n // Fallback - should not reach here\n return node;\n}\n\n// ============================================================================\n// Condition Type Checking\n// ============================================================================\n\n/**\n * Check if a condition is a compound condition\n */\nexport function isCompoundCondition(\n node: ConditionNode,\n): node is CompoundCondition {\n return node.kind === 'compound';\n}\n\n// ============================================================================\n// UniqueId Generation\n// ============================================================================\n\n/**\n * Generate a normalized unique ID for a modifier condition\n */\nexport function modifierUniqueId(\n attribute: string,\n value?: string,\n operator = '=',\n negated = false,\n): string {\n const base = value\n ? `mod:${attribute}${operator}${value}`\n : `mod:${attribute}`;\n return negated ? `!${base}` : base;\n}\n\n/**\n * Generate a normalized unique ID for a pseudo condition\n */\nexport function pseudoUniqueId(pseudo: string, negated = false): string {\n const base = `pseudo:${pseudo}`;\n return negated ? `!${base}` : base;\n}\n\n/**\n * Generate a normalized unique ID for a media condition\n */\nexport function mediaUniqueId(\n subtype: 'dimension' | 'feature' | 'type',\n props: {\n dimension?: string;\n lowerBound?: NumericBound;\n upperBound?: NumericBound;\n feature?: string;\n featureValue?: string;\n mediaType?: string;\n },\n negated = false,\n): string {\n let base: string;\n\n if (subtype === 'dimension') {\n const parts = ['media', 'dim', props.dimension];\n if (props.lowerBound) {\n parts.push(props.lowerBound.inclusive ? '>=' : '>');\n parts.push(props.lowerBound.value);\n }\n if (props.upperBound) {\n parts.push(props.upperBound.inclusive ? '<=' : '<');\n parts.push(props.upperBound.value);\n }\n base = parts.join(':');\n } else if (subtype === 'feature') {\n base = props.featureValue\n ? `media:feat:${props.feature}:${props.featureValue}`\n : `media:feat:${props.feature}`;\n } else {\n base = `media:type:${props.mediaType}`;\n }\n\n return negated ? `!${base}` : base;\n}\n\n/**\n * Generate a normalized unique ID for a container condition\n */\nexport function containerUniqueId(\n subtype: 'dimension' | 'style' | 'raw',\n props: {\n containerName?: string;\n dimension?: string;\n lowerBound?: NumericBound;\n upperBound?: NumericBound;\n property?: string;\n propertyValue?: string;\n rawCondition?: string;\n },\n negated = false,\n): string {\n let base: string;\n const name = props.containerName || '_';\n\n if (subtype === 'dimension') {\n const parts = ['container', 'dim', name, props.dimension];\n if (props.lowerBound) {\n parts.push(props.lowerBound.inclusive ? '>=' : '>');\n parts.push(props.lowerBound.value);\n }\n if (props.upperBound) {\n parts.push(props.upperBound.inclusive ? '<=' : '<');\n parts.push(props.upperBound.value);\n }\n base = parts.join(':');\n } else if (subtype === 'raw') {\n base = `container:raw:${name}:${props.rawCondition}`;\n } else {\n base = props.propertyValue\n ? `container:style:${name}:--${props.property}:${props.propertyValue}`\n : `container:style:${name}:--${props.property}`;\n }\n\n return negated ? `!${base}` : base;\n}\n\n/**\n * Generate a normalized unique ID for a root condition\n */\nexport function rootUniqueId(innerUniqueId: string, negated = false): string {\n const base = `root:${innerUniqueId}`;\n return negated ? `!${base}` : base;\n}\n\n/**\n * Generate a normalized unique ID for a parent condition\n */\nexport function parentUniqueId(\n innerUniqueId: string,\n direct: boolean,\n negated = false,\n): string {\n const base = `parent:${direct ? '>' : ''}${innerUniqueId}`;\n return negated ? `!${base}` : base;\n}\n\n/**\n * Generate a normalized unique ID for an own condition\n */\nexport function ownUniqueId(innerUniqueId: string, negated = false): string {\n const base = `own:${innerUniqueId}`;\n return negated ? `!${base}` : base;\n}\n\n/**\n * Generate a normalized unique ID for a starting condition\n */\nexport function startingUniqueId(negated = false): string {\n return negated ? '!starting' : 'starting';\n}\n\n/**\n * Generate a normalized unique ID for a supports condition\n */\nexport function supportsUniqueId(\n subtype: 'feature' | 'selector',\n condition: string,\n negated = false,\n): string {\n const base = `supports:${subtype}:${condition}`;\n return negated ? `!${base}` : base;\n}\n\n// ============================================================================\n// Condition Creation Helpers\n// ============================================================================\n\n/**\n * Create a modifier condition\n */\nexport function createModifierCondition(\n attribute: string,\n value?: string,\n operator: '=' | '^=' | '$=' | '*=' = '=',\n negated = false,\n raw?: string,\n): ModifierCondition {\n return {\n kind: 'state',\n type: 'modifier',\n negated,\n raw: raw || (value ? `${attribute}${operator}${value}` : attribute),\n uniqueId: modifierUniqueId(attribute, value, operator, negated),\n attribute,\n value,\n operator: value ? operator : undefined,\n };\n}\n\n/**\n * Create a pseudo condition\n */\nexport function createPseudoCondition(\n pseudo: string,\n negated = false,\n raw?: string,\n): PseudoCondition {\n return {\n kind: 'state',\n type: 'pseudo',\n negated,\n raw: raw || pseudo,\n uniqueId: pseudoUniqueId(pseudo, negated),\n pseudo,\n };\n}\n\n/**\n * Create a media dimension condition\n */\nexport function createMediaDimensionCondition(\n dimension: 'width' | 'height' | 'inline-size' | 'block-size',\n lowerBound?: NumericBound,\n upperBound?: NumericBound,\n negated = false,\n raw?: string,\n): MediaCondition {\n return {\n kind: 'state',\n type: 'media',\n subtype: 'dimension',\n negated,\n raw: raw || `@media(${dimension})`,\n uniqueId: mediaUniqueId(\n 'dimension',\n { dimension, lowerBound, upperBound },\n negated,\n ),\n dimension,\n lowerBound,\n upperBound,\n };\n}\n\n/**\n * Create a media feature condition\n */\nexport function createMediaFeatureCondition(\n feature: string,\n featureValue?: string,\n negated = false,\n raw?: string,\n): MediaCondition {\n return {\n kind: 'state',\n type: 'media',\n subtype: 'feature',\n negated,\n raw: raw || `@media(${feature}${featureValue ? `: ${featureValue}` : ''})`,\n uniqueId: mediaUniqueId('feature', { feature, featureValue }, negated),\n feature,\n featureValue,\n };\n}\n\n/**\n * Create a media type condition\n */\nexport function createMediaTypeCondition(\n mediaType: 'print' | 'screen' | 'all' | 'speech',\n negated = false,\n raw?: string,\n): MediaCondition {\n return {\n kind: 'state',\n type: 'media',\n subtype: 'type',\n negated,\n raw: raw || `@media:${mediaType}`,\n uniqueId: mediaUniqueId('type', { mediaType }, negated),\n mediaType,\n };\n}\n\n/**\n * Create a container dimension condition\n */\nexport function createContainerDimensionCondition(\n dimension: 'width' | 'height' | 'inline-size' | 'block-size',\n lowerBound?: NumericBound,\n upperBound?: NumericBound,\n containerName?: string,\n negated = false,\n raw?: string,\n): ContainerCondition {\n return {\n kind: 'state',\n type: 'container',\n subtype: 'dimension',\n negated,\n raw: raw || `@(${containerName ? containerName + ', ' : ''}${dimension})`,\n uniqueId: containerUniqueId(\n 'dimension',\n { containerName, dimension, lowerBound, upperBound },\n negated,\n ),\n containerName,\n dimension,\n lowerBound,\n upperBound,\n };\n}\n\n/**\n * Create a container style condition\n */\nexport function createContainerStyleCondition(\n property: string,\n propertyValue?: string,\n containerName?: string,\n negated = false,\n raw?: string,\n): ContainerCondition {\n return {\n kind: 'state',\n type: 'container',\n subtype: 'style',\n negated,\n raw:\n raw ||\n `@(${containerName ? containerName + ', ' : ''}$${property}${propertyValue ? '=' + propertyValue : ''})`,\n uniqueId: containerUniqueId(\n 'style',\n { containerName, property, propertyValue },\n negated,\n ),\n containerName,\n property,\n propertyValue,\n };\n}\n\n/**\n * Create a container raw function condition (e.g., scroll-state(), style(), etc.)\n * The condition string is passed through to CSS verbatim.\n */\nexport function createContainerRawCondition(\n rawCondition: string,\n containerName?: string,\n negated = false,\n raw?: string,\n): ContainerCondition {\n return {\n kind: 'state',\n type: 'container',\n subtype: 'raw',\n negated,\n raw:\n raw || `@(${containerName ? containerName + ', ' : ''}${rawCondition})`,\n uniqueId: containerUniqueId(\n 'raw',\n { containerName, rawCondition },\n negated,\n ),\n containerName,\n rawCondition,\n };\n}\n\n/**\n * Create a root condition\n */\nexport function createRootCondition(\n innerCondition: ConditionNode,\n negated = false,\n raw?: string,\n): RootCondition {\n const innerUniqueId = getConditionUniqueId(innerCondition);\n return {\n kind: 'state',\n type: 'root',\n negated,\n raw: raw || `@root(${innerUniqueId})`,\n uniqueId: rootUniqueId(innerUniqueId, negated),\n innerCondition,\n };\n}\n\n/**\n * Create a parent condition\n */\nexport function createParentCondition(\n innerCondition: ConditionNode,\n direct: boolean,\n negated = false,\n raw?: string,\n): ParentCondition {\n const innerUniqueId = getConditionUniqueId(innerCondition);\n return {\n kind: 'state',\n type: 'parent',\n negated,\n raw: raw || `@parent(${innerUniqueId})`,\n uniqueId: parentUniqueId(innerUniqueId, direct, negated),\n innerCondition,\n direct,\n };\n}\n\n/**\n * Create an own condition\n */\nexport function createOwnCondition(\n innerCondition: ConditionNode,\n negated = false,\n raw?: string,\n): OwnCondition {\n const innerUniqueId = getConditionUniqueId(innerCondition);\n return {\n kind: 'state',\n type: 'own',\n negated,\n raw: raw || `@own(...)`,\n uniqueId: ownUniqueId(innerUniqueId, negated),\n innerCondition,\n };\n}\n\n/**\n * Create a starting condition\n */\nexport function createStartingCondition(\n negated = false,\n raw?: string,\n): StartingCondition {\n return {\n kind: 'state',\n type: 'starting',\n negated,\n raw: raw || '@starting',\n uniqueId: startingUniqueId(negated),\n };\n}\n\n/**\n * Create a supports condition\n *\n * @param subtype 'feature' for @supports(display: grid), 'selector' for @supports($, :has(*))\n * @param condition The condition string (e.g., \"display: grid\" or \":has(*)\")\n */\nexport function createSupportsCondition(\n subtype: 'feature' | 'selector',\n condition: string,\n negated = false,\n raw?: string,\n): SupportsCondition {\n return {\n kind: 'state',\n type: 'supports',\n subtype,\n negated,\n raw: raw || `@supports(${condition})`,\n uniqueId: supportsUniqueId(subtype, condition, negated),\n condition,\n };\n}\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\nconst uniqueIdCache = new WeakMap<ConditionNode, string>();\n\n/**\n * Get the unique ID for any condition node.\n * Results are memoized via WeakMap since condition nodes are immutable.\n */\nexport function getConditionUniqueId(node: ConditionNode): string {\n const cached = uniqueIdCache.get(node);\n if (cached !== undefined) return cached;\n\n let id: string;\n if (node.kind === 'true') {\n id = 'TRUE';\n } else if (node.kind === 'false') {\n id = 'FALSE';\n } else if (node.kind === 'state') {\n id = node.uniqueId;\n } else if (node.kind === 'compound') {\n const childIds = node.children.map(getConditionUniqueId).sort();\n id = `${node.operator}(${childIds.join(',')})`;\n } else {\n id = 'UNKNOWN';\n }\n\n uniqueIdCache.set(node, id);\n return id;\n}\n"],"mappings":"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"}
@@ -1,6 +1,5 @@
1
1
  import { and, isCompoundCondition, not, trueCondition } from "./conditions.js";
2
2
  import { simplifyCondition } from "./simplify.js";
3
-
4
3
  //#region src/pipeline/exclusive.ts
5
4
  /**
6
5
  * Build exclusive conditions for a list of parsed style entries.
@@ -225,7 +224,7 @@ function expandExclusiveConditionOrs(entry) {
225
224
  }
226
225
  return result;
227
226
  }
228
-
229
227
  //#endregion
230
228
  export { buildExclusiveConditions, expandExclusiveOrs, expandOrConditions, isValueMapping, parseStyleEntries };
229
+
231
230
  //# sourceMappingURL=exclusive.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"exclusive.js","names":[],"sources":["../../src/pipeline/exclusive.ts"],"sourcesContent":["/**\n * Exclusive Condition Builder\n *\n * Transforms parsed style entries into exclusive conditions.\n * Each entry's condition is ANDed with the negation of all higher-priority conditions,\n * ensuring exactly one condition matches at any given time.\n */\n\nimport type { StyleValue } from '../utils/styles';\n\nimport type { ConditionNode } from './conditions';\nimport { and, isCompoundCondition, not, trueCondition } from './conditions';\nimport { simplifyCondition } from './simplify';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Parsed style entry with condition\n */\nexport interface ParsedStyleEntry {\n styleKey: string; // e.g., 'padding', 'fill'\n stateKey: string; // Original key: '', 'compact', '@media(w < 768px)'\n value: StyleValue; // The style value (before handler processing)\n condition: ConditionNode; // Parsed condition tree\n priority: number; // Order in original object (higher = higher priority)\n}\n\n/**\n * Style entry with exclusive condition\n */\nexport interface ExclusiveStyleEntry extends ParsedStyleEntry {\n exclusiveCondition: ConditionNode; // condition & !higherPriorityConditions\n}\n\n// ============================================================================\n// Main Function\n// ============================================================================\n\n/**\n * Build exclusive conditions for a list of parsed style entries.\n *\n * The entries should be ordered by priority (highest priority first).\n *\n * For each entry, we compute:\n * exclusiveCondition = condition & !prior[0] & !prior[1] & ...\n *\n * This ensures exactly one condition matches at any time.\n *\n * Example:\n * Input (ordered highest to lowest priority):\n * A: value1 (priority 2)\n * B: value2 (priority 1)\n * C: value3 (priority 0)\n *\n * Output:\n * A: A\n * B: B & !A\n * C: C & !A & !B\n *\n * @param entries Parsed style entries ordered by priority (highest first)\n * @returns Entries with exclusive conditions, filtered to remove impossible ones\n */\nexport function buildExclusiveConditions(\n entries: ParsedStyleEntry[],\n): ExclusiveStyleEntry[] {\n const result: ExclusiveStyleEntry[] = [];\n const priorConditions: ConditionNode[] = [];\n\n for (const entry of entries) {\n // Build: condition & !prior[0] & !prior[1] & ...\n let exclusive: ConditionNode = entry.condition;\n\n for (const prior of priorConditions) {\n // Skip negating \"always true\" (default state) - it would become \"always false\"\n if (prior.kind !== 'true') {\n exclusive = and(exclusive, not(prior));\n }\n }\n\n // Simplify the exclusive condition\n const simplified = simplifyCondition(exclusive);\n\n // Skip impossible conditions (simplified to FALSE)\n if (simplified.kind === 'false') {\n continue;\n }\n\n result.push({\n ...entry,\n exclusiveCondition: simplified,\n });\n\n // Add non-default conditions to prior list for subsequent entries\n if (entry.condition.kind !== 'true') {\n priorConditions.push(entry.condition);\n }\n }\n\n return result;\n}\n\n/**\n * Parse style entries from a value mapping object.\n *\n * @param styleKey The style key (e.g., 'padding')\n * @param valueMap The value mapping { '': '2x', 'compact': '1x', '@media(w < 768px)': '0.5x' }\n * @param parseCondition Function to parse state keys into conditions\n * @returns Parsed entries ordered by priority (highest first)\n */\nexport function parseStyleEntries(\n styleKey: string,\n valueMap: Record<string, StyleValue>,\n parseCondition: (stateKey: string) => ConditionNode,\n): ParsedStyleEntry[] {\n const entries: ParsedStyleEntry[] = [];\n const keys = Object.keys(valueMap);\n\n keys.forEach((stateKey, index) => {\n const value = valueMap[stateKey];\n const condition =\n stateKey === '' ? trueCondition() : parseCondition(stateKey);\n\n entries.push({\n styleKey,\n stateKey,\n value,\n condition,\n priority: index,\n });\n });\n\n // Reverse so highest priority (last in object) comes first for exclusive building\n // buildExclusiveConditions expects highest priority first\n entries.reverse();\n\n return entries;\n}\n\n/**\n * Check if a value is a style value mapping (object with state keys)\n */\nexport function isValueMapping(\n value: StyleValue | Record<string, StyleValue>,\n): value is Record<string, StyleValue> {\n return (\n value !== null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n !(value instanceof Date)\n );\n}\n\n// ============================================================================\n// OR Expansion\n// ============================================================================\n\n/**\n * Expand OR conditions in parsed entries into multiple exclusive entries.\n *\n * For an entry with condition `A | B | C`, this creates 3 entries:\n * - condition: A\n * - condition: B & !A\n * - condition: C & !A & !B\n *\n * This ensures OR branches are mutually exclusive BEFORE the main\n * exclusive condition building pass.\n *\n * @param entries Parsed entries (may contain OR conditions)\n * @returns Expanded entries with OR branches made exclusive\n */\nexport function expandOrConditions(\n entries: ParsedStyleEntry[],\n): ParsedStyleEntry[] {\n const result: ParsedStyleEntry[] = [];\n\n for (const entry of entries) {\n const expanded = expandSingleEntry(entry);\n result.push(...expanded);\n }\n\n return result;\n}\n\n/**\n * Expand a single entry's OR condition into multiple exclusive entries\n */\nfunction expandSingleEntry(entry: ParsedStyleEntry): ParsedStyleEntry[] {\n const orBranches = collectOrBranches(entry.condition);\n\n // If no OR (single branch), return as-is\n if (orBranches.length <= 1) {\n return [entry];\n }\n\n // Make each OR branch exclusive from prior branches\n const result: ParsedStyleEntry[] = [];\n const priorBranches: ConditionNode[] = [];\n\n for (let i = 0; i < orBranches.length; i++) {\n const branch = orBranches[i];\n\n // Build: branch & !prior[0] & !prior[1] & ...\n let exclusiveBranch: ConditionNode = branch;\n for (const prior of priorBranches) {\n exclusiveBranch = and(exclusiveBranch, not(prior));\n }\n\n // Simplify to detect impossible combinations\n const simplified = simplifyCondition(exclusiveBranch);\n\n // Skip impossible branches\n if (simplified.kind === 'false') {\n priorBranches.push(branch);\n continue;\n }\n\n result.push({\n ...entry,\n stateKey: `${entry.stateKey}[${i}]`, // Mark as expanded branch\n condition: simplified,\n // Keep same priority - all branches from same entry have same priority\n });\n\n priorBranches.push(branch);\n }\n\n return result;\n}\n\n/**\n * Collect top-level OR branches from a condition.\n *\n * For `A | B | C`, returns [A, B, C]\n * For `A & B`, returns [A & B] (single branch)\n * For `A | (B & C)`, returns [A, B & C]\n */\nfunction collectOrBranches(condition: ConditionNode): ConditionNode[] {\n if (condition.kind === 'true' || condition.kind === 'false') {\n return [condition];\n }\n\n if (isCompoundCondition(condition) && condition.operator === 'OR') {\n // Flatten nested ORs\n const branches: ConditionNode[] = [];\n for (const child of condition.children) {\n branches.push(...collectOrBranches(child));\n }\n return branches;\n }\n\n // Not an OR - return as single branch\n return [condition];\n}\n\n// ============================================================================\n// Post-Build OR Expansion (for De Morgan ORs)\n// ============================================================================\n\n/**\n * Expand OR conditions in exclusive entries AFTER buildExclusiveConditions.\n *\n * This handles ORs that arise from De Morgan expansion during negation:\n * !(A & B) = !A | !B\n *\n * These ORs need to be made exclusive to avoid overlapping CSS rules:\n * !A | !B → !A | (A & !B)\n *\n * This is logically equivalent but ensures each branch has proper context.\n *\n * Example:\n * Input: { \"\": V1, \"@supports(...) & :has()\": V2 }\n * V2's exclusive = @supports & :has\n * V1's exclusive = !(@supports & :has) = !@supports | !:has\n *\n * Without this fix: V1 gets two rules:\n * - @supports (not ...) → V1 ✓\n * - :not(:has()) → V1 ✗ (missing @supports context!)\n *\n * With this fix: V1 gets two exclusive rules:\n * - @supports (not ...) → V1 ✓\n * - @supports (...) { :not(:has()) } → V1 ✓ (proper context!)\n */\nexport function expandExclusiveOrs(\n entries: ExclusiveStyleEntry[],\n): ExclusiveStyleEntry[] {\n const result: ExclusiveStyleEntry[] = [];\n\n for (const entry of entries) {\n const expanded = expandExclusiveConditionOrs(entry);\n result.push(...expanded);\n }\n\n return result;\n}\n\n/**\n * Check if a condition involves at-rules (media, container, supports, starting)\n */\nfunction hasAtRuleContext(node: ConditionNode): boolean {\n if (node.kind === 'true' || node.kind === 'false') {\n return false;\n }\n\n if (node.kind === 'state') {\n // These condition types generate at-rules\n return (\n node.type === 'media' ||\n node.type === 'container' ||\n node.type === 'supports' ||\n node.type === 'starting'\n );\n }\n\n if (node.kind === 'compound') {\n return node.children.some(hasAtRuleContext);\n }\n\n return false;\n}\n\n/**\n * Sort OR branches to prioritize at-rule conditions first.\n *\n * This is critical for correct CSS generation. For `!A | !B` where A is at-rule\n * and B is modifier, we want:\n * - Branch 0: !A (at-rule negation - covers \"no @supports/media\" case)\n * - Branch 1: A & !B (modifier negation with at-rule context)\n *\n * If we process in wrong order (!B first), we'd get:\n * - Branch 0: !B (modifier negation WITHOUT at-rule context - WRONG!)\n * - Branch 1: B & !A (at-rule negation with modifier - incomplete coverage)\n */\nfunction sortOrBranchesForExpansion(\n branches: ConditionNode[],\n): ConditionNode[] {\n return [...branches].sort((a, b) => {\n const aHasAtRule = hasAtRuleContext(a);\n const bHasAtRule = hasAtRuleContext(b);\n\n // At-rule conditions come first\n if (aHasAtRule && !bHasAtRule) return -1;\n if (!aHasAtRule && bHasAtRule) return 1;\n\n // Same type - keep original order (stable sort)\n return 0;\n });\n}\n\n/**\n * Expand ORs in a single entry's exclusive condition\n */\nfunction expandExclusiveConditionOrs(\n entry: ExclusiveStyleEntry,\n): ExclusiveStyleEntry[] {\n let orBranches = collectOrBranches(entry.exclusiveCondition);\n\n // If no OR (single branch), return as-is\n if (orBranches.length <= 1) {\n return [entry];\n }\n\n // Sort branches so at-rule conditions come first\n // This ensures proper context inheritance during expansion\n orBranches = sortOrBranchesForExpansion(orBranches);\n\n // Make each OR branch exclusive from prior branches\n const result: ExclusiveStyleEntry[] = [];\n const priorBranches: ConditionNode[] = [];\n\n for (let i = 0; i < orBranches.length; i++) {\n const branch = orBranches[i];\n\n // Build: branch & !prior[0] & !prior[1] & ...\n // This transforms: !A | !B → !A, !B & !!A = !A, (A & !B)\n let exclusiveBranch: ConditionNode = branch;\n for (const prior of priorBranches) {\n exclusiveBranch = and(exclusiveBranch, not(prior));\n }\n\n // Simplify to detect impossible combinations and clean up double negations\n const simplified = simplifyCondition(exclusiveBranch);\n\n // Skip impossible branches\n if (simplified.kind === 'false') {\n priorBranches.push(branch);\n continue;\n }\n\n result.push({\n ...entry,\n stateKey: `${entry.stateKey}[or:${i}]`, // Mark as expanded OR branch\n exclusiveCondition: simplified,\n });\n\n priorBranches.push(branch);\n }\n\n return result;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"exclusive.js","names":[],"sources":["../../src/pipeline/exclusive.ts"],"sourcesContent":["/**\n * Exclusive Condition Builder\n *\n * Transforms parsed style entries into exclusive conditions.\n * Each entry's condition is ANDed with the negation of all higher-priority conditions,\n * ensuring exactly one condition matches at any given time.\n */\n\nimport type { StyleValue } from '../utils/styles';\n\nimport type { ConditionNode } from './conditions';\nimport { and, isCompoundCondition, not, trueCondition } from './conditions';\nimport { simplifyCondition } from './simplify';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Parsed style entry with condition\n */\nexport interface ParsedStyleEntry {\n styleKey: string; // e.g., 'padding', 'fill'\n stateKey: string; // Original key: '', 'compact', '@media(w < 768px)'\n value: StyleValue; // The style value (before handler processing)\n condition: ConditionNode; // Parsed condition tree\n priority: number; // Order in original object (higher = higher priority)\n}\n\n/**\n * Style entry with exclusive condition\n */\nexport interface ExclusiveStyleEntry extends ParsedStyleEntry {\n exclusiveCondition: ConditionNode; // condition & !higherPriorityConditions\n}\n\n// ============================================================================\n// Main Function\n// ============================================================================\n\n/**\n * Build exclusive conditions for a list of parsed style entries.\n *\n * The entries should be ordered by priority (highest priority first).\n *\n * For each entry, we compute:\n * exclusiveCondition = condition & !prior[0] & !prior[1] & ...\n *\n * This ensures exactly one condition matches at any time.\n *\n * Example:\n * Input (ordered highest to lowest priority):\n * A: value1 (priority 2)\n * B: value2 (priority 1)\n * C: value3 (priority 0)\n *\n * Output:\n * A: A\n * B: B & !A\n * C: C & !A & !B\n *\n * @param entries Parsed style entries ordered by priority (highest first)\n * @returns Entries with exclusive conditions, filtered to remove impossible ones\n */\nexport function buildExclusiveConditions(\n entries: ParsedStyleEntry[],\n): ExclusiveStyleEntry[] {\n const result: ExclusiveStyleEntry[] = [];\n const priorConditions: ConditionNode[] = [];\n\n for (const entry of entries) {\n // Build: condition & !prior[0] & !prior[1] & ...\n let exclusive: ConditionNode = entry.condition;\n\n for (const prior of priorConditions) {\n // Skip negating \"always true\" (default state) - it would become \"always false\"\n if (prior.kind !== 'true') {\n exclusive = and(exclusive, not(prior));\n }\n }\n\n // Simplify the exclusive condition\n const simplified = simplifyCondition(exclusive);\n\n // Skip impossible conditions (simplified to FALSE)\n if (simplified.kind === 'false') {\n continue;\n }\n\n result.push({\n ...entry,\n exclusiveCondition: simplified,\n });\n\n // Add non-default conditions to prior list for subsequent entries\n if (entry.condition.kind !== 'true') {\n priorConditions.push(entry.condition);\n }\n }\n\n return result;\n}\n\n/**\n * Parse style entries from a value mapping object.\n *\n * @param styleKey The style key (e.g., 'padding')\n * @param valueMap The value mapping { '': '2x', 'compact': '1x', '@media(w < 768px)': '0.5x' }\n * @param parseCondition Function to parse state keys into conditions\n * @returns Parsed entries ordered by priority (highest first)\n */\nexport function parseStyleEntries(\n styleKey: string,\n valueMap: Record<string, StyleValue>,\n parseCondition: (stateKey: string) => ConditionNode,\n): ParsedStyleEntry[] {\n const entries: ParsedStyleEntry[] = [];\n const keys = Object.keys(valueMap);\n\n keys.forEach((stateKey, index) => {\n const value = valueMap[stateKey];\n const condition =\n stateKey === '' ? trueCondition() : parseCondition(stateKey);\n\n entries.push({\n styleKey,\n stateKey,\n value,\n condition,\n priority: index,\n });\n });\n\n // Reverse so highest priority (last in object) comes first for exclusive building\n // buildExclusiveConditions expects highest priority first\n entries.reverse();\n\n return entries;\n}\n\n/**\n * Check if a value is a style value mapping (object with state keys)\n */\nexport function isValueMapping(\n value: StyleValue | Record<string, StyleValue>,\n): value is Record<string, StyleValue> {\n return (\n value !== null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n !(value instanceof Date)\n );\n}\n\n// ============================================================================\n// OR Expansion\n// ============================================================================\n\n/**\n * Expand OR conditions in parsed entries into multiple exclusive entries.\n *\n * For an entry with condition `A | B | C`, this creates 3 entries:\n * - condition: A\n * - condition: B & !A\n * - condition: C & !A & !B\n *\n * This ensures OR branches are mutually exclusive BEFORE the main\n * exclusive condition building pass.\n *\n * @param entries Parsed entries (may contain OR conditions)\n * @returns Expanded entries with OR branches made exclusive\n */\nexport function expandOrConditions(\n entries: ParsedStyleEntry[],\n): ParsedStyleEntry[] {\n const result: ParsedStyleEntry[] = [];\n\n for (const entry of entries) {\n const expanded = expandSingleEntry(entry);\n result.push(...expanded);\n }\n\n return result;\n}\n\n/**\n * Expand a single entry's OR condition into multiple exclusive entries\n */\nfunction expandSingleEntry(entry: ParsedStyleEntry): ParsedStyleEntry[] {\n const orBranches = collectOrBranches(entry.condition);\n\n // If no OR (single branch), return as-is\n if (orBranches.length <= 1) {\n return [entry];\n }\n\n // Make each OR branch exclusive from prior branches\n const result: ParsedStyleEntry[] = [];\n const priorBranches: ConditionNode[] = [];\n\n for (let i = 0; i < orBranches.length; i++) {\n const branch = orBranches[i];\n\n // Build: branch & !prior[0] & !prior[1] & ...\n let exclusiveBranch: ConditionNode = branch;\n for (const prior of priorBranches) {\n exclusiveBranch = and(exclusiveBranch, not(prior));\n }\n\n // Simplify to detect impossible combinations\n const simplified = simplifyCondition(exclusiveBranch);\n\n // Skip impossible branches\n if (simplified.kind === 'false') {\n priorBranches.push(branch);\n continue;\n }\n\n result.push({\n ...entry,\n stateKey: `${entry.stateKey}[${i}]`, // Mark as expanded branch\n condition: simplified,\n // Keep same priority - all branches from same entry have same priority\n });\n\n priorBranches.push(branch);\n }\n\n return result;\n}\n\n/**\n * Collect top-level OR branches from a condition.\n *\n * For `A | B | C`, returns [A, B, C]\n * For `A & B`, returns [A & B] (single branch)\n * For `A | (B & C)`, returns [A, B & C]\n */\nfunction collectOrBranches(condition: ConditionNode): ConditionNode[] {\n if (condition.kind === 'true' || condition.kind === 'false') {\n return [condition];\n }\n\n if (isCompoundCondition(condition) && condition.operator === 'OR') {\n // Flatten nested ORs\n const branches: ConditionNode[] = [];\n for (const child of condition.children) {\n branches.push(...collectOrBranches(child));\n }\n return branches;\n }\n\n // Not an OR - return as single branch\n return [condition];\n}\n\n// ============================================================================\n// Post-Build OR Expansion (for De Morgan ORs)\n// ============================================================================\n\n/**\n * Expand OR conditions in exclusive entries AFTER buildExclusiveConditions.\n *\n * This handles ORs that arise from De Morgan expansion during negation:\n * !(A & B) = !A | !B\n *\n * These ORs need to be made exclusive to avoid overlapping CSS rules:\n * !A | !B → !A | (A & !B)\n *\n * This is logically equivalent but ensures each branch has proper context.\n *\n * Example:\n * Input: { \"\": V1, \"@supports(...) & :has()\": V2 }\n * V2's exclusive = @supports & :has\n * V1's exclusive = !(@supports & :has) = !@supports | !:has\n *\n * Without this fix: V1 gets two rules:\n * - @supports (not ...) → V1 ✓\n * - :not(:has()) → V1 ✗ (missing @supports context!)\n *\n * With this fix: V1 gets two exclusive rules:\n * - @supports (not ...) → V1 ✓\n * - @supports (...) { :not(:has()) } → V1 ✓ (proper context!)\n */\nexport function expandExclusiveOrs(\n entries: ExclusiveStyleEntry[],\n): ExclusiveStyleEntry[] {\n const result: ExclusiveStyleEntry[] = [];\n\n for (const entry of entries) {\n const expanded = expandExclusiveConditionOrs(entry);\n result.push(...expanded);\n }\n\n return result;\n}\n\n/**\n * Check if a condition involves at-rules (media, container, supports, starting)\n */\nfunction hasAtRuleContext(node: ConditionNode): boolean {\n if (node.kind === 'true' || node.kind === 'false') {\n return false;\n }\n\n if (node.kind === 'state') {\n // These condition types generate at-rules\n return (\n node.type === 'media' ||\n node.type === 'container' ||\n node.type === 'supports' ||\n node.type === 'starting'\n );\n }\n\n if (node.kind === 'compound') {\n return node.children.some(hasAtRuleContext);\n }\n\n return false;\n}\n\n/**\n * Sort OR branches to prioritize at-rule conditions first.\n *\n * This is critical for correct CSS generation. For `!A | !B` where A is at-rule\n * and B is modifier, we want:\n * - Branch 0: !A (at-rule negation - covers \"no @supports/media\" case)\n * - Branch 1: A & !B (modifier negation with at-rule context)\n *\n * If we process in wrong order (!B first), we'd get:\n * - Branch 0: !B (modifier negation WITHOUT at-rule context - WRONG!)\n * - Branch 1: B & !A (at-rule negation with modifier - incomplete coverage)\n */\nfunction sortOrBranchesForExpansion(\n branches: ConditionNode[],\n): ConditionNode[] {\n return [...branches].sort((a, b) => {\n const aHasAtRule = hasAtRuleContext(a);\n const bHasAtRule = hasAtRuleContext(b);\n\n // At-rule conditions come first\n if (aHasAtRule && !bHasAtRule) return -1;\n if (!aHasAtRule && bHasAtRule) return 1;\n\n // Same type - keep original order (stable sort)\n return 0;\n });\n}\n\n/**\n * Expand ORs in a single entry's exclusive condition\n */\nfunction expandExclusiveConditionOrs(\n entry: ExclusiveStyleEntry,\n): ExclusiveStyleEntry[] {\n let orBranches = collectOrBranches(entry.exclusiveCondition);\n\n // If no OR (single branch), return as-is\n if (orBranches.length <= 1) {\n return [entry];\n }\n\n // Sort branches so at-rule conditions come first\n // This ensures proper context inheritance during expansion\n orBranches = sortOrBranchesForExpansion(orBranches);\n\n // Make each OR branch exclusive from prior branches\n const result: ExclusiveStyleEntry[] = [];\n const priorBranches: ConditionNode[] = [];\n\n for (let i = 0; i < orBranches.length; i++) {\n const branch = orBranches[i];\n\n // Build: branch & !prior[0] & !prior[1] & ...\n // This transforms: !A | !B → !A, !B & !!A = !A, (A & !B)\n let exclusiveBranch: ConditionNode = branch;\n for (const prior of priorBranches) {\n exclusiveBranch = and(exclusiveBranch, not(prior));\n }\n\n // Simplify to detect impossible combinations and clean up double negations\n const simplified = simplifyCondition(exclusiveBranch);\n\n // Skip impossible branches\n if (simplified.kind === 'false') {\n priorBranches.push(branch);\n continue;\n }\n\n result.push({\n ...entry,\n stateKey: `${entry.stateKey}[or:${i}]`, // Mark as expanded OR branch\n exclusiveCondition: simplified,\n });\n\n priorBranches.push(branch);\n }\n\n return result;\n}\n"],"mappings":"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"}
@@ -3,13 +3,12 @@ import { stringifyStyles } from "../utils/styles.js";
3
3
  import { createStyle } from "../styles/createStyle.js";
4
4
  import { STYLE_HANDLER_MAP } from "../styles/index.js";
5
5
  import { createStateParserContext, extractLocalPredefinedStates } from "../states/index.js";
6
- import { and, falseCondition, not, or, trueCondition } from "./conditions.js";
6
+ import { and, or, trueCondition } from "./conditions.js";
7
7
  import { simplifyCondition } from "./simplify.js";
8
8
  import { buildExclusiveConditions, expandExclusiveOrs, expandOrConditions, isValueMapping, parseStyleEntries } from "./exclusive.js";
9
9
  import { branchToCSS, buildAtRulesFromVariant, conditionToCSS, mergeVariantsIntoSelectorGroups, optimizeGroups, parentGroupsToCSS, rootGroupsToCSS, selectorGroupToCSS } from "./materialize.js";
10
10
  import { emitWarning } from "./warnings.js";
11
11
  import { parseStateKey } from "./parseStateKey.js";
12
-
13
12
  //#region src/pipeline/index.ts
14
13
  /**
15
14
  * Tasty Style Rendering Pipeline
@@ -703,7 +702,7 @@ function renderStyles(styles, classNameOrSelector, options, pipelineCacheKey) {
703
702
  startingStyle: r.startingStyle
704
703
  })) };
705
704
  }
706
-
707
705
  //#endregion
708
706
  export { clearPipelineCache, hasPipelineCacheEntry, isSelector, renderStyles };
707
+
709
708
  //# sourceMappingURL=index.js.map