@tenphi/tasty 0.0.0-snapshot.649b5ba → 0.0.0-snapshot.a3ac603

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.
package/README.md CHANGED
@@ -24,9 +24,10 @@ On top of that foundation, Tasty gives you a concise, CSS-like DSL with design t
24
24
  ## Why Tasty
25
25
 
26
26
  - **Deterministic at any scale** — Exclusive selector generation eliminates the entire class of cascade/specificity bugs. Every state combination resolves to exactly one CSS rule per property. Refactor freely.
27
+ - **AI-friendly by design** — Style definitions are declarative, self-contained, and structurally consistent. AI tools can read, understand, and refactor even advanced state bindings as confidently as a human — because there's no hidden cascade logic or implicit ordering to second-guess.
27
28
  - **DSL that feels like CSS** — Property names you already know (`padding`, `color`, `display`) with syntax sugar that removes boilerplate. Learn the DSL in minutes, not days.
28
29
  - **Design-system native** — Color tokens (`#primary`), spacing units (`2x`), typography presets (`h1`, `t2`), border radius (`1r`), and recipes are first-class primitives, not afterthoughts.
29
- - **Full modern CSS coverage** — Media queries, container queries, `@supports`, `:has()`, `@starting-style`, `@property`, keyframes, boolean state logic with `&`, `|`, `!` operators. If CSS can do it, Tasty can express it concisely.
30
+ - **Near-complete modern CSS coverage** — Media queries, container queries, `@supports`, `:has()`, `@starting-style`, `@property`, `@keyframes`, etc. Some features that don't fit Tasty's component model (such as `@layer` and `!important`) are intentionally omitted, but real-world use cases are covered almost completely.
30
31
  - **Runtime or zero-runtime — your call** — Use `tasty()` for dynamic React components with runtime injection, or `tastyStatic()` with the Babel plugin for zero-runtime CSS extraction. Same DSL, same tokens, same output.
31
32
  - **Only generate what is used** — In runtime mode, Tasty injects CSS on demand for mounted components/variants, so your app avoids shipping style rules for UI states that are never rendered.
32
33
  - **Runtime performance that holds at scale** — The runtime path is tested against enterprise-scale applications and tuned with multi-level caching, chunk-level style reuse, style garbage collection, and a dedicated injector.
@@ -133,9 +134,13 @@ Predefined states turn complex selector logic into single tokens. Use `@mobile`
133
134
 
134
135
  This is the core idea that makes everything else possible.
135
136
 
136
- Traditional CSS uses the cascade to resolve conflicts: when multiple selectors match, the one with the highest specificity wins, or — if specificity is equal — the last one in source order wins. This makes styles inherently fragile. Reordering imports, adding a new media query, or composing components from different libraries can silently break styling.
137
+ Traditional CSS has two structural problems.
137
138
 
138
- Tasty takes a fundamentally different approach: **every state mapping compiles into selectors that are guaranteed to never overlap.**
139
+ First, the **cascade** resolves conflicts by specificity and source order: when multiple selectors match, the one with the highest specificity wins, or — if specificity is equal — the last one in source order wins. That makes styles inherently fragile. Reordering imports, adding a media query, or composing components from different libraries can silently break styling.
140
+
141
+ Second, **authoring selectors that capture real-world state logic is fundamentally hard.** A single state like "dark mode" may depend on a root attribute, an OS preference, or both — each branch needing its own selector, proper negation of competing branches, and correct `@media` nesting. The example below shows the CSS you'd write by hand for just *one* property with *one* state. Scale that across dozens of properties, then add breakpoints and container queries, and the selector logic quickly becomes unmanageable.
142
+
143
+ Tasty solves both problems at once: **every state mapping compiles into mutually exclusive selectors.**
139
144
 
140
145
  ```tsx
141
146
  const Text = tasty({
@@ -180,7 +185,9 @@ If `@dark` expands to `@root(schema=dark) | (!@root(schema) & @media(prefers-col
180
185
  }
181
186
  ```
182
187
 
183
- Every rule is guarded by the negation of all higher-priority rules. No two rules can ever match simultaneously. No specificity arithmetic. No source-order dependence. Components compose and extend without ever colliding.
188
+ Every rule is guarded by the negation of higher-priority rules. No two rules can match at the same time. No specificity arithmetic. No source-order dependence. Components compose and extend without collisions.
189
+
190
+ By absorbing selector complexity, Tasty makes advanced CSS patterns practical again — nested container queries, multi-condition `@supports` gates, and combined root-state/media branches. You stay in pure CSS instead of relying on JavaScript workarounds, so the browser can optimize layout, painting, and transitions natively. Tasty doesn't limit CSS; it unlocks its full potential by removing the complexity that held teams back.
184
191
 
185
192
  ## Capabilities
186
193
 
@@ -412,11 +419,12 @@ If you choose the runtime approach, performance is usually a non-issue in practi
412
419
 
413
420
  | Import | Description | Platform |
414
421
  |--------|-------------|----------|
415
- | `@tenphi/tasty` | Runtime style engine | Browser |
416
- | `@tenphi/tasty/static` | Zero-runtime static styles | Browser |
417
- | `@tenphi/tasty/babel-plugin` | Babel plugin for CSS extraction | Node |
422
+ | `@tenphi/tasty` | Runtime style engine (`tasty`, hooks, `configure`) | Browser |
423
+ | `@tenphi/tasty/static` | Zero-runtime static styles (`tastyStatic`) | Browser |
424
+ | `@tenphi/tasty/core` | Lower-level internals (config, parser, pipeline, injector, style handlers) for tooling and advanced use | Browser / Node |
425
+ | `@tenphi/tasty/babel-plugin` | Babel plugin for zero-runtime CSS extraction | Node |
418
426
  | `@tenphi/tasty/zero` | Programmatic extraction API | Node |
419
- | `@tenphi/tasty/next` | Next.js integration | Node |
427
+ | `@tenphi/tasty/next` | Next.js integration wrapper | Node |
420
428
 
421
429
  ## Ecosystem
422
430
 
@@ -455,14 +463,21 @@ const tokens = theme.tasty(); // Ready-to-use Tasty tokens
455
463
 
456
464
  Syntax highlighting for Tasty styles in TypeScript, TSX, JavaScript, and JSX. Highlights color tokens, custom units, state keys, presets, and style properties inside `tasty()`, `tastyStatic()`, and related APIs.
457
465
 
466
+ <p align="center">
467
+ <img src="assets/tasty-vscode-highlight.png" width="512" alt="Tasty VS Code syntax highlighting example">
468
+ </p>
469
+
458
470
  ### [Cube UI Kit](https://github.com/cube-js/cube-ui-kit)
459
471
 
460
472
  Open-source React UI kit built on Tasty + React Aria. 100+ production components proving Tasty works at design-system scale. A reference implementation and a ready-to-use component library.
461
473
 
462
474
  ## Documentation
463
475
 
464
- - **[Runtime API (tasty)](docs/tasty.md)** — Full runtime styling documentation: component creation, state mappings, sub-elements, variants, hooks, configuration, and style property reference
476
+ - **[Runtime API (tasty)](docs/tasty.md)** — Full runtime styling documentation: component creation, state mappings, sub-elements, variants, hooks, and configuration
477
+ - **[Style Properties](docs/styles.md)** — Complete reference for all enhanced style properties: syntax, values, modifiers, and recommendations
465
478
  - **[Zero Runtime (tastyStatic)](docs/tasty-static.md)** — Build-time static styling: Babel plugin setup, Next.js integration, and static style patterns
479
+ - **[Style Injector](docs/injector.md)** — Internal CSS injection engine: `inject()`, `injectGlobal()`, `injectRawCSS()`, `keyframes()`, deduplication, reference counting, cleanup, SSR support, and Shadow DOM
480
+ - **[Debug Utilities](docs/debug.md)** — Runtime CSS inspection via `tastyDebug`: CSS extraction, element inspection, cache metrics, chunk breakdown, and performance monitoring
466
481
 
467
482
  ## License
468
483
 
package/dist/index.d.ts CHANGED
@@ -37,4 +37,12 @@ import { TypographyPreset } from "./tokens/typography.js";
37
37
  import { generateTypographyTokens } from "./utils/typography.js";
38
38
  import { tastyDebug } from "./debug.js";
39
39
  import "./core/index.js";
40
- export { type AllBaseProps, type AllBasePropsWithMods, AtRuleContext, BASE_STYLES, BLOCK_INNER_STYLES, BLOCK_OUTER_STYLES, BLOCK_STYLES, type BaseProps, type BasePropsWithoutChildren, BaseStyleProps, BlockInnerStyleProps, BlockOuterStyleProps, BlockStyleProps, Bucket, CHUNK_NAMES, COLOR_STYLES, COMPUTE_FUNC_MAP, CONTAINER_STYLES, CSSMap, CSSProperties, CUSTOM_UNITS, CacheMetrics, ChunkInfo, ChunkName, ColorStyleProps, ComputeModel, ConditionNode, ContainerStyleProps, DIMENSION_STYLES, DIRECTIONS, DimensionStyleProps, DisposeFunction, Element, type ElementsDefinition, FLOW_STYLES, FlowStyleProps, GlobalStyledProps, INNER_STYLES, InjectResult, InnerStyleProps, KeyframesCacheEntry, KeyframesInfo, KeyframesResult, KeyframesSteps, ModValue, Mods, NoType, NotSelector, OUTER_STYLES, OuterStyleProps, POSITION_STYLES, ParseStateKeyOptions, ParsedAdvancedState, ParsedColor, ParserOptions, PositionStyleProps, ProcessedStyle, PropertyDefinition, PropertyOptions, Props, RawCSSResult, RawStyleHandler, RecipeStyles, RenderResult, RootRegistry, RuleInfo, STATE_OPERATORS, STATE_OPERATOR_LIST, STYLE_TO_CHUNK, Selector, SheetInfo, SheetManager, ShortGridStyles, StateParserContext, StyleDetails, StyleDetailsPart, StyleHandler, StyleHandlerDefinition, StyleHandlerResult, StyleInjector, StyleInjectorConfig, StyleMap, StyleParser, StylePropValue, StyleResult, StyleRule, StyleStateData, StyleStateDataList, StyleStateDataListMap, StyleStateMap, StyleValue, StyleValueStateMap, Styles, StylesInterface, StylesWithoutSelectors, type SubElementDefinition, type SubElementProps, SuffixForSelector, TEXT_STYLES, TagName, TastyConfig, type TastyElementOptions, type TastyElementProps, TastyExtensionConfig, TastyNamedColors, TastyPlugin, TastyPluginFactory, TastyPresetNames, type TastyProps, TastyThemeNames, TextStyleProps, TokenValue, Tokens, TypographyPreset, UnitHandler, type UsePropertyOptions, type UseStylesOptions, type UseStylesResult, type VariantMap, type WithVariant, allocateClassName, buildAtRuleContext, categorizeStyleKeys, cleanup, color, computeState, configure, createInjector, createStateParserContext, customFunc, deprecationWarning, destroy, dotize, extendStyles, extractStyles, filterBaseProps, filterMods, generateTypographyTokens, getConfig, getCssText, getCssTextForNode, getDisplayName, getGlobalFuncs, getGlobalKeyframes, getGlobalParser, getGlobalPredefinedStates, getGlobalPredefinedTokens, getGlobalRecipes, getIsTestEnvironment, getModSelector, getRawCSSText, getRgbValuesFromRgbaString, hasGlobalKeyframes, hasGlobalRecipes, hasStylesGenerated, hexToRgb, hslToRgbValues, inject, injectGlobal, injectRawCSS, injector, isAdvancedStateToken, isConfigLocked, isPropertyDefined, isSelector, isTestEnvironment, keyframes, mergeStyles, _modAttrs as modAttrs, normalizeColorTokenValue, okhslFunc, okhslPlugin, parseColor, parseStateKey, parseStateNotation, parseStyle, processTokens, property, renderStyles, resetConfig, resetGlobalPredefinedTokens, resolveRecipes, setGlobalPredefinedStates, setGlobalPredefinedTokens, strToRgb, stringifyStyles, stringifyTokens, styleHandlers, styleStateMapToStyleStateDataList, tasty, tastyDebug, useGlobalStyles, useKeyframes, useProperty, useRawCSS, useStyles, warn };
40
+ import { CSSProperties as CSSProperties$1 } from "react";
41
+
42
+ //#region src/index.d.ts
43
+ declare module './utils/css-types' {
44
+ interface CSSProperties extends CSSProperties$1 {}
45
+ }
46
+ //#endregion
47
+ export { type AllBaseProps, type AllBasePropsWithMods, AtRuleContext, BASE_STYLES, BLOCK_INNER_STYLES, BLOCK_OUTER_STYLES, BLOCK_STYLES, type BaseProps, type BasePropsWithoutChildren, BaseStyleProps, BlockInnerStyleProps, BlockOuterStyleProps, BlockStyleProps, Bucket, CHUNK_NAMES, COLOR_STYLES, COMPUTE_FUNC_MAP, CONTAINER_STYLES, CSSMap, CSSProperties, CUSTOM_UNITS, CacheMetrics, ChunkInfo, ChunkName, ColorStyleProps, ComputeModel, ConditionNode, ContainerStyleProps, DIMENSION_STYLES, DIRECTIONS, DimensionStyleProps, DisposeFunction, Element, type ElementsDefinition, FLOW_STYLES, FlowStyleProps, GlobalStyledProps, INNER_STYLES, InjectResult, InnerStyleProps, KeyframesCacheEntry, KeyframesInfo, KeyframesResult, KeyframesSteps, ModValue, Mods, NoType, NotSelector, OUTER_STYLES, OuterStyleProps, POSITION_STYLES, ParseStateKeyOptions, ParsedAdvancedState, ParsedColor, ParserOptions, PositionStyleProps, ProcessedStyle, PropertyDefinition, PropertyOptions, Props, RawCSSResult, RawStyleHandler, RecipeStyles, RenderResult, RootRegistry, RuleInfo, STATE_OPERATORS, STATE_OPERATOR_LIST, STYLE_TO_CHUNK, Selector, SheetInfo, SheetManager, ShortGridStyles, StateParserContext, StyleDetails, StyleDetailsPart, StyleHandler, StyleHandlerDefinition, StyleHandlerResult, StyleInjector, StyleInjectorConfig, StyleMap, StyleParser, StylePropValue, StyleResult, StyleRule, StyleStateData, StyleStateDataList, StyleStateDataListMap, StyleStateMap, StyleValue, StyleValueStateMap, Styles, StylesInterface, StylesWithoutSelectors, type SubElementDefinition, type SubElementProps, SuffixForSelector, TEXT_STYLES, TagName, TastyConfig, type TastyElementOptions, type TastyElementProps, TastyExtensionConfig, TastyNamedColors, TastyPlugin, TastyPluginFactory, TastyPresetNames, type TastyProps, TastyThemeNames, TextStyleProps, TokenValue, Tokens, TypographyPreset, UnitHandler, type UsePropertyOptions, type UseStylesOptions, type UseStylesResult, type VariantMap, type WithVariant, allocateClassName, buildAtRuleContext, categorizeStyleKeys, cleanup, color, computeState, configure, createInjector, createStateParserContext, customFunc, deprecationWarning, destroy, dotize, extendStyles, extractStyles, filterBaseProps, filterMods, generateTypographyTokens, getConfig, getCssText, getCssTextForNode, getDisplayName, getGlobalFuncs, getGlobalKeyframes, getGlobalParser, getGlobalPredefinedStates, getGlobalPredefinedTokens, getGlobalRecipes, getIsTestEnvironment, getModSelector, getRawCSSText, getRgbValuesFromRgbaString, hasGlobalKeyframes, hasGlobalRecipes, hasStylesGenerated, hexToRgb, hslToRgbValues, inject, injectGlobal, injectRawCSS, injector, isAdvancedStateToken, isConfigLocked, isPropertyDefined, isSelector, isTestEnvironment, keyframes, mergeStyles, _modAttrs as modAttrs, normalizeColorTokenValue, okhslFunc, okhslPlugin, parseColor, parseStateKey, parseStateNotation, parseStyle, processTokens, property, renderStyles, resetConfig, resetGlobalPredefinedTokens, resolveRecipes, setGlobalPredefinedStates, setGlobalPredefinedTokens, strToRgb, stringifyStyles, stringifyTokens, styleHandlers, styleStateMapToStyleStateDataList, tasty, tastyDebug, useGlobalStyles, useKeyframes, useProperty, useRawCSS, useStyles, warn };
48
+ //# sourceMappingURL=index.d.ts.map
@@ -73,7 +73,7 @@ interface RootCondition extends BaseStateCondition {
73
73
  innerCondition: ConditionNode;
74
74
  }
75
75
  /**
76
- * Parent state condition: @parent(hovered), @parent(theme=dark >)
76
+ * Parent state condition: @parent(hovered), @parent(theme=dark, >)
77
77
  */
78
78
  interface ParentCondition extends BaseStateCondition {
79
79
  type: 'parent';
@@ -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\n/**\n * Get the unique ID for any condition node\n */\nexport function getConditionUniqueId(node: ConditionNode): string {\n if (node.kind === 'true') {\n return 'TRUE';\n }\n if (node.kind === 'false') {\n return 'FALSE';\n }\n if (node.kind === 'state') {\n return node.uniqueId;\n }\n if (node.kind === 'compound') {\n const childIds = node.children.map(getConditionUniqueId).sort();\n return `${node.operator}(${childIds.join(',')})`;\n }\n return 'UNKNOWN';\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\n/**\n * Get the unique ID for any condition node\n */\nexport function getConditionUniqueId(node: ConditionNode): string {\n if (node.kind === 'true') {\n return 'TRUE';\n }\n if (node.kind === 'false') {\n return 'FALSE';\n }\n if (node.kind === 'state') {\n return node.uniqueId;\n }\n if (node.kind === 'compound') {\n const childIds = node.children.map(getConditionUniqueId).sort();\n return `${node.operator}(${childIds.join(',')})`;\n }\n return 'UNKNOWN';\n}\n"],"mappings":"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"}
@@ -6,7 +6,7 @@ import { STYLE_HANDLER_MAP } from "../styles/index.js";
6
6
  import { and, falseCondition, not, or, trueCondition } from "./conditions.js";
7
7
  import { simplifyCondition } from "./simplify.js";
8
8
  import { buildExclusiveConditions, expandExclusiveOrs, expandOrConditions, isValueMapping, parseStyleEntries } from "./exclusive.js";
9
- import { buildAtRulesFromVariant, conditionToCSS, modifierToCSS, parentConditionsToCSS, pseudoToCSS, rootConditionsToCSS, selectorConditionToCSS } from "./materialize.js";
9
+ import { buildAtRulesFromVariant, conditionToCSS, modifierToCSS, parentGroupsToCSS, pseudoToCSS, rootConditionsToCSS, selectorConditionToCSS } from "./materialize.js";
10
10
  import { parseStateKey } from "./parseStateKey.js";
11
11
 
12
12
  //#region src/pipeline/index.ts
@@ -556,7 +556,7 @@ function buildSelectorFromVariant(variant, selectorSuffix) {
556
556
  let selector = "";
557
557
  for (const mod of variant.modifierConditions) selector += modifierToCSS(mod);
558
558
  for (const pseudo of variant.pseudoConditions) selector += pseudoToCSS(pseudo);
559
- if (variant.parentConditions.length > 0) selector += parentConditionsToCSS(variant.parentConditions, variant.parentDirect);
559
+ if (variant.parentGroups.length > 0) selector += parentGroupsToCSS(variant.parentGroups);
560
560
  selector += selectorSuffix;
561
561
  for (const own of variant.ownConditions) selector += selectorConditionToCSS(own);
562
562
  return selector;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/pipeline/index.ts"],"sourcesContent":["/**\n * Tasty Style Rendering Pipeline\n *\n * This is the main entrypoint for the new pipeline implementation.\n * It implements the complete flow from style objects to CSS rules.\n *\n * Pipeline stages:\n * 1. PARSE CONDITIONS - Parse state keys into ConditionNode trees\n * 2. BUILD EXCLUSIVE CONDITIONS - AND with negation of higher-priority conditions\n * 3. SIMPLIFY CONDITIONS - Apply boolean algebra, detect contradictions\n * 4. GROUP BY HANDLER - Collect styles per handler, compute combinations\n * 5. COMPUTE CSS VALUES - Call handlers to get CSS declarations\n * 6. MERGE BY VALUE - Merge rules with identical CSS output\n * 7. MATERIALIZE CSS - Convert conditions to CSS selectors + at-rules\n */\n\nimport { Lru } from '../parser/lru';\nimport type { StateParserContext } from '../states';\nimport {\n createStateParserContext,\n extractLocalPredefinedStates,\n} from '../states';\nimport { createStyle, STYLE_HANDLER_MAP } from '../styles';\nimport type { Styles } from '../styles/types';\nimport type {\n StyleHandler,\n StyleMap,\n StyleValue,\n StyleValueStateMap,\n} from '../utils/styles';\nimport { stringifyStyles } from '../utils/styles';\n\nimport type { ConditionNode } from './conditions';\nimport { and, or, trueCondition } from './conditions';\nimport type { ExclusiveStyleEntry } from './exclusive';\nimport {\n buildExclusiveConditions,\n expandExclusiveOrs,\n expandOrConditions,\n isValueMapping,\n parseStyleEntries,\n} from './exclusive';\nimport type { CSSRule, SelectorVariant } from './materialize';\nimport {\n buildAtRulesFromVariant,\n conditionToCSS,\n modifierToCSS,\n parentConditionsToCSS,\n pseudoToCSS,\n rootConditionsToCSS,\n selectorConditionToCSS,\n} from './materialize';\nimport { parseStateKey } from './parseStateKey';\nimport { simplifyCondition } from './simplify';\n\n// ============================================================================\n// Types (compatible with old renderStyles API)\n// ============================================================================\n\n/**\n * Matches the old StyleResult interface for backward compatibility\n */\nexport interface StyleResult {\n selector: string;\n declarations: string;\n atRules?: string[];\n needsClassName?: boolean;\n rootPrefix?: string;\n}\n\n/**\n * Matches the old RenderResult interface for backward compatibility\n */\nexport interface RenderResult {\n rules: StyleResult[];\n className?: string;\n}\n\nexport interface PipelineResult {\n rules: CSSRule[];\n className?: string;\n}\n\ninterface ComputedRule {\n condition: ConditionNode;\n declarations: Record<string, string>;\n selectorSuffix: string;\n}\n\n// ============================================================================\n// Caching\n// ============================================================================\n\nconst pipelineCache = new Lru<string, CSSRule[]>(5000);\n\n// ============================================================================\n// Main Pipeline Function\n// ============================================================================\n\n/**\n * Render styles using the new pipeline.\n *\n * This is the main entrypoint that implements the complete flow.\n */\nexport function renderStylesPipeline(\n styles?: Styles,\n className?: string,\n): PipelineResult {\n if (!styles) {\n return { rules: [], className };\n }\n\n // Check cache\n const cacheKey = stringifyStyles(styles);\n let rules = pipelineCache.get(cacheKey);\n\n if (!rules) {\n // Create parser context\n const parserContext = createStateParserContext(styles);\n\n // Run pipeline\n rules = runPipeline(styles, parserContext);\n\n // Cache result\n pipelineCache.set(cacheKey, rules);\n }\n\n // If no className, rules need it to be prepended later\n if (!className) {\n return {\n rules: rules.map((r) => ({\n ...r,\n needsClassName: true,\n })),\n };\n }\n\n // Prepend className to selectors\n const finalRules = rules.map((rule) => {\n // Parse the selector to find where to insert className\n let selector = rule.selector;\n\n // If selector starts with :root, insert className after the :root part\n if (rule.rootPrefix) {\n selector = `${rule.rootPrefix} .${className}.${className}${selector}`;\n } else {\n selector = `.${className}.${className}${selector}`;\n }\n\n return {\n ...rule,\n selector,\n };\n });\n\n return {\n rules: finalRules,\n className,\n };\n}\n\n/**\n * Clear the pipeline cache (for testing)\n */\nexport function clearPipelineCache(): void {\n pipelineCache.clear();\n}\n\n// ============================================================================\n// Pipeline Implementation\n// ============================================================================\n\nfunction runPipeline(\n styles: Styles,\n parserContext: StateParserContext,\n): CSSRule[] {\n const allRules: CSSRule[] = [];\n\n // Process styles recursively (including nested selectors)\n processStyles(styles, '', parserContext, allRules);\n\n // Deduplicate rules\n const seen = new Set<string>();\n const dedupedRules = allRules.filter((rule) => {\n // Include rootPrefix in dedup key - rules with different root prefixes are distinct\n const key = `${rule.selector}|${rule.declarations}|${JSON.stringify(rule.atRules || [])}|${rule.rootPrefix || ''}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n\n return dedupedRules;\n}\n\n/**\n * Process styles at a given nesting level\n */\nfunction processStyles(\n styles: Styles,\n selectorSuffix: string,\n parserContext: StateParserContext,\n allRules: CSSRule[],\n): void {\n const keys = Object.keys(styles);\n\n // Separate selector keys from style keys\n // Skip @keyframes (processed separately) and other @ prefixed keys (predefined states)\n const selectorKeys = keys.filter((key) => isSelector(key));\n const styleKeys = keys.filter(\n (key) => !isSelector(key) && !key.startsWith('@'),\n );\n\n // Process nested selectors first\n for (const key of selectorKeys) {\n const nestedStyles = styles[key] as Styles;\n if (!nestedStyles || typeof nestedStyles !== 'object') continue;\n\n // Get all selectors (handles comma-separated patterns)\n const suffixes = getAllSelectors(key, nestedStyles);\n if (!suffixes) continue; // Invalid selector, skip\n\n // Remove $ from nested styles\n const { $: _$, ...cleanedStyles } = nestedStyles;\n\n // Extract local predefined states scoped to this sub-element\n const subLocalStates = extractLocalPredefinedStates(cleanedStyles);\n const hasSubStates = Object.keys(subLocalStates).length > 0;\n const subContext: StateParserContext = {\n ...parserContext,\n isSubElement: true,\n localPredefinedStates: hasSubStates\n ? { ...parserContext.localPredefinedStates, ...subLocalStates }\n : parserContext.localPredefinedStates,\n };\n\n // Process for each selector (multiple selectors = same styles applied to each)\n for (const suffix of suffixes) {\n processStyles(\n cleanedStyles,\n selectorSuffix + suffix,\n subContext,\n allRules,\n );\n }\n }\n\n // Build handler queue\n const handlerQueue = buildHandlerQueue(styleKeys, styles);\n\n // Process each handler\n for (const { handler, styleMap } of handlerQueue) {\n const lookupStyles = handler.__lookupStyles;\n\n // Stage 1 & 2: Parse and build exclusive conditions for each style\n // Exclusive conditions ensure each CSS rule applies to exactly one state.\n // OR conditions in exclusives are properly expanded to DNF (multiple CSS selectors).\n const exclusiveByStyle = new Map<string, ExclusiveStyleEntry[]>();\n\n for (const styleName of lookupStyles) {\n const value = styleMap[styleName];\n if (value === undefined) continue;\n\n if (isValueMapping(value)) {\n // Parse entries from value mapping\n const parsed = parseStyleEntries(styleName, value, (stateKey) =>\n parseStateKey(stateKey, { context: parserContext }),\n );\n\n // Expand OR conditions into exclusive branches\n // This ensures OR branches like `A | B | C` become:\n // A, B & !A, C & !A & !B\n const expanded = expandOrConditions(parsed);\n\n // Build exclusive conditions across all entries\n const exclusive = buildExclusiveConditions(expanded);\n\n // Expand ORs from De Morgan negation into exclusive branches\n // This transforms: !A | !B → !A, (A & !B)\n // Ensures each CSS rule has proper at-rule context\n const fullyExpanded = expandExclusiveOrs(exclusive);\n exclusiveByStyle.set(styleName, fullyExpanded);\n } else {\n // Simple value - single entry with TRUE condition\n exclusiveByStyle.set(styleName, [\n {\n styleKey: styleName,\n stateKey: '',\n value,\n condition: trueCondition(),\n priority: 0,\n exclusiveCondition: trueCondition(),\n },\n ]);\n }\n }\n\n // Stage 4: Compute all valid state combinations\n const stateSnapshots = computeStateCombinations(\n exclusiveByStyle,\n lookupStyles,\n );\n\n // Stage 5: Call handler for each snapshot\n const computedRules: ComputedRule[] = [];\n\n for (const snapshot of stateSnapshots) {\n const result = handler(snapshot.values as StyleValueStateMap);\n if (!result) continue;\n\n // Handler may return single or array\n const results = Array.isArray(result) ? result : [result];\n\n for (const r of results) {\n if (!r || typeof r !== 'object') continue;\n\n const { $, ...styleProps } = r;\n const declarations: Record<string, string> = {};\n\n for (const [prop, val] of Object.entries(styleProps)) {\n if (val != null && val !== '') {\n declarations[prop] = String(val);\n }\n }\n\n if (Object.keys(declarations).length === 0) continue;\n\n // Handle $ suffixes\n const suffixes = $\n ? (Array.isArray($) ? $ : [$]).map(\n (s) => selectorSuffix + normalizeSelectorSuffix(String(s)),\n )\n : [selectorSuffix];\n\n for (const suffix of suffixes) {\n computedRules.push({\n condition: snapshot.condition,\n declarations,\n selectorSuffix: suffix,\n });\n }\n }\n }\n\n // Stage 6: Merge rules with identical CSS output\n const mergedRules = mergeByValue(computedRules);\n\n // Stage 7: Materialize to CSS\n for (const rule of mergedRules) {\n const cssRules = materializeComputedRule(rule);\n allRules.push(...cssRules);\n }\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Check if a key is a CSS selector\n */\nexport function isSelector(key: string): boolean {\n return key.startsWith('&') || key.startsWith('.') || /^[A-Z]/.test(key);\n}\n\n/**\n * Result of processing a selector affix ($) pattern.\n *\n * @example\n * // Valid result with multiple selectors\n * { valid: true, selectors: ['> [data-element=\"Cell\"]', ' [data-element=\"Body\"] > [data-element=\"Cell\"]'] }\n *\n * // Invalid result with error message\n * { valid: false, reason: 'Selector affix \"+\" targets elements outside the root scope.' }\n */\ntype AffixResult =\n | { valid: true; selectors: string[] }\n | { valid: false; reason: string };\n\n/**\n * Get all selector suffixes for a sub-element key.\n *\n * Handles three types of selector keys:\n * - `&` prefix: Raw selector suffix (e.g., `&:hover` → `:hover`)\n * - `.` prefix: Class selector (e.g., `.active` → ` .active`)\n * - Uppercase: Sub-element with optional `$` affix pattern\n *\n * @param key - The sub-element key (e.g., 'Label', '&:hover', '.active')\n * @param styles - The styles object, may contain `$` property for selector affix\n * @returns Array of selector suffixes, or null if invalid (with console warning)\n *\n * @example\n * getAllSelectors('Label', {})\n * // → [' [data-element=\"Label\"]']\n *\n * getAllSelectors('Cell', { $: '>, >Body>' })\n * // → ['> [data-element=\"Cell\"]', ' [data-element=\"Body\"] > [data-element=\"Cell\"]']\n */\nfunction getAllSelectors(key: string, styles?: Styles): string[] | null {\n if (key.startsWith('&')) {\n return [key.slice(1)];\n }\n\n if (key.startsWith('.')) {\n return [` ${key}`];\n }\n\n if (/^[A-Z]/.test(key)) {\n const affix = styles?.$;\n if (affix !== undefined) {\n const result = processAffix(String(affix), key);\n if (!result.valid) {\n console.warn(`[Tasty] ${result.reason}`);\n return null; // Skip this sub-element entirely\n }\n return result.selectors;\n }\n return [` [data-element=\"${key}\"]`];\n }\n\n return null;\n}\n\n/**\n * Process selector affix pattern and return selector(s)\n *\n * Supports:\n * - Direct child: '>'\n * - Chained elements: '>Body>Row>'\n * - HTML tags: 'a', '>ul>li', 'button:hover'\n * - Pseudo-elements on root: '::before'\n * - Pseudo on sub-element: '@::before', '>@:hover'\n * - Classes: '.active', '>@.active'\n * - Multiple selectors: '>, >Body>'\n * - Sibling combinators (after element): '>Item+', '>Item~'\n */\nfunction processAffix(affix: string, key: string): AffixResult {\n const trimmed = affix.trim();\n\n // Empty = default behavior (descendant selector with key)\n if (!trimmed) {\n return { valid: true, selectors: [` [data-element=\"${key}\"]`] };\n }\n\n // Split by comma for multiple selectors\n const patterns = trimmed.split(',').map((p) => p.trim());\n const selectors: string[] = [];\n\n for (const pattern of patterns) {\n const validation = validatePattern(pattern);\n if (!validation.valid) {\n return validation;\n }\n\n const selector = processSinglePattern(pattern, key);\n selectors.push(selector);\n }\n\n return { valid: true, selectors };\n}\n\n/**\n * Recognized token patterns for selector affix validation.\n *\n * These patterns are used to tokenize and validate `$` affix strings.\n * Order matters: more specific patterns must come first to avoid\n * partial matches (e.g., `::before` must match before `:` alone).\n *\n * Unrecognized tokens (like `#id`, `*`, or numbers) will cause validation to fail.\n */\nconst VALID_TOKEN_PATTERNS = [\n /^[>+~]/, // Combinators: >, +, ~\n /^[A-Z][a-zA-Z0-9]*/, // Uppercase element names → [data-element=\"...\"]\n /^@/, // @ placeholder for key injection position\n /^::?[a-z][a-z0-9-]*(?:\\([^)]*\\))?/, // Pseudo-elements/classes (:hover, ::before, :not(.x))\n /^\\.[a-zA-Z_-][a-zA-Z0-9_-]*/, // Class selectors (.active, .is-open)\n /^\\[[^\\]]+\\]/, // Attribute selectors ([type=\"text\"], [role])\n /^[a-z][a-z0-9-]*/, // HTML tag names (a, div, button, my-component)\n /^\\s+/, // Whitespace (ignored during parsing)\n /^&/, // Root reference (stripped, kept for backward compat)\n];\n\n/**\n * Scan a pattern for unrecognized tokens.\n *\n * Iterates through the pattern, consuming recognized tokens until\n * either the pattern is fully consumed (valid) or an unrecognized\n * character sequence is found (invalid).\n *\n * @param pattern - The selector pattern to validate\n * @returns The first unrecognized token found, or null if all tokens are valid\n *\n * @example\n * findUnrecognizedTokens('>Body>Row>') // → null (valid)\n * findUnrecognizedTokens('123') // → '123' (invalid)\n * findUnrecognizedTokens('#myId') // → '#' (invalid)\n */\nfunction findUnrecognizedTokens(pattern: string): string | null {\n let remaining = pattern;\n\n while (remaining.length > 0) {\n let matched = false;\n\n for (const regex of VALID_TOKEN_PATTERNS) {\n const match = remaining.match(regex);\n if (match) {\n remaining = remaining.slice(match[0].length);\n matched = true;\n break;\n }\n }\n\n if (!matched) {\n // Found unrecognized content - extract the problematic part\n const unrecognized = remaining.match(/^[^\\s>+~@.:[\\]A-Z]+/);\n return unrecognized ? unrecognized[0] : remaining[0];\n }\n }\n\n return null;\n}\n\n/**\n * Validate a selector pattern for structural correctness.\n *\n * Checks for:\n * 1. Out-of-scope selectors: Patterns starting with `+` or `~` target siblings\n * of the root element, which is outside the component's DOM scope.\n * 2. Consecutive combinators: Patterns like `>>` or `>+` are malformed CSS.\n * 3. Unrecognized tokens: Characters/sequences not matching valid CSS selectors.\n *\n * @param pattern - A single selector pattern (already split by comma)\n * @returns AffixResult indicating validity and error reason if invalid\n *\n * @example\n * validatePattern('>Body>Row>') // → { valid: true, selectors: [] }\n * validatePattern('+') // → { valid: false, reason: '...outside root scope...' }\n * validatePattern('>>') // → { valid: false, reason: '...consecutive combinators...' }\n */\nfunction validatePattern(pattern: string): AffixResult {\n const trimmed = pattern.trim();\n\n // Patterns starting with + or ~ target siblings of the root element,\n // which is outside the component's scope. Valid sibling patterns must\n // be preceded by an element: \">Item+\", \">Item~\"\n if (/^[+~]/.test(trimmed)) {\n return {\n valid: false,\n reason:\n `Selector affix \"${pattern}\" targets elements outside the root scope. ` +\n `Sibling selectors (+, ~) must be preceded by an element inside the root. ` +\n `Use \">Element+\" or \">Element~\" instead.`,\n };\n }\n\n // Check for consecutive combinators\n if (/[>+~]{2,}/.test(trimmed.replace(/\\s+/g, ''))) {\n return {\n valid: false,\n reason: `Selector affix \"${pattern}\" contains consecutive combinators.`,\n };\n }\n\n // Check for unrecognized tokens (e.g., lowercase text like \"foo\")\n const unrecognized = findUnrecognizedTokens(trimmed);\n if (unrecognized) {\n return {\n valid: false,\n reason:\n `Selector affix \"${pattern}\" contains unrecognized token \"${unrecognized}\". ` +\n `Valid tokens: combinators (>, +, ~), element names (Uppercase), ` +\n `@ placeholder, pseudo (:hover, ::before), class (.name), attribute ([attr]).`,\n };\n }\n\n return { valid: true, selectors: [] };\n}\n\n/**\n * Process a single selector pattern into a CSS selector suffix.\n *\n * This is the main transformation function that converts a `$` affix pattern\n * into a valid CSS selector suffix. It handles:\n *\n * 1. `@` placeholder replacement with `[data-element=\"key\"]`\n * 2. Key injection based on pattern ending (see `shouldInjectKey`)\n * 3. Proper spacing for descendant vs direct child selectors\n *\n * @param pattern - A single validated selector pattern\n * @param key - The sub-element key to inject (e.g., 'Label', 'Cell')\n * @returns CSS selector suffix ready to append to the root selector\n *\n * @example\n * processSinglePattern('>', 'Row')\n * // → '> [data-element=\"Row\"]'\n *\n * processSinglePattern('>Body>Row>', 'Cell')\n * // → '> [data-element=\"Body\"] > [data-element=\"Row\"] > [data-element=\"Cell\"]'\n *\n * processSinglePattern('::before', 'Before')\n * // → '::before' (no key injection for pseudo on root)\n *\n * processSinglePattern('>@:hover', 'Item')\n * // → '> [data-element=\"Item\"]:hover'\n */\nfunction processSinglePattern(pattern: string, key: string): string {\n // Strip leading & if present (implicit root reference, kept for compat)\n const normalized = pattern.replace(/^&/, '').trim();\n\n if (!normalized) {\n return ` [data-element=\"${key}\"]`;\n }\n\n // Pseudo-elements/classes at start apply directly to root (no space prefix)\n const startsWithPseudo = /^::?[a-z]/.test(normalized);\n\n // Transform the pattern: convert element names and normalize spacing\n let result = transformPattern(normalized);\n\n // Handle @ placeholder: explicit key injection position\n if (result.includes('@')) {\n // Remove space between @ and following class/pseudo for proper attachment\n // e.g., \"@ .active\" → \"[el].active\", but \"@ > span\" → \"[el] > span\"\n result = result.replace(/@ (?=[.:])/g, '@');\n result = result.replace(/@/g, `[data-element=\"${key}\"]`);\n\n if (!startsWithPseudo && !result.startsWith(' ')) {\n result = ' ' + result;\n }\n return result;\n }\n\n // Auto-inject key based on pattern ending (see shouldInjectKey for rules)\n if (shouldInjectKey(normalized)) {\n result = result + ' ' + `[data-element=\"${key}\"]`;\n }\n\n // Add space prefix for selectors targeting inside root (not pseudo on root)\n if (!startsWithPseudo && !result.startsWith(' ')) {\n result = ' ' + result;\n }\n\n return result;\n}\n\n/**\n * Transform a selector pattern by converting element names and normalizing spacing.\n *\n * This is a character-by-character tokenizer that:\n * - Converts uppercase names to `[data-element=\"Name\"]` selectors\n * - Adds proper spacing around combinators (>, +, ~)\n * - Preserves lowercase tags, classes, pseudos, and attributes as-is\n * - Keeps @ placeholder for later replacement\n *\n * The tokenizer handles these token types in order:\n * 1. Whitespace (skipped)\n * 2. Combinators: >, +, ~ (add surrounding spaces)\n * 3. Uppercase names: Body, Row (convert to [data-element=\"...\"])\n * 4. @ placeholder (keep for later replacement)\n * 5. Pseudo: :hover, ::before (attach to previous token)\n * 6. Tags: a, div, button (keep as-is with spacing)\n * 7. Classes: .active (attach to previous element/tag/placeholder)\n * 8. Attributes: [type=\"text\"] (keep as-is)\n *\n * @param pattern - The raw selector pattern to transform\n * @returns Transformed pattern with proper CSS selector syntax\n *\n * @example\n * transformPattern('>Body>Row>')\n * // → '> [data-element=\"Body\"] > [data-element=\"Row\"] >'\n *\n * transformPattern('button.primary:hover')\n * // → 'button.primary:hover'\n */\nfunction transformPattern(pattern: string): string {\n let result = '';\n let i = 0;\n\n while (i < pattern.length) {\n const char = pattern[i];\n\n // Skip whitespace\n if (/\\s/.test(char)) {\n i++;\n continue;\n }\n\n // Combinator: > + ~\n if (/[>+~]/.test(char)) {\n // Add combinator with surrounding spaces\n if (result && !result.endsWith(' ')) {\n result += ' ';\n }\n result += char;\n i++;\n continue;\n }\n\n // Uppercase element name\n if (/[A-Z]/.test(char)) {\n // Read the full element name\n let name = '';\n while (i < pattern.length && /[a-zA-Z0-9]/.test(pattern[i])) {\n name += pattern[i];\n i++;\n }\n // Add with proper spacing\n if (result && !result.endsWith(' ')) {\n result += ' ';\n }\n result += `[data-element=\"${name}\"]`;\n continue;\n }\n\n // @ placeholder\n if (char === '@') {\n if (result && !result.endsWith(' ')) {\n result += ' ';\n }\n result += '@';\n i++;\n // Don't add space after @ - let the next token attach if it's a class/pseudo\n continue;\n }\n\n // Pseudo-element/class (::before, :hover)\n if (char === ':') {\n // Don't add space before pseudo if attached to previous element\n let pseudo = '';\n while (\n i < pattern.length &&\n !/[\\s>+~,@]/.test(pattern[i]) &&\n !/[A-Z]/.test(pattern[i])\n ) {\n pseudo += pattern[i];\n i++;\n }\n result += pseudo;\n continue;\n }\n\n // Lowercase HTML tag name (a, div, button, my-component)\n if (/[a-z]/.test(char)) {\n let tag = '';\n while (i < pattern.length && /[a-z0-9-]/.test(pattern[i])) {\n tag += pattern[i];\n i++;\n }\n // Add with proper spacing\n if (result && !result.endsWith(' ')) {\n result += ' ';\n }\n result += tag;\n continue;\n }\n\n // Class (.active, .myClass, .navItem)\n if (char === '.') {\n // Keep attached if directly after ] (element), @ (placeholder), or alphanumeric (tag)\n // Otherwise add space (standalone class selector)\n const lastNonSpace = result.replace(/\\s+$/, '').slice(-1);\n const attachToLast =\n lastNonSpace === ']' ||\n lastNonSpace === '@' ||\n /[a-zA-Z0-9-]/.test(lastNonSpace);\n if (result && !attachToLast && !result.endsWith(' ')) {\n result += ' ';\n }\n // Start with the dot\n let cls = '.';\n i++;\n // Class names can contain uppercase letters (camelCase, BEM, etc.)\n // Stop at: whitespace, combinators, comma, @, or new token starters (. : [)\n while (i < pattern.length && /[a-zA-Z0-9_-]/.test(pattern[i])) {\n cls += pattern[i];\n i++;\n }\n result += cls;\n continue;\n }\n\n // Attribute selector [...]\n if (char === '[') {\n // Keep attached if directly after ] (element), @ (placeholder), or alphanumeric (tag)\n // Otherwise add space (standalone attribute selector)\n const lastNonSpace = result.replace(/\\s+$/, '').slice(-1);\n const attachToLast =\n lastNonSpace === ']' ||\n lastNonSpace === '@' ||\n /[a-zA-Z0-9-]/.test(lastNonSpace);\n if (result && !attachToLast && !result.endsWith(' ')) {\n result += ' ';\n }\n let attr = '';\n let depth = 0;\n while (i < pattern.length) {\n attr += pattern[i];\n if (pattern[i] === '[') depth++;\n if (pattern[i] === ']') depth--;\n i++;\n if (depth === 0) break;\n }\n result += attr;\n continue;\n }\n\n // Other characters - just append\n result += char;\n i++;\n }\n\n return result;\n}\n\n/**\n * Determine if the sub-element key should be auto-injected based on pattern ending.\n *\n * Key injection rules (when no @ placeholder is present):\n *\n * | Pattern Ending | Inject Key? | Example | Result |\n * |----------------|-------------|---------|--------|\n * | Combinator (>, +, ~) | Yes | `'>Body>'` | `> [data-element=\"Body\"] > [el]` |\n * | Uppercase element | Yes | `'>Body>Row'` | `> [el1] > [el2] [key]` |\n * | Lowercase tag | Yes | `'>ul>li'` | `> ul > li [key]` |\n * | Pseudo (:hover, ::before) | No | `'::before'` | `::before` |\n * | Class (.active) | No | `'.active'` | `.active` |\n * | Attribute ([type]) | No | `'[type=\"text\"]'` | `[type=\"text\"]` |\n *\n * @param pattern - The normalized pattern (after stripping &)\n * @returns true if key should be injected, false otherwise\n *\n * @example\n * shouldInjectKey('>') // → true (trailing combinator)\n * shouldInjectKey('>Body>Row') // → true (ends with element)\n * shouldInjectKey('>ul>li') // → true (ends with tag)\n * shouldInjectKey('::before') // → false (ends with pseudo)\n * shouldInjectKey('.active') // → false (ends with class)\n * shouldInjectKey('a:hover') // → false (ends with pseudo)\n * shouldInjectKey('button.primary') // → false (ends with class)\n */\nfunction shouldInjectKey(pattern: string): boolean {\n const trimmed = pattern.trim();\n\n // Rule 1: Ends with combinator → inject key after it\n // e.g., '>' → '> [data-element=\"Key\"]'\n if (/[>+~]$/.test(trimmed)) {\n return true;\n }\n\n // Rule 2: Ends with uppercase element name → inject key as descendant\n // The lookbehind ensures we're matching a standalone element name, not\n // part of a class like .myClass (where C is preceded by lowercase)\n // e.g., '>Body' → '> [data-element=\"Body\"] [data-element=\"Key\"]'\n if (/(?:^|[\\s>+~\\]:])[A-Z][a-zA-Z0-9]*$/.test(trimmed)) {\n return true;\n }\n\n // Rule 3: Ends with lowercase tag name → inject key as descendant\n // The negative lookbehind (?<![:.]) ensures we don't match:\n // - ':hover' (pseudo ending)\n // - '.primary' (class ending)\n // e.g., '>ul>li' → '> ul > li [data-element=\"Key\"]'\n if (/(?<![:.])(?:^|[\\s>+~])[a-z][a-z0-9-]*$/.test(trimmed)) {\n return true;\n }\n\n // Rule 4: Otherwise (pseudo, class, attribute) → no injection\n // The pattern is complete as-is, applying to root or a specific selector\n return false;\n}\n\n/**\n * Normalize selector suffix from $ property\n */\nfunction normalizeSelectorSuffix(suffix: string): string {\n if (!suffix) return '';\n return suffix.startsWith('&') ? suffix.slice(1) : suffix;\n}\n\n/**\n * Build handler queue from style keys\n */\nfunction buildHandlerQueue(\n styleKeys: string[],\n styles: Styles,\n): { handler: StyleHandler; styleMap: StyleMap }[] {\n const queue: { handler: StyleHandler; styleMap: StyleMap }[] = [];\n const seenHandlers = new Set<StyleHandler>();\n\n for (const styleName of styleKeys) {\n let handlers: StyleHandler[] = STYLE_HANDLER_MAP[styleName];\n\n if (!handlers) {\n handlers = STYLE_HANDLER_MAP[styleName] = [createStyle(styleName)];\n }\n\n for (const handler of handlers) {\n if (seenHandlers.has(handler)) continue;\n seenHandlers.add(handler);\n\n const lookupStyles = handler.__lookupStyles;\n const styleMap: StyleMap = {};\n\n for (const name of lookupStyles) {\n const val = styles[name];\n if (val !== undefined) {\n styleMap[name] = val as StyleValue | StyleValueStateMap;\n }\n }\n\n queue.push({ handler, styleMap });\n }\n }\n\n return queue;\n}\n\n/**\n * Compute all valid state combinations for a handler's lookup styles\n */\nfunction computeStateCombinations(\n exclusiveByStyle: Map<string, ExclusiveStyleEntry[]>,\n lookupStyles: string[],\n): { condition: ConditionNode; values: Record<string, StyleValue> }[] {\n // Get entries for each style\n const entriesPerStyle = lookupStyles.map(\n (style) => exclusiveByStyle.get(style) || [],\n );\n\n // Cartesian product of all combinations\n const combinations = cartesianProduct(entriesPerStyle);\n\n // Build snapshots, simplifying and filtering impossible combinations\n const snapshots: {\n condition: ConditionNode;\n values: Record<string, StyleValue>;\n }[] = [];\n\n for (const combo of combinations) {\n // Combine all exclusive conditions with AND\n const conditions = combo.map((e) => e.exclusiveCondition);\n const combined = and(...conditions);\n const simplified = simplifyCondition(combined);\n\n // Skip impossible combinations\n if (simplified.kind === 'false') continue;\n\n // Build values map\n const values: Record<string, StyleValue> = {};\n for (const entry of combo) {\n values[entry.styleKey] = entry.value;\n }\n\n snapshots.push({\n condition: simplified,\n values,\n });\n }\n\n return snapshots;\n}\n\n/**\n * Cartesian product of arrays\n */\nfunction cartesianProduct<T>(arrays: T[][]): T[][] {\n if (arrays.length === 0) return [[]];\n\n // Filter out empty arrays\n const nonEmpty = arrays.filter((a) => a.length > 0);\n if (nonEmpty.length === 0) return [[]];\n\n return nonEmpty.reduce<T[][]>(\n (acc, arr) => acc.flatMap((combo) => arr.map((item) => [...combo, item])),\n [[]],\n );\n}\n\n/**\n * Merge rules with identical CSS output\n */\nfunction mergeByValue(rules: ComputedRule[]): ComputedRule[] {\n // Group by selectorSuffix + declarations\n const groups = new Map<string, ComputedRule[]>();\n\n for (const rule of rules) {\n const key = `${rule.selectorSuffix}|${JSON.stringify(rule.declarations)}`;\n if (!groups.has(key)) {\n groups.set(key, []);\n }\n groups.get(key)!.push(rule);\n }\n\n // Merge conditions with OR for each group\n const merged: ComputedRule[] = [];\n\n for (const [, groupRules] of groups) {\n if (groupRules.length === 1) {\n merged.push(groupRules[0]);\n } else {\n // Merge conditions with OR\n const mergedCondition = simplifyCondition(\n or(...groupRules.map((r) => r.condition)),\n );\n merged.push({\n condition: mergedCondition,\n declarations: groupRules[0].declarations,\n selectorSuffix: groupRules[0].selectorSuffix,\n });\n }\n }\n\n return merged;\n}\n\n/**\n * Build selector fragment from a variant (without className prefix)\n */\nfunction buildSelectorFromVariant(\n variant: SelectorVariant,\n selectorSuffix: string,\n): string {\n let selector = '';\n\n // Add modifier selectors\n for (const mod of variant.modifierConditions) {\n selector += modifierToCSS(mod);\n }\n\n // Add pseudo selectors\n for (const pseudo of variant.pseudoConditions) {\n selector += pseudoToCSS(pseudo);\n }\n\n // Add parent selector (before sub-element suffix)\n if (variant.parentConditions.length > 0) {\n selector += parentConditionsToCSS(\n variant.parentConditions,\n variant.parentDirect,\n );\n }\n\n selector += selectorSuffix;\n\n // Add own selectors (after sub-element)\n for (const own of variant.ownConditions) {\n selector += selectorConditionToCSS(own);\n }\n\n return selector;\n}\n\n/**\n * Materialize a computed rule to final CSS format\n *\n * Returns an array because OR conditions may generate multiple CSS rules\n * (when different branches have different at-rules)\n */\nfunction materializeComputedRule(rule: ComputedRule): CSSRule[] {\n const components = conditionToCSS(rule.condition);\n\n if (components.isImpossible || components.variants.length === 0) {\n return [];\n }\n\n const declarations = Object.entries(rule.declarations)\n .map(([prop, value]) => `${prop}: ${value};`)\n .join(' ');\n\n // Helper to get root prefix key for grouping\n const getRootPrefixKey = (variant: SelectorVariant): string => {\n return variant.rootConditions\n .map((r) => selectorConditionToCSS(r))\n .sort()\n .join('|');\n };\n\n // Group variants by their at-rules (variants with same at-rules can be combined with commas)\n const byAtRules = new Map<\n string,\n { variants: SelectorVariant[]; atRules: string[]; rootPrefix?: string }\n >();\n\n for (const variant of components.variants) {\n const atRules = buildAtRulesFromVariant(variant);\n const key = atRules.sort().join('|||') + '###' + getRootPrefixKey(variant);\n\n const group = byAtRules.get(key);\n if (group) {\n group.variants.push(variant);\n } else {\n byAtRules.set(key, {\n variants: [variant],\n atRules,\n rootPrefix: rootConditionsToCSS(variant.rootConditions),\n });\n }\n }\n\n // Generate one CSSRule per at-rules group\n const rules: CSSRule[] = [];\n for (const [, group] of byAtRules) {\n // Build selector fragments for each variant (will be joined with className later)\n const selectorFragments = group.variants.map((v) =>\n buildSelectorFromVariant(v, rule.selectorSuffix),\n );\n\n // Store as array if multiple, string if single\n const selector =\n selectorFragments.length === 1 ? selectorFragments[0] : selectorFragments;\n\n const cssRule: CSSRule = {\n selector,\n declarations,\n };\n\n if (group.atRules.length > 0) {\n cssRule.atRules = group.atRules;\n }\n\n if (group.rootPrefix) {\n cssRule.rootPrefix = group.rootPrefix;\n }\n\n rules.push(cssRule);\n }\n\n return rules;\n}\n\n// ============================================================================\n// Public API: renderStyles (compatible with old API)\n// ============================================================================\n\n/**\n * Options for renderStyles when using direct selector mode.\n */\nexport interface RenderStylesOptions {\n /**\n * Whether to double the class selector for increased specificity.\n * When true, `.myClass` becomes `.myClass.myClass` for higher specificity.\n *\n * @default false - User-provided selectors are not doubled.\n *\n * Note: This only applies when a classNameOrSelector is provided.\n * When renderStyles returns RenderResult with needsClassName=true,\n * the injector handles doubling automatically.\n */\n doubleSelector?: boolean;\n}\n\n/**\n * Render styles to CSS rules.\n *\n * When called without classNameOrSelector, returns RenderResult with needsClassName=true.\n * When called with a selector/className string, returns StyleResult[] for direct injection.\n */\nexport function renderStyles(styles?: Styles): RenderResult;\nexport function renderStyles(\n styles: Styles | undefined,\n classNameOrSelector: string,\n options?: RenderStylesOptions,\n): StyleResult[];\nexport function renderStyles(\n styles?: Styles,\n classNameOrSelector?: string,\n options?: RenderStylesOptions,\n): RenderResult | StyleResult[] {\n // Check if we have a direct selector/className\n const directSelector = !!classNameOrSelector;\n\n if (!styles) {\n return directSelector ? [] : { rules: [] };\n }\n\n // Check cache\n const cacheKey = stringifyStyles(styles);\n let rules = pipelineCache.get(cacheKey);\n\n if (!rules) {\n // Create parser context\n const parserContext = createStateParserContext(styles);\n\n // Run pipeline\n rules = runPipeline(styles, parserContext);\n\n // Cache result\n pipelineCache.set(cacheKey, rules);\n }\n\n // Direct selector/className mode: return StyleResult[] directly\n if (directSelector) {\n const shouldDouble = options?.doubleSelector ?? false;\n\n return rules.map((rule): StyleResult => {\n // Handle selector as array (OR conditions) or string\n const selectorParts = Array.isArray(rule.selector)\n ? rule.selector\n : rule.selector\n ? [rule.selector]\n : [''];\n\n const finalSelector = selectorParts\n .map((part) => {\n let sel = part\n ? `${classNameOrSelector}${part}`\n : classNameOrSelector;\n\n // Double class selector for increased specificity if requested\n // This is used when the caller explicitly wants higher specificity\n if (shouldDouble && sel.startsWith('.')) {\n const classMatch = sel.match(/^\\.[a-zA-Z_-][a-zA-Z0-9_-]*/);\n if (classMatch) {\n const baseClass = classMatch[0];\n sel = baseClass + sel;\n }\n }\n\n // Handle root prefix for this selector\n if (rule.rootPrefix) {\n sel = `${rule.rootPrefix} ${sel}`;\n }\n\n return sel;\n })\n .join(', ');\n\n const result: StyleResult = {\n selector: finalSelector,\n declarations: rule.declarations,\n };\n\n if (rule.atRules && rule.atRules.length > 0) {\n result.atRules = rule.atRules;\n }\n\n return result;\n });\n }\n\n // No className mode: return RenderResult with needsClassName flag\n // Normalize selector to string (join array with placeholder that injector will handle)\n return {\n rules: rules.map(\n (r): StyleResult => ({\n selector: Array.isArray(r.selector)\n ? r.selector.join('|||')\n : r.selector,\n declarations: r.declarations,\n atRules: r.atRules,\n needsClassName: true,\n rootPrefix: r.rootPrefix,\n }),\n ),\n };\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nexport type { ConditionNode } from './conditions';\nexport { and, or, not, trueCondition, falseCondition } from './conditions';\nexport { parseStateKey } from './parseStateKey';\nexport { simplifyCondition } from './simplify';\nexport { buildExclusiveConditions } from './exclusive';\nexport { conditionToCSS } from './materialize';\nexport type { CSSRule } from './materialize';\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/pipeline/index.ts"],"sourcesContent":["/**\n * Tasty Style Rendering Pipeline\n *\n * This is the main entrypoint for the new pipeline implementation.\n * It implements the complete flow from style objects to CSS rules.\n *\n * Pipeline stages:\n * 1. PARSE CONDITIONS - Parse state keys into ConditionNode trees\n * 2. BUILD EXCLUSIVE CONDITIONS - AND with negation of higher-priority conditions\n * 3. SIMPLIFY CONDITIONS - Apply boolean algebra, detect contradictions\n * 4. GROUP BY HANDLER - Collect styles per handler, compute combinations\n * 5. COMPUTE CSS VALUES - Call handlers to get CSS declarations\n * 6. MERGE BY VALUE - Merge rules with identical CSS output\n * 7. MATERIALIZE CSS - Convert conditions to CSS selectors + at-rules\n */\n\nimport { Lru } from '../parser/lru';\nimport type { StateParserContext } from '../states';\nimport {\n createStateParserContext,\n extractLocalPredefinedStates,\n} from '../states';\nimport { createStyle, STYLE_HANDLER_MAP } from '../styles';\nimport type { Styles } from '../styles/types';\nimport type {\n StyleHandler,\n StyleMap,\n StyleValue,\n StyleValueStateMap,\n} from '../utils/styles';\nimport { stringifyStyles } from '../utils/styles';\n\nimport type { ConditionNode } from './conditions';\nimport { and, or, trueCondition } from './conditions';\nimport type { ExclusiveStyleEntry } from './exclusive';\nimport {\n buildExclusiveConditions,\n expandExclusiveOrs,\n expandOrConditions,\n isValueMapping,\n parseStyleEntries,\n} from './exclusive';\nimport type { CSSRule, SelectorVariant } from './materialize';\nimport {\n buildAtRulesFromVariant,\n conditionToCSS,\n modifierToCSS,\n parentGroupsToCSS,\n pseudoToCSS,\n rootConditionsToCSS,\n selectorConditionToCSS,\n} from './materialize';\nimport { parseStateKey } from './parseStateKey';\nimport { simplifyCondition } from './simplify';\n\n// ============================================================================\n// Types (compatible with old renderStyles API)\n// ============================================================================\n\n/**\n * Matches the old StyleResult interface for backward compatibility\n */\nexport interface StyleResult {\n selector: string;\n declarations: string;\n atRules?: string[];\n needsClassName?: boolean;\n rootPrefix?: string;\n}\n\n/**\n * Matches the old RenderResult interface for backward compatibility\n */\nexport interface RenderResult {\n rules: StyleResult[];\n className?: string;\n}\n\nexport interface PipelineResult {\n rules: CSSRule[];\n className?: string;\n}\n\ninterface ComputedRule {\n condition: ConditionNode;\n declarations: Record<string, string>;\n selectorSuffix: string;\n}\n\n// ============================================================================\n// Caching\n// ============================================================================\n\nconst pipelineCache = new Lru<string, CSSRule[]>(5000);\n\n// ============================================================================\n// Main Pipeline Function\n// ============================================================================\n\n/**\n * Render styles using the new pipeline.\n *\n * This is the main entrypoint that implements the complete flow.\n */\nexport function renderStylesPipeline(\n styles?: Styles,\n className?: string,\n): PipelineResult {\n if (!styles) {\n return { rules: [], className };\n }\n\n // Check cache\n const cacheKey = stringifyStyles(styles);\n let rules = pipelineCache.get(cacheKey);\n\n if (!rules) {\n // Create parser context\n const parserContext = createStateParserContext(styles);\n\n // Run pipeline\n rules = runPipeline(styles, parserContext);\n\n // Cache result\n pipelineCache.set(cacheKey, rules);\n }\n\n // If no className, rules need it to be prepended later\n if (!className) {\n return {\n rules: rules.map((r) => ({\n ...r,\n needsClassName: true,\n })),\n };\n }\n\n // Prepend className to selectors\n const finalRules = rules.map((rule) => {\n // Parse the selector to find where to insert className\n let selector = rule.selector;\n\n // If selector starts with :root, insert className after the :root part\n if (rule.rootPrefix) {\n selector = `${rule.rootPrefix} .${className}.${className}${selector}`;\n } else {\n selector = `.${className}.${className}${selector}`;\n }\n\n return {\n ...rule,\n selector,\n };\n });\n\n return {\n rules: finalRules,\n className,\n };\n}\n\n/**\n * Clear the pipeline cache (for testing)\n */\nexport function clearPipelineCache(): void {\n pipelineCache.clear();\n}\n\n// ============================================================================\n// Pipeline Implementation\n// ============================================================================\n\nfunction runPipeline(\n styles: Styles,\n parserContext: StateParserContext,\n): CSSRule[] {\n const allRules: CSSRule[] = [];\n\n // Process styles recursively (including nested selectors)\n processStyles(styles, '', parserContext, allRules);\n\n // Deduplicate rules\n const seen = new Set<string>();\n const dedupedRules = allRules.filter((rule) => {\n // Include rootPrefix in dedup key - rules with different root prefixes are distinct\n const key = `${rule.selector}|${rule.declarations}|${JSON.stringify(rule.atRules || [])}|${rule.rootPrefix || ''}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n\n return dedupedRules;\n}\n\n/**\n * Process styles at a given nesting level\n */\nfunction processStyles(\n styles: Styles,\n selectorSuffix: string,\n parserContext: StateParserContext,\n allRules: CSSRule[],\n): void {\n const keys = Object.keys(styles);\n\n // Separate selector keys from style keys\n // Skip @keyframes (processed separately) and other @ prefixed keys (predefined states)\n const selectorKeys = keys.filter((key) => isSelector(key));\n const styleKeys = keys.filter(\n (key) => !isSelector(key) && !key.startsWith('@'),\n );\n\n // Process nested selectors first\n for (const key of selectorKeys) {\n const nestedStyles = styles[key] as Styles;\n if (!nestedStyles || typeof nestedStyles !== 'object') continue;\n\n // Get all selectors (handles comma-separated patterns)\n const suffixes = getAllSelectors(key, nestedStyles);\n if (!suffixes) continue; // Invalid selector, skip\n\n // Remove $ from nested styles\n const { $: _$, ...cleanedStyles } = nestedStyles;\n\n // Extract local predefined states scoped to this sub-element\n const subLocalStates = extractLocalPredefinedStates(cleanedStyles);\n const hasSubStates = Object.keys(subLocalStates).length > 0;\n const subContext: StateParserContext = {\n ...parserContext,\n isSubElement: true,\n localPredefinedStates: hasSubStates\n ? { ...parserContext.localPredefinedStates, ...subLocalStates }\n : parserContext.localPredefinedStates,\n };\n\n // Process for each selector (multiple selectors = same styles applied to each)\n for (const suffix of suffixes) {\n processStyles(\n cleanedStyles,\n selectorSuffix + suffix,\n subContext,\n allRules,\n );\n }\n }\n\n // Build handler queue\n const handlerQueue = buildHandlerQueue(styleKeys, styles);\n\n // Process each handler\n for (const { handler, styleMap } of handlerQueue) {\n const lookupStyles = handler.__lookupStyles;\n\n // Stage 1 & 2: Parse and build exclusive conditions for each style\n // Exclusive conditions ensure each CSS rule applies to exactly one state.\n // OR conditions in exclusives are properly expanded to DNF (multiple CSS selectors).\n const exclusiveByStyle = new Map<string, ExclusiveStyleEntry[]>();\n\n for (const styleName of lookupStyles) {\n const value = styleMap[styleName];\n if (value === undefined) continue;\n\n if (isValueMapping(value)) {\n // Parse entries from value mapping\n const parsed = parseStyleEntries(styleName, value, (stateKey) =>\n parseStateKey(stateKey, { context: parserContext }),\n );\n\n // Expand OR conditions into exclusive branches\n // This ensures OR branches like `A | B | C` become:\n // A, B & !A, C & !A & !B\n const expanded = expandOrConditions(parsed);\n\n // Build exclusive conditions across all entries\n const exclusive = buildExclusiveConditions(expanded);\n\n // Expand ORs from De Morgan negation into exclusive branches\n // This transforms: !A | !B → !A, (A & !B)\n // Ensures each CSS rule has proper at-rule context\n const fullyExpanded = expandExclusiveOrs(exclusive);\n exclusiveByStyle.set(styleName, fullyExpanded);\n } else {\n // Simple value - single entry with TRUE condition\n exclusiveByStyle.set(styleName, [\n {\n styleKey: styleName,\n stateKey: '',\n value,\n condition: trueCondition(),\n priority: 0,\n exclusiveCondition: trueCondition(),\n },\n ]);\n }\n }\n\n // Stage 4: Compute all valid state combinations\n const stateSnapshots = computeStateCombinations(\n exclusiveByStyle,\n lookupStyles,\n );\n\n // Stage 5: Call handler for each snapshot\n const computedRules: ComputedRule[] = [];\n\n for (const snapshot of stateSnapshots) {\n const result = handler(snapshot.values as StyleValueStateMap);\n if (!result) continue;\n\n // Handler may return single or array\n const results = Array.isArray(result) ? result : [result];\n\n for (const r of results) {\n if (!r || typeof r !== 'object') continue;\n\n const { $, ...styleProps } = r;\n const declarations: Record<string, string> = {};\n\n for (const [prop, val] of Object.entries(styleProps)) {\n if (val != null && val !== '') {\n declarations[prop] = String(val);\n }\n }\n\n if (Object.keys(declarations).length === 0) continue;\n\n // Handle $ suffixes\n const suffixes = $\n ? (Array.isArray($) ? $ : [$]).map(\n (s) => selectorSuffix + normalizeSelectorSuffix(String(s)),\n )\n : [selectorSuffix];\n\n for (const suffix of suffixes) {\n computedRules.push({\n condition: snapshot.condition,\n declarations,\n selectorSuffix: suffix,\n });\n }\n }\n }\n\n // Stage 6: Merge rules with identical CSS output\n const mergedRules = mergeByValue(computedRules);\n\n // Stage 7: Materialize to CSS\n for (const rule of mergedRules) {\n const cssRules = materializeComputedRule(rule);\n allRules.push(...cssRules);\n }\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n/**\n * Check if a key is a CSS selector\n */\nexport function isSelector(key: string): boolean {\n return key.startsWith('&') || key.startsWith('.') || /^[A-Z]/.test(key);\n}\n\n/**\n * Result of processing a selector affix ($) pattern.\n *\n * @example\n * // Valid result with multiple selectors\n * { valid: true, selectors: ['> [data-element=\"Cell\"]', ' [data-element=\"Body\"] > [data-element=\"Cell\"]'] }\n *\n * // Invalid result with error message\n * { valid: false, reason: 'Selector affix \"+\" targets elements outside the root scope.' }\n */\ntype AffixResult =\n | { valid: true; selectors: string[] }\n | { valid: false; reason: string };\n\n/**\n * Get all selector suffixes for a sub-element key.\n *\n * Handles three types of selector keys:\n * - `&` prefix: Raw selector suffix (e.g., `&:hover` → `:hover`)\n * - `.` prefix: Class selector (e.g., `.active` → ` .active`)\n * - Uppercase: Sub-element with optional `$` affix pattern\n *\n * @param key - The sub-element key (e.g., 'Label', '&:hover', '.active')\n * @param styles - The styles object, may contain `$` property for selector affix\n * @returns Array of selector suffixes, or null if invalid (with console warning)\n *\n * @example\n * getAllSelectors('Label', {})\n * // → [' [data-element=\"Label\"]']\n *\n * getAllSelectors('Cell', { $: '>, >Body>' })\n * // → ['> [data-element=\"Cell\"]', ' [data-element=\"Body\"] > [data-element=\"Cell\"]']\n */\nfunction getAllSelectors(key: string, styles?: Styles): string[] | null {\n if (key.startsWith('&')) {\n return [key.slice(1)];\n }\n\n if (key.startsWith('.')) {\n return [` ${key}`];\n }\n\n if (/^[A-Z]/.test(key)) {\n const affix = styles?.$;\n if (affix !== undefined) {\n const result = processAffix(String(affix), key);\n if (!result.valid) {\n console.warn(`[Tasty] ${result.reason}`);\n return null; // Skip this sub-element entirely\n }\n return result.selectors;\n }\n return [` [data-element=\"${key}\"]`];\n }\n\n return null;\n}\n\n/**\n * Process selector affix pattern and return selector(s)\n *\n * Supports:\n * - Direct child: '>'\n * - Chained elements: '>Body>Row>'\n * - HTML tags: 'a', '>ul>li', 'button:hover'\n * - Pseudo-elements on root: '::before'\n * - Pseudo on sub-element: '@::before', '>@:hover'\n * - Classes: '.active', '>@.active'\n * - Multiple selectors: '>, >Body>'\n * - Sibling combinators (after element): '>Item+', '>Item~'\n */\nfunction processAffix(affix: string, key: string): AffixResult {\n const trimmed = affix.trim();\n\n // Empty = default behavior (descendant selector with key)\n if (!trimmed) {\n return { valid: true, selectors: [` [data-element=\"${key}\"]`] };\n }\n\n // Split by comma for multiple selectors\n const patterns = trimmed.split(',').map((p) => p.trim());\n const selectors: string[] = [];\n\n for (const pattern of patterns) {\n const validation = validatePattern(pattern);\n if (!validation.valid) {\n return validation;\n }\n\n const selector = processSinglePattern(pattern, key);\n selectors.push(selector);\n }\n\n return { valid: true, selectors };\n}\n\n/**\n * Recognized token patterns for selector affix validation.\n *\n * These patterns are used to tokenize and validate `$` affix strings.\n * Order matters: more specific patterns must come first to avoid\n * partial matches (e.g., `::before` must match before `:` alone).\n *\n * Unrecognized tokens (like `#id`, `*`, or numbers) will cause validation to fail.\n */\nconst VALID_TOKEN_PATTERNS = [\n /^[>+~]/, // Combinators: >, +, ~\n /^[A-Z][a-zA-Z0-9]*/, // Uppercase element names → [data-element=\"...\"]\n /^@/, // @ placeholder for key injection position\n /^::?[a-z][a-z0-9-]*(?:\\([^)]*\\))?/, // Pseudo-elements/classes (:hover, ::before, :not(.x))\n /^\\.[a-zA-Z_-][a-zA-Z0-9_-]*/, // Class selectors (.active, .is-open)\n /^\\[[^\\]]+\\]/, // Attribute selectors ([type=\"text\"], [role])\n /^[a-z][a-z0-9-]*/, // HTML tag names (a, div, button, my-component)\n /^\\s+/, // Whitespace (ignored during parsing)\n /^&/, // Root reference (stripped, kept for backward compat)\n];\n\n/**\n * Scan a pattern for unrecognized tokens.\n *\n * Iterates through the pattern, consuming recognized tokens until\n * either the pattern is fully consumed (valid) or an unrecognized\n * character sequence is found (invalid).\n *\n * @param pattern - The selector pattern to validate\n * @returns The first unrecognized token found, or null if all tokens are valid\n *\n * @example\n * findUnrecognizedTokens('>Body>Row>') // → null (valid)\n * findUnrecognizedTokens('123') // → '123' (invalid)\n * findUnrecognizedTokens('#myId') // → '#' (invalid)\n */\nfunction findUnrecognizedTokens(pattern: string): string | null {\n let remaining = pattern;\n\n while (remaining.length > 0) {\n let matched = false;\n\n for (const regex of VALID_TOKEN_PATTERNS) {\n const match = remaining.match(regex);\n if (match) {\n remaining = remaining.slice(match[0].length);\n matched = true;\n break;\n }\n }\n\n if (!matched) {\n // Found unrecognized content - extract the problematic part\n const unrecognized = remaining.match(/^[^\\s>+~@.:[\\]A-Z]+/);\n return unrecognized ? unrecognized[0] : remaining[0];\n }\n }\n\n return null;\n}\n\n/**\n * Validate a selector pattern for structural correctness.\n *\n * Checks for:\n * 1. Out-of-scope selectors: Patterns starting with `+` or `~` target siblings\n * of the root element, which is outside the component's DOM scope.\n * 2. Consecutive combinators: Patterns like `>>` or `>+` are malformed CSS.\n * 3. Unrecognized tokens: Characters/sequences not matching valid CSS selectors.\n *\n * @param pattern - A single selector pattern (already split by comma)\n * @returns AffixResult indicating validity and error reason if invalid\n *\n * @example\n * validatePattern('>Body>Row>') // → { valid: true, selectors: [] }\n * validatePattern('+') // → { valid: false, reason: '...outside root scope...' }\n * validatePattern('>>') // → { valid: false, reason: '...consecutive combinators...' }\n */\nfunction validatePattern(pattern: string): AffixResult {\n const trimmed = pattern.trim();\n\n // Patterns starting with + or ~ target siblings of the root element,\n // which is outside the component's scope. Valid sibling patterns must\n // be preceded by an element: \">Item+\", \">Item~\"\n if (/^[+~]/.test(trimmed)) {\n return {\n valid: false,\n reason:\n `Selector affix \"${pattern}\" targets elements outside the root scope. ` +\n `Sibling selectors (+, ~) must be preceded by an element inside the root. ` +\n `Use \">Element+\" or \">Element~\" instead.`,\n };\n }\n\n // Check for consecutive combinators\n if (/[>+~]{2,}/.test(trimmed.replace(/\\s+/g, ''))) {\n return {\n valid: false,\n reason: `Selector affix \"${pattern}\" contains consecutive combinators.`,\n };\n }\n\n // Check for unrecognized tokens (e.g., lowercase text like \"foo\")\n const unrecognized = findUnrecognizedTokens(trimmed);\n if (unrecognized) {\n return {\n valid: false,\n reason:\n `Selector affix \"${pattern}\" contains unrecognized token \"${unrecognized}\". ` +\n `Valid tokens: combinators (>, +, ~), element names (Uppercase), ` +\n `@ placeholder, pseudo (:hover, ::before), class (.name), attribute ([attr]).`,\n };\n }\n\n return { valid: true, selectors: [] };\n}\n\n/**\n * Process a single selector pattern into a CSS selector suffix.\n *\n * This is the main transformation function that converts a `$` affix pattern\n * into a valid CSS selector suffix. It handles:\n *\n * 1. `@` placeholder replacement with `[data-element=\"key\"]`\n * 2. Key injection based on pattern ending (see `shouldInjectKey`)\n * 3. Proper spacing for descendant vs direct child selectors\n *\n * @param pattern - A single validated selector pattern\n * @param key - The sub-element key to inject (e.g., 'Label', 'Cell')\n * @returns CSS selector suffix ready to append to the root selector\n *\n * @example\n * processSinglePattern('>', 'Row')\n * // → '> [data-element=\"Row\"]'\n *\n * processSinglePattern('>Body>Row>', 'Cell')\n * // → '> [data-element=\"Body\"] > [data-element=\"Row\"] > [data-element=\"Cell\"]'\n *\n * processSinglePattern('::before', 'Before')\n * // → '::before' (no key injection for pseudo on root)\n *\n * processSinglePattern('>@:hover', 'Item')\n * // → '> [data-element=\"Item\"]:hover'\n */\nfunction processSinglePattern(pattern: string, key: string): string {\n // Strip leading & if present (implicit root reference, kept for compat)\n const normalized = pattern.replace(/^&/, '').trim();\n\n if (!normalized) {\n return ` [data-element=\"${key}\"]`;\n }\n\n // Pseudo-elements/classes at start apply directly to root (no space prefix)\n const startsWithPseudo = /^::?[a-z]/.test(normalized);\n\n // Transform the pattern: convert element names and normalize spacing\n let result = transformPattern(normalized);\n\n // Handle @ placeholder: explicit key injection position\n if (result.includes('@')) {\n // Remove space between @ and following class/pseudo for proper attachment\n // e.g., \"@ .active\" → \"[el].active\", but \"@ > span\" → \"[el] > span\"\n result = result.replace(/@ (?=[.:])/g, '@');\n result = result.replace(/@/g, `[data-element=\"${key}\"]`);\n\n if (!startsWithPseudo && !result.startsWith(' ')) {\n result = ' ' + result;\n }\n return result;\n }\n\n // Auto-inject key based on pattern ending (see shouldInjectKey for rules)\n if (shouldInjectKey(normalized)) {\n result = result + ' ' + `[data-element=\"${key}\"]`;\n }\n\n // Add space prefix for selectors targeting inside root (not pseudo on root)\n if (!startsWithPseudo && !result.startsWith(' ')) {\n result = ' ' + result;\n }\n\n return result;\n}\n\n/**\n * Transform a selector pattern by converting element names and normalizing spacing.\n *\n * This is a character-by-character tokenizer that:\n * - Converts uppercase names to `[data-element=\"Name\"]` selectors\n * - Adds proper spacing around combinators (>, +, ~)\n * - Preserves lowercase tags, classes, pseudos, and attributes as-is\n * - Keeps @ placeholder for later replacement\n *\n * The tokenizer handles these token types in order:\n * 1. Whitespace (skipped)\n * 2. Combinators: >, +, ~ (add surrounding spaces)\n * 3. Uppercase names: Body, Row (convert to [data-element=\"...\"])\n * 4. @ placeholder (keep for later replacement)\n * 5. Pseudo: :hover, ::before (attach to previous token)\n * 6. Tags: a, div, button (keep as-is with spacing)\n * 7. Classes: .active (attach to previous element/tag/placeholder)\n * 8. Attributes: [type=\"text\"] (keep as-is)\n *\n * @param pattern - The raw selector pattern to transform\n * @returns Transformed pattern with proper CSS selector syntax\n *\n * @example\n * transformPattern('>Body>Row>')\n * // → '> [data-element=\"Body\"] > [data-element=\"Row\"] >'\n *\n * transformPattern('button.primary:hover')\n * // → 'button.primary:hover'\n */\nfunction transformPattern(pattern: string): string {\n let result = '';\n let i = 0;\n\n while (i < pattern.length) {\n const char = pattern[i];\n\n // Skip whitespace\n if (/\\s/.test(char)) {\n i++;\n continue;\n }\n\n // Combinator: > + ~\n if (/[>+~]/.test(char)) {\n // Add combinator with surrounding spaces\n if (result && !result.endsWith(' ')) {\n result += ' ';\n }\n result += char;\n i++;\n continue;\n }\n\n // Uppercase element name\n if (/[A-Z]/.test(char)) {\n // Read the full element name\n let name = '';\n while (i < pattern.length && /[a-zA-Z0-9]/.test(pattern[i])) {\n name += pattern[i];\n i++;\n }\n // Add with proper spacing\n if (result && !result.endsWith(' ')) {\n result += ' ';\n }\n result += `[data-element=\"${name}\"]`;\n continue;\n }\n\n // @ placeholder\n if (char === '@') {\n if (result && !result.endsWith(' ')) {\n result += ' ';\n }\n result += '@';\n i++;\n // Don't add space after @ - let the next token attach if it's a class/pseudo\n continue;\n }\n\n // Pseudo-element/class (::before, :hover)\n if (char === ':') {\n // Don't add space before pseudo if attached to previous element\n let pseudo = '';\n while (\n i < pattern.length &&\n !/[\\s>+~,@]/.test(pattern[i]) &&\n !/[A-Z]/.test(pattern[i])\n ) {\n pseudo += pattern[i];\n i++;\n }\n result += pseudo;\n continue;\n }\n\n // Lowercase HTML tag name (a, div, button, my-component)\n if (/[a-z]/.test(char)) {\n let tag = '';\n while (i < pattern.length && /[a-z0-9-]/.test(pattern[i])) {\n tag += pattern[i];\n i++;\n }\n // Add with proper spacing\n if (result && !result.endsWith(' ')) {\n result += ' ';\n }\n result += tag;\n continue;\n }\n\n // Class (.active, .myClass, .navItem)\n if (char === '.') {\n // Keep attached if directly after ] (element), @ (placeholder), or alphanumeric (tag)\n // Otherwise add space (standalone class selector)\n const lastNonSpace = result.replace(/\\s+$/, '').slice(-1);\n const attachToLast =\n lastNonSpace === ']' ||\n lastNonSpace === '@' ||\n /[a-zA-Z0-9-]/.test(lastNonSpace);\n if (result && !attachToLast && !result.endsWith(' ')) {\n result += ' ';\n }\n // Start with the dot\n let cls = '.';\n i++;\n // Class names can contain uppercase letters (camelCase, BEM, etc.)\n // Stop at: whitespace, combinators, comma, @, or new token starters (. : [)\n while (i < pattern.length && /[a-zA-Z0-9_-]/.test(pattern[i])) {\n cls += pattern[i];\n i++;\n }\n result += cls;\n continue;\n }\n\n // Attribute selector [...]\n if (char === '[') {\n // Keep attached if directly after ] (element), @ (placeholder), or alphanumeric (tag)\n // Otherwise add space (standalone attribute selector)\n const lastNonSpace = result.replace(/\\s+$/, '').slice(-1);\n const attachToLast =\n lastNonSpace === ']' ||\n lastNonSpace === '@' ||\n /[a-zA-Z0-9-]/.test(lastNonSpace);\n if (result && !attachToLast && !result.endsWith(' ')) {\n result += ' ';\n }\n let attr = '';\n let depth = 0;\n while (i < pattern.length) {\n attr += pattern[i];\n if (pattern[i] === '[') depth++;\n if (pattern[i] === ']') depth--;\n i++;\n if (depth === 0) break;\n }\n result += attr;\n continue;\n }\n\n // Other characters - just append\n result += char;\n i++;\n }\n\n return result;\n}\n\n/**\n * Determine if the sub-element key should be auto-injected based on pattern ending.\n *\n * Key injection rules (when no @ placeholder is present):\n *\n * | Pattern Ending | Inject Key? | Example | Result |\n * |----------------|-------------|---------|--------|\n * | Combinator (>, +, ~) | Yes | `'>Body>'` | `> [data-element=\"Body\"] > [el]` |\n * | Uppercase element | Yes | `'>Body>Row'` | `> [el1] > [el2] [key]` |\n * | Lowercase tag | Yes | `'>ul>li'` | `> ul > li [key]` |\n * | Pseudo (:hover, ::before) | No | `'::before'` | `::before` |\n * | Class (.active) | No | `'.active'` | `.active` |\n * | Attribute ([type]) | No | `'[type=\"text\"]'` | `[type=\"text\"]` |\n *\n * @param pattern - The normalized pattern (after stripping &)\n * @returns true if key should be injected, false otherwise\n *\n * @example\n * shouldInjectKey('>') // → true (trailing combinator)\n * shouldInjectKey('>Body>Row') // → true (ends with element)\n * shouldInjectKey('>ul>li') // → true (ends with tag)\n * shouldInjectKey('::before') // → false (ends with pseudo)\n * shouldInjectKey('.active') // → false (ends with class)\n * shouldInjectKey('a:hover') // → false (ends with pseudo)\n * shouldInjectKey('button.primary') // → false (ends with class)\n */\nfunction shouldInjectKey(pattern: string): boolean {\n const trimmed = pattern.trim();\n\n // Rule 1: Ends with combinator → inject key after it\n // e.g., '>' → '> [data-element=\"Key\"]'\n if (/[>+~]$/.test(trimmed)) {\n return true;\n }\n\n // Rule 2: Ends with uppercase element name → inject key as descendant\n // The lookbehind ensures we're matching a standalone element name, not\n // part of a class like .myClass (where C is preceded by lowercase)\n // e.g., '>Body' → '> [data-element=\"Body\"] [data-element=\"Key\"]'\n if (/(?:^|[\\s>+~\\]:])[A-Z][a-zA-Z0-9]*$/.test(trimmed)) {\n return true;\n }\n\n // Rule 3: Ends with lowercase tag name → inject key as descendant\n // The negative lookbehind (?<![:.]) ensures we don't match:\n // - ':hover' (pseudo ending)\n // - '.primary' (class ending)\n // e.g., '>ul>li' → '> ul > li [data-element=\"Key\"]'\n if (/(?<![:.])(?:^|[\\s>+~])[a-z][a-z0-9-]*$/.test(trimmed)) {\n return true;\n }\n\n // Rule 4: Otherwise (pseudo, class, attribute) → no injection\n // The pattern is complete as-is, applying to root or a specific selector\n return false;\n}\n\n/**\n * Normalize selector suffix from $ property\n */\nfunction normalizeSelectorSuffix(suffix: string): string {\n if (!suffix) return '';\n return suffix.startsWith('&') ? suffix.slice(1) : suffix;\n}\n\n/**\n * Build handler queue from style keys\n */\nfunction buildHandlerQueue(\n styleKeys: string[],\n styles: Styles,\n): { handler: StyleHandler; styleMap: StyleMap }[] {\n const queue: { handler: StyleHandler; styleMap: StyleMap }[] = [];\n const seenHandlers = new Set<StyleHandler>();\n\n for (const styleName of styleKeys) {\n let handlers: StyleHandler[] = STYLE_HANDLER_MAP[styleName];\n\n if (!handlers) {\n handlers = STYLE_HANDLER_MAP[styleName] = [createStyle(styleName)];\n }\n\n for (const handler of handlers) {\n if (seenHandlers.has(handler)) continue;\n seenHandlers.add(handler);\n\n const lookupStyles = handler.__lookupStyles;\n const styleMap: StyleMap = {};\n\n for (const name of lookupStyles) {\n const val = styles[name];\n if (val !== undefined) {\n styleMap[name] = val as StyleValue | StyleValueStateMap;\n }\n }\n\n queue.push({ handler, styleMap });\n }\n }\n\n return queue;\n}\n\n/**\n * Compute all valid state combinations for a handler's lookup styles\n */\nfunction computeStateCombinations(\n exclusiveByStyle: Map<string, ExclusiveStyleEntry[]>,\n lookupStyles: string[],\n): { condition: ConditionNode; values: Record<string, StyleValue> }[] {\n // Get entries for each style\n const entriesPerStyle = lookupStyles.map(\n (style) => exclusiveByStyle.get(style) || [],\n );\n\n // Cartesian product of all combinations\n const combinations = cartesianProduct(entriesPerStyle);\n\n // Build snapshots, simplifying and filtering impossible combinations\n const snapshots: {\n condition: ConditionNode;\n values: Record<string, StyleValue>;\n }[] = [];\n\n for (const combo of combinations) {\n // Combine all exclusive conditions with AND\n const conditions = combo.map((e) => e.exclusiveCondition);\n const combined = and(...conditions);\n const simplified = simplifyCondition(combined);\n\n // Skip impossible combinations\n if (simplified.kind === 'false') continue;\n\n // Build values map\n const values: Record<string, StyleValue> = {};\n for (const entry of combo) {\n values[entry.styleKey] = entry.value;\n }\n\n snapshots.push({\n condition: simplified,\n values,\n });\n }\n\n return snapshots;\n}\n\n/**\n * Cartesian product of arrays\n */\nfunction cartesianProduct<T>(arrays: T[][]): T[][] {\n if (arrays.length === 0) return [[]];\n\n // Filter out empty arrays\n const nonEmpty = arrays.filter((a) => a.length > 0);\n if (nonEmpty.length === 0) return [[]];\n\n return nonEmpty.reduce<T[][]>(\n (acc, arr) => acc.flatMap((combo) => arr.map((item) => [...combo, item])),\n [[]],\n );\n}\n\n/**\n * Merge rules with identical CSS output\n */\nfunction mergeByValue(rules: ComputedRule[]): ComputedRule[] {\n // Group by selectorSuffix + declarations\n const groups = new Map<string, ComputedRule[]>();\n\n for (const rule of rules) {\n const key = `${rule.selectorSuffix}|${JSON.stringify(rule.declarations)}`;\n if (!groups.has(key)) {\n groups.set(key, []);\n }\n groups.get(key)!.push(rule);\n }\n\n // Merge conditions with OR for each group\n const merged: ComputedRule[] = [];\n\n for (const [, groupRules] of groups) {\n if (groupRules.length === 1) {\n merged.push(groupRules[0]);\n } else {\n // Merge conditions with OR\n const mergedCondition = simplifyCondition(\n or(...groupRules.map((r) => r.condition)),\n );\n merged.push({\n condition: mergedCondition,\n declarations: groupRules[0].declarations,\n selectorSuffix: groupRules[0].selectorSuffix,\n });\n }\n }\n\n return merged;\n}\n\n/**\n * Build selector fragment from a variant (without className prefix)\n */\nfunction buildSelectorFromVariant(\n variant: SelectorVariant,\n selectorSuffix: string,\n): string {\n let selector = '';\n\n // Add modifier selectors\n for (const mod of variant.modifierConditions) {\n selector += modifierToCSS(mod);\n }\n\n // Add pseudo selectors\n for (const pseudo of variant.pseudoConditions) {\n selector += pseudoToCSS(pseudo);\n }\n\n // Add parent selectors (before sub-element suffix)\n if (variant.parentGroups.length > 0) {\n selector += parentGroupsToCSS(variant.parentGroups);\n }\n\n selector += selectorSuffix;\n\n // Add own selectors (after sub-element)\n for (const own of variant.ownConditions) {\n selector += selectorConditionToCSS(own);\n }\n\n return selector;\n}\n\n/**\n * Materialize a computed rule to final CSS format\n *\n * Returns an array because OR conditions may generate multiple CSS rules\n * (when different branches have different at-rules)\n */\nfunction materializeComputedRule(rule: ComputedRule): CSSRule[] {\n const components = conditionToCSS(rule.condition);\n\n if (components.isImpossible || components.variants.length === 0) {\n return [];\n }\n\n const declarations = Object.entries(rule.declarations)\n .map(([prop, value]) => `${prop}: ${value};`)\n .join(' ');\n\n // Helper to get root prefix key for grouping\n const getRootPrefixKey = (variant: SelectorVariant): string => {\n return variant.rootConditions\n .map((r) => selectorConditionToCSS(r))\n .sort()\n .join('|');\n };\n\n // Group variants by their at-rules (variants with same at-rules can be combined with commas)\n const byAtRules = new Map<\n string,\n { variants: SelectorVariant[]; atRules: string[]; rootPrefix?: string }\n >();\n\n for (const variant of components.variants) {\n const atRules = buildAtRulesFromVariant(variant);\n const key = atRules.sort().join('|||') + '###' + getRootPrefixKey(variant);\n\n const group = byAtRules.get(key);\n if (group) {\n group.variants.push(variant);\n } else {\n byAtRules.set(key, {\n variants: [variant],\n atRules,\n rootPrefix: rootConditionsToCSS(variant.rootConditions),\n });\n }\n }\n\n // Generate one CSSRule per at-rules group\n const rules: CSSRule[] = [];\n for (const [, group] of byAtRules) {\n // Build selector fragments for each variant (will be joined with className later)\n const selectorFragments = group.variants.map((v) =>\n buildSelectorFromVariant(v, rule.selectorSuffix),\n );\n\n // Store as array if multiple, string if single\n const selector =\n selectorFragments.length === 1 ? selectorFragments[0] : selectorFragments;\n\n const cssRule: CSSRule = {\n selector,\n declarations,\n };\n\n if (group.atRules.length > 0) {\n cssRule.atRules = group.atRules;\n }\n\n if (group.rootPrefix) {\n cssRule.rootPrefix = group.rootPrefix;\n }\n\n rules.push(cssRule);\n }\n\n return rules;\n}\n\n// ============================================================================\n// Public API: renderStyles (compatible with old API)\n// ============================================================================\n\n/**\n * Options for renderStyles when using direct selector mode.\n */\nexport interface RenderStylesOptions {\n /**\n * Whether to double the class selector for increased specificity.\n * When true, `.myClass` becomes `.myClass.myClass` for higher specificity.\n *\n * @default false - User-provided selectors are not doubled.\n *\n * Note: This only applies when a classNameOrSelector is provided.\n * When renderStyles returns RenderResult with needsClassName=true,\n * the injector handles doubling automatically.\n */\n doubleSelector?: boolean;\n}\n\n/**\n * Render styles to CSS rules.\n *\n * When called without classNameOrSelector, returns RenderResult with needsClassName=true.\n * When called with a selector/className string, returns StyleResult[] for direct injection.\n */\nexport function renderStyles(styles?: Styles): RenderResult;\nexport function renderStyles(\n styles: Styles | undefined,\n classNameOrSelector: string,\n options?: RenderStylesOptions,\n): StyleResult[];\nexport function renderStyles(\n styles?: Styles,\n classNameOrSelector?: string,\n options?: RenderStylesOptions,\n): RenderResult | StyleResult[] {\n // Check if we have a direct selector/className\n const directSelector = !!classNameOrSelector;\n\n if (!styles) {\n return directSelector ? [] : { rules: [] };\n }\n\n // Check cache\n const cacheKey = stringifyStyles(styles);\n let rules = pipelineCache.get(cacheKey);\n\n if (!rules) {\n // Create parser context\n const parserContext = createStateParserContext(styles);\n\n // Run pipeline\n rules = runPipeline(styles, parserContext);\n\n // Cache result\n pipelineCache.set(cacheKey, rules);\n }\n\n // Direct selector/className mode: return StyleResult[] directly\n if (directSelector) {\n const shouldDouble = options?.doubleSelector ?? false;\n\n return rules.map((rule): StyleResult => {\n // Handle selector as array (OR conditions) or string\n const selectorParts = Array.isArray(rule.selector)\n ? rule.selector\n : rule.selector\n ? [rule.selector]\n : [''];\n\n const finalSelector = selectorParts\n .map((part) => {\n let sel = part\n ? `${classNameOrSelector}${part}`\n : classNameOrSelector;\n\n // Double class selector for increased specificity if requested\n // This is used when the caller explicitly wants higher specificity\n if (shouldDouble && sel.startsWith('.')) {\n const classMatch = sel.match(/^\\.[a-zA-Z_-][a-zA-Z0-9_-]*/);\n if (classMatch) {\n const baseClass = classMatch[0];\n sel = baseClass + sel;\n }\n }\n\n // Handle root prefix for this selector\n if (rule.rootPrefix) {\n sel = `${rule.rootPrefix} ${sel}`;\n }\n\n return sel;\n })\n .join(', ');\n\n const result: StyleResult = {\n selector: finalSelector,\n declarations: rule.declarations,\n };\n\n if (rule.atRules && rule.atRules.length > 0) {\n result.atRules = rule.atRules;\n }\n\n return result;\n });\n }\n\n // No className mode: return RenderResult with needsClassName flag\n // Normalize selector to string (join array with placeholder that injector will handle)\n return {\n rules: rules.map(\n (r): StyleResult => ({\n selector: Array.isArray(r.selector)\n ? r.selector.join('|||')\n : r.selector,\n declarations: r.declarations,\n atRules: r.atRules,\n needsClassName: true,\n rootPrefix: r.rootPrefix,\n }),\n ),\n };\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nexport type { ConditionNode } from './conditions';\nexport { and, or, not, trueCondition, falseCondition } from './conditions';\nexport { parseStateKey } from './parseStateKey';\nexport { simplifyCondition } from './simplify';\nexport { buildExclusiveConditions } from './exclusive';\nexport { conditionToCSS } from './materialize';\nexport type { CSSRule } from './materialize';\n"],"mappings":"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"}