Skip to content

Add @layer at-rule support to Lucius parser - #304

Open
jeongoon wants to merge 2 commits into
yesodweb:masterfrom
jeongoon:support-at-layer
Open

jeongoon wants to merge 2 commits into
yesodweb:masterfrom
jeongoon:support-at-layer

Conversation

@jeongoon

@jeongoon jeongoon commented Feb 6, 2026 •

Copy link
Copy Markdown
Contributor

Base: yesodweb/shakespeare master
Head: jeongoon/shakespeare support-at-layer


Summary

CSS @layer allows explicit cascade layer ordering for better CSS organization. This PR adds support for all three valid CSS forms:

  • Block form: @layer utilities { .class { prop: val; } }
  • Declaration form: @layer utilities; or @layer a, b, c;
  • Anonymous block: @layer { .class { prop: val; } }

Additionally, this PR enables recursive nesting of at-rules inside each other. Previously, at-rule blocks (@media, @supports, etc.) could only contain regular CSS blocks. Modern CSS commonly requires nesting at-rules, e.g.:

@layer components {
    @media (max-width: 600px) {
        .btn { font-size: 1.2rem; }
    }
}

Changes

  • Added layer parser to Text/Internal/Lucius.hs
  • Changed TopAtBlock to hold [TopLevel a] instead of [Block a] in Text/Internal/Css.hs
  • Updated parseBlocks to parse nested at-rules (media, supports, layer, topAtBlock) in addition to regular blocks
  • Updated compressTopLevel, cssUsedIdentifiers, renderCss, cssRuntime, topLevelsToCassius, and luciusRTInternal for recursive TopLevel handling
  • renderCss now supports nested indentation via goWith indent pattern
  • Added 16 test cases (8 unordered + 8 ordered) to test/Text/CssSpec.hs

Implementation notes

  • Uses try for backtracking between block and declaration forms for @layer
  • Uses many instead of many1 for the selector to support anonymous layers (empty selector)
  • Follows the same pattern as existing @media and @supports parsers
  • Nested at-rules reuse the same parseBlocks → at-rule parser path recursively

Backwards compatibility

TopAtBlock is exported from Text.Internal.Css which is marked "not stable API". Code that pattern-matches on TopAtBlock will need to update the third field from [Block a] to [TopLevel a].

Test plan

  • All 285 existing tests pass (293 total with new tests)
  • New @layer tests cover block, declaration, multiple declaration, and anonymous forms
  • New nested at-rule tests: @media inside @layer, @layer inside @media, @supports inside @layer, @media inside @media
  • Tests added for both ordered and unordered Lucius variants

References

jeongoon and others added 2 commits February 6, 2026 08:29
CSS @layer allows explicit cascade layer ordering. This adds support
for all three forms:

- Block form: @layer utilities { .class { prop: val; } }
- Declaration form: @layer utilities; or @layer a, b, c;
- Anonymous block: @layer { .class { prop: val; } }

The parser uses `many` instead of `many1` for the selector to support
anonymous layers (empty selector).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change TopAtBlock to hold [TopLevel a] instead of [Block a], enabling
recursive nesting of @media, @layer, @supports inside each other.
Update parser, compressor, renderer, compile-time and runtime resolvers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jeongoon

Copy link
Copy Markdown
Contributor Author

some tests fails only because it fails to download the compilers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant