Add support for CSS if() inline conditional function parsing - #253
Add support for CSS if() inline conditional function parsing#253bartveneman wants to merge 5 commits into
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #253 +/- ##
==========================================
+ Coverage 93.20% 93.25% +0.04%
==========================================
Files 17 17
Lines 3062 3262 +200
Branches 853 911 +58
==========================================
+ Hits 2854 3042 +188
- Misses 208 220 +12 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Bundle ReportChanges will increase total bundle size by 14.96kB (7.84%) ⬆️
Affected Assets, Files, and Routes:view changes for bundle: @projectwallace/css-parser-esmAssets Changed:
Files in
Files in
Files in
Files in
Files in
|
The CSS inline if() function uses colons and semicolons as structural delimiters (condition: value; condition: value; else: fallback). These were previously silently dropped inside function argument parsing. Now TOKEN_COLON and TOKEN_SEMICOLON produce OPERATOR nodes in value contexts, preserving the full structure of if(), style(), supports(), and media() condition functions in the AST.
Implements the CSS Values Level 5 grammar for inline if():
if( <if-branch>+ )
<if-branch> = <if-condition> : <declaration-value>? ;?
<if-condition> = style(…) | media(…) | supports(…) | else
Key changes:
- New IF_BRANCH (58) node type in the arena. Each condition/value pair
inside if() becomes an IfBranch node — a first-class AST node rather
than a flat list of tokens.
- IfBranch exposes:
.condition — the condition text ("style(--x: 1)", "else", …)
.value — the value text ("green", "red", …), or null if absent
.is_else — true on the else branch
.first_child — parsed condition node (Function or Identifier)
.children — condition node followed by parsed value nodes
- FUNCTION("if") children are exclusively IfBranch nodes; colons and
semicolons are structural separators and are not emitted as OPERATOR
nodes at the if() level.
- Condition functions (style(), supports(), media()) are generic FUNCTION
nodes. Their `:` separators are preserved as OPERATOR children (the
TOKEN_COLON → OPERATOR change from the previous commit), which is
correct for all three condition types.
- Nested if() functions are parsed recursively via the same dispatch in
parse_function_node().
- New is_if_branch() type predicate and IfBranch TypeScript type
exported from the public API.
style() and supports() conditions now produce a DECLARATION child (property + VALUE), media() conditions produce a MEDIA_FEATURE child (property + value children), and each IF_BRANCH value is wrapped in a VALUE node so branch.value returns a Value node instead of a raw string.
Rebasing onto main (which added RATIO = 58) collided with this branch's IF_BRANCH = 58, so IF_BRANCH moves to 59. Also widens Function's children type to include Declaration/MediaFeature, which if()'s style()/supports()/media() condition parsing produces but the type didn't account for.
69f376b to
689df0c
Compare
|
| 📦 Package | 📋 Versions |
|---|---|
| @emnapi/core | 3 versions
|
| @emnapi/runtime | 3 versions
|
| @oxc-project/types | 3 versions
|
💡 To find out what depends on a specific package, run: pnpm -r why example-package
⚠️ Package Size Increase
| 📦 Package | 📏 Base Size | 📏 Source Size | 📈 Size Change |
|---|---|---|---|
| @projectwallace/css-parser | 41.1 kB | 43.9 kB | +2.7 kB |
|
Rebased onto latest Generated by Claude Code |
- css-node.ts: use braces/newline for guard-clause return in IfBranch.condition getter - IfBranch.condition now returns the parsed condition node (Function | Identifier) instead of its raw text, matching first_child; text is still available via condition.text - parse-value.test.ts: rename abbreviated `idx` param to `index`, update condition assertions to .condition.text
Summary
This PR adds comprehensive support for parsing CSS
if()inline conditional functions (CSS Values Level 5 spec). The parser now recognizesif()functions and creates a dedicatedIF_BRANCHnode type to represent each condition-value pair within the function.Key Changes
New
IF_BRANCHnode type: Introduced a new AST node type to represent individual branches within anif()function, with properties for:condition: The condition text (e.g.,"style(--active: 1)"or"else")value: The value text between the colon and semicolon (ornullif empty)is_else: Boolean flag indicating if this is theelsebranchchildren: Parsed condition node followed by parsed value nodesDedicated
if()parser: Implementedparse_if_function_node()inValueParserthat:if()functions and dispatches to specialized parsing logicstyle(),supports(),media(), orelseidentifier)if()functions recursivelyToken handling: Extended operator parsing to include colons and semicolons as structural separators within
if()branchesType definitions: Added
IfBranchtype to the public API with proper TypeScript support and type guardsComprehensive test coverage: Added 30+ test cases covering:
style(),supports(),media(),else)if()functionsImplementation Details
The parser treats
if()as a special function that creates aFUNCTIONnode withIF_BRANCHchildren instead of generic value nodes. Each branch's condition and value are tracked separately through arena fields (contentStartDelta/contentLengthfor condition,valueStartDelta/valueLengthfor value), allowing efficient text extraction without reparsing. The implementation properly handles whitespace, malformed input, and maintains accurate source location information for all nodes.https://claude.ai/code/session_01UmLv7na8e3eUyPAZbjMf3U