css_ruleset_parser.ts

CSS ruleset parser using Svelte's CSS parser.

Parses CSS rulesets to extract selectors and declarations with position information. Used for: - Phase 0a: Detecting single-selector rulesets that could be converted to declaration format - Phase 2: Modifying selectors for modifier support on composite classes

NOTE: We wrap CSS in a <style> tag for Svelte's parser. This adds an offset to positions. Line numbers in parser errors will be offset by 1. This is acceptable - Fuz will have its own CSS parser in the future.

Declarations
#

14 declarations

view source

extract_css_comment
#

css_ruleset_parser.ts view source

(css: string, rules: ParsedRule[]): string | null

Extracts the CSS comment from a ruleset (if any). Looks for comments before the first rule.

css

- Raw CSS string

type string

rules

- Parsed rules

type ParsedRule[]

returns

string | null

Comment text without delimiters, or null if no comment

find_compound_end
#

css_ruleset_parser.ts view source

(selector: string, class_pos: number): number

Finds the end position of the compound selector containing the class at class_pos. A compound selector is a sequence of simple selectors without combinators.

selector

- The CSS selector string

type string

class_pos

- Position of the . in .class_name

type number

returns

number

Position where state modifiers should be inserted (before any pseudo-element)

generate_modified_ruleset
#

css_ruleset_parser.ts view source

(original_ruleset: string, original_class: string, new_class_escaped: string, state_css: string, pseudo_element_css: string, media_wrapper: string | null, ancestor_wrapper: string | null): ModifiedRulesetResult

Generates CSS for a modified ruleset with applied modifiers.

Conflict handling is per-selector within selector lists: - For .plain:hover, .plain:active with hover: modifier, only .plain:hover skips the :hover addition; .plain:active still gets :hover appended. - For multiple states like :hover:focus, each is checked individually; conflicting states are skipped while non-conflicting ones are still applied.

original_ruleset

- The original CSS ruleset string

type string

original_class

- The base class name

type string

new_class_escaped

- The escaped new class name with modifiers

type string

state_css

- State modifier CSS (e.g., ":hover" or ":hover:focus")

type string

pseudo_element_css

- Pseudo-element modifier CSS (e.g., "::before")

type string

media_wrapper

- Media query wrapper (e.g., "@media (width >= 48rem)")

type string | null

ancestor_wrapper

- Ancestor wrapper (e.g., ":root.dark")

type string | null

returns

ModifiedRulesetResult

Result with generated CSS and information about skipped modifiers

is_single_selector_ruleset
#

css_ruleset_parser.ts view source

(rules: ParsedRule[], escaped_class_name: string): boolean

Checks if a ruleset has only a single simple selector (just the class name). Used to detect rulesets that could be converted to declaration format.

rules

- Parsed rules from the ruleset

type ParsedRule[]

escaped_class_name

- The CSS-escaped class name (e.g., "box" or "hover\\:card")

type string

returns

boolean

True if there's exactly one rule with selector ".class_name"

ModifiedRulesetResult
#

css_ruleset_parser.ts view source

ModifiedRulesetResult

Result from generating a modified ruleset.

Uses | null for skipped_modifiers to avoid allocating empty arrays. Callers should use a guard pattern: if (result.skipped_modifiers) { ... }

css

The generated CSS

type string

skipped_modifiers

Information about modifiers that were skipped for certain rules, or null if none

type Array<SkippedModifierInfo> | null

ModifiedSelectorGroupResult
#

css_ruleset_parser.ts view source

ModifiedSelectorGroupResult

Result from modifying a selector group with conflict detection.

Uses | null for skipped_modifiers to avoid allocating empty arrays. Callers should use a guard pattern: if (result.skipped_modifiers) { ... }

selector

The modified selector list as a string

type string

skipped_modifiers

Information about modifiers skipped for specific selectors, or null if none

type Array<SkippedModifierInfo> | null

modify_selector_group
#

css_ruleset_parser.ts view source

(selector_group: string, original_class: string, new_class_escaped: string, states_to_add: string[], pseudo_element_css: string): ModifiedSelectorGroupResult

Modifies a selector list (comma-separated selectors) to add modifiers. Handles conflicts per-selector: if one selector in a list has a conflict, only that selector skips the modifier; other selectors still get it.

selector_group

- CSS selector list (may contain commas)

type string

original_class

- The base class name

type string

new_class_escaped

- The escaped new class name

type string

states_to_add

- Individual state modifiers (e.g., [":hover", ":focus"])

type string[]

pseudo_element_css

- Pseudo-element modifier CSS to insert (e.g., "::before")

type string

returns

ModifiedSelectorGroupResult

Result with modified selector list and information about skipped modifiers

modify_single_selector
#

css_ruleset_parser.ts view source

(selector: string, original_class: string, new_class_escaped: string, state_css: string, pseudo_element_css: string): string

Modifies a single CSS selector to add modifiers.

selector

- A single CSS selector (not a selector list)

type string

original_class

- The base class name (e.g., "menu_item")

type string

new_class_escaped

- The escaped new class name (e.g., "hover\\:menu_item")

type string

state_css

- State modifier CSS to insert (e.g., ":hover")

type string

pseudo_element_css

- Pseudo-element modifier CSS to insert (e.g., "::before")

type string

returns

string

Modified selector

examples

Example 1

parse_ruleset
#

css_ruleset_parser.ts view source

(css: string): ParsedRuleset

Parses a CSS ruleset string using Svelte's CSS parser.

css

- Raw CSS string (e.g., ".box { display: flex; }")

type string

returns

ParsedRuleset

ParsedRuleset with structured rule data and positions

ParsedRule
#

css_ruleset_parser.ts view source

ParsedRule

A parsed CSS rule with its components and positions.

selector

Full selector string (e.g., ".box", ".selectable:hover")

type string

selector_start

Start position of selector in original CSS (0-indexed, relative to style wrapper)

type number

selector_end

End position of selector in original CSS

type number

declarations

The declarations block (without braces)

type string

rule_start

Start position of the entire rule

type number

rule_end

End position of the entire rule

type number

ParsedRuleset
#

css_ruleset_parser.ts view source

ParsedRuleset

Result of parsing a CSS ruleset.

rules

All rules in the ruleset

type Array<ParsedRule>

wrapper_offset

The offset added by the <style> wrapper (characters before actual CSS)

type number

ruleset_contains_class
#

css_ruleset_parser.ts view source

(rules: ParsedRule[], escaped_class_name: string): boolean

Checks if any selector in the ruleset contains the expected class name. Used to validate that ruleset definitions match their key.

rules

- Parsed rules from the ruleset

type ParsedRule[]

escaped_class_name

- The CSS-escaped class name (e.g., "clickable" or "hover\\:card")

type string

returns

boolean

True if at least one selector contains ".class_name"

SkippedModifierInfo
#

css_ruleset_parser.ts view source

SkippedModifierInfo

Information about a modifier that was skipped for a selector during ruleset modification. The selector is still included in output, just without the conflicting modifier applied.

selector

The specific selector where the modifier was skipped (not the full selector list)

type string

reason

Reason the modifier was skipped

type 'pseudo_element_conflict' | 'state_conflict'

conflicting_modifier

The conflicting modifier that was not applied (e.g., "::before" or ":hover")

type string

split_selector_list
#

css_ruleset_parser.ts view source

(selector_group: string): string[]

Splits a selector list by commas, respecting parentheses, brackets, and quoted strings.

selector_group

type string

returns

string[]

examples

Example 1

Imported by
#