Skip to content

Support dotted layer names in @layer at-rule prelude parsing#268

Merged
bartveneman merged 1 commit into
mainfrom
claude/layer-prelude-dot-parsing-r3kwql
Jul 11, 2026
Merged

Support dotted layer names in @layer at-rule prelude parsing#268
bartveneman merged 1 commit into
mainfrom
claude/layer-prelude-dot-parsing-r3kwql

Conversation

@bartveneman

Copy link
Copy Markdown
Member

Summary

This PR adds support for parsing dotted layer names (e.g., a.b.c) in CSS @layer at-rule prelude declarations, allowing nested layer references to be properly recognized and preserved.

Key Changes

  • Enhanced layer name parsing: Modified parse_layer_names() to recognize and preserve dotted notation in layer names by consuming consecutive . and <ident> tokens that immediately follow the initial identifier with no whitespace gaps
  • Whitespace sensitivity: Implemented strict position checking to ensure dots separated by whitespace are not glued to layer names (e.g., a. b parses as two separate names)
  • Token imports: Added TOKEN_DELIM import to support dot token detection
  • String utilities: Added CHAR_PERIOD constant for dot character code comparison
  • Comprehensive test coverage: Added four new test cases covering:
    • Dotted layer names mixed with simple names in comma-separated lists
    • Deeply nested dotted layer names (e.g., d.e.f)
    • Whitespace-separated dots not being attached to names
    • Improved assertion specificity for existing dotted layer name test

Implementation Details

The parser now uses a lookahead mechanism with position save/restore to safely attempt consuming dot-identifier segments. It validates that:

  1. The next token is a TOKEN_DELIM with character code matching CHAR_PERIOD
  2. The dot immediately follows the previous token (no whitespace gap)
  3. An identifier immediately follows the dot (no whitespace gap)

If any condition fails, the parser restores the previous position and stops consuming segments, allowing the comma separator or end of prelude to be processed normally.

https://claude.ai/code/session_01R9GWUSxhM3VVAWVFs9F5bG

parse_layer_names() only handled bare IDENT tokens, so a nested
layer name like a.b.c was tokenized as three separate LayerName
nodes with the connecting '.' silently discarded. Reprinting those
nodes as a comma list turned one nested layer into unrelated
top-level layers, changing cascade order.

Glue immediately-adjacent 'ident . ident' sequences (no whitespace
around the dot, per the <layer-name> grammar) into a single
LAYER_NAME node spanning the whole dotted name.
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Duplicate Dependencies (found: 35, threshold: 1)

📦 Package 📋 Versions
tinybench
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • vitest@4.1.9
        • tinybench@2.9.0

  • root@
    • tinybench@6.0.2

@babel/helper-validator-identifier
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • magicast@0.5.2
        • @babel/parser@7.29.3
          • @babel/types@7.29.0
            • @babel/helper-validator-identifier@7.28.5

  • root@
    • tsdown@0.22.3
      • ...
        • @babel/parser@8.0.0
          • @babel/types@8.0.0
            • @babel/helper-validator-identifier@8.0.2

js-tokens
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • ast-v8-to-istanbul@1.0.0
        • js-tokens@10.0.0

  • root@
    • tailwindcss@2.2.19
      • cosmiconfig@7.1.0
        • parse-json@5.2.0
          • @babel/code-frame@7.27.1
            • js-tokens@4.0.0

@babel/parser
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • magicast@0.5.2
        • @babel/parser@7.29.3

  • root@
    • tsdown@0.22.3
      • rolldown-plugin-dts@0.26.0
        • @babel/generator@8.0.0
          • @babel/parser@8.0.0

@babel/types
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • magicast@0.5.2
        • @babel/parser@7.29.3
          • @babel/types@7.29.0

  • root@
    • tsdown@0.22.3
      • rolldown-plugin-dts@0.26.0
        • @babel/generator@8.0.0
          • @babel/parser@8.0.0
            • @babel/types@8.0.0

@babel/helper-string-parser
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • magicast@0.5.2
        • @babel/parser@7.29.3
          • @babel/types@7.29.0
            • @babel/helper-string-parser@7.27.1

  • root@
    • tsdown@0.22.3
      • ...
        • @babel/parser@8.0.0
          • @babel/types@8.0.0
            • @babel/helper-string-parser@8.0.0

@emnapi/core
3 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • ...
        • rolldown@1.0.3
          • @rolldown/binding-wasm32-wasi@1.0.3
            • @emnapi/core@1.10.0

  • root@
    • knip@6.18.0
      • oxc-resolver@11.21.3
        • @oxc-resolver/binding-wasm32-wasi@11.21.3
          • @emnapi/core@1.11.0

  • root@
    • knip@6.18.0
      • oxc-parser@0.137.0
        • @oxc-parser/binding-wasm32-wasi@0.137.0
          • @emnapi/core@1.11.1

@emnapi/wasi-threads
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • ...
        • @rolldown/binding-wasm32-wasi@1.0.3
          • @emnapi/core@1.10.0
            • @emnapi/wasi-threads@1.2.1

  • root@
    • knip@6.18.0
      • oxc-parser@0.137.0
        • @oxc-parser/binding-wasm32-wasi@0.137.0
          • @emnapi/core@1.11.1
            • @emnapi/wasi-threads@1.2.2

@emnapi/runtime
3 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • ...
        • rolldown@1.0.3
          • @rolldown/binding-wasm32-wasi@1.0.3
            • @emnapi/runtime@1.10.0

  • root@
    • knip@6.18.0
      • oxc-resolver@11.21.3
        • @oxc-resolver/binding-wasm32-wasi@11.21.3
          • @emnapi/runtime@1.11.0

  • root@
    • knip@6.18.0
      • oxc-parser@0.137.0
        • @oxc-parser/binding-wasm32-wasi@0.137.0
          • @emnapi/runtime@1.11.1

@rolldown/binding-wasm32-wasi
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • ...
        • vite@8.0.16
          • rolldown@1.0.3
            • @rolldown/binding-wasm32-wasi@1.0.3

  • root@
    • tsdown@0.22.3
      • rolldown@1.1.2
        • @rolldown/binding-wasm32-wasi@1.1.2

obug
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • obug@2.1.1

  • root@
    • tsdown@0.22.3
      • obug@2.1.3

picomatch
2 versions
  • root@
    • tailwindcss@2.2.19
      • chokidar@3.6.0
        • anymatch@3.1.3
          • picomatch@2.3.2

  • root@
    • @vitest/coverage-v8@4.1.9
      • vitest@4.1.9
        • @vitest/mocker@4.1.9
          • vite@8.0.16
            • picomatch@4.0.4

postcss-value-parser
2 versions
  • root@
    • tailwindcss@2.2.19
      • reduce-css-calc@2.1.8
        • postcss-value-parser@3.3.1

  • root@
    • tailwindcss@2.2.19
      • autoprefixer@10.4.23
        • postcss-value-parser@4.2.0

glob-parent
2 versions
  • root@
    • tailwindcss@2.2.19
      • chokidar@3.6.0
        • glob-parent@5.1.2

  • root@
    • tailwindcss@2.2.19
      • glob-parent@6.0.2

yaml
2 versions
  • root@
    • tailwindcss@2.2.19
      • cosmiconfig@7.1.0
        • yaml@1.10.3

  • root@
    • @vitest/coverage-v8@4.1.9
      • vitest@4.1.9
        • @vitest/mocker@4.1.9
          • vite@8.0.16
            • yaml@2.9.0

is-arrayish
2 versions
  • root@
    • tailwindcss@2.2.19
      • cosmiconfig@7.1.0
        • parse-json@5.2.0
          • error-ex@1.3.4
            • is-arrayish@0.2.1

  • root@
    • tailwindcss@2.2.19
      • color@4.2.3
        • color-string@1.9.1
          • simple-swizzle@0.2.4
            • is-arrayish@0.3.4

get-tsconfig
2 versions
  • root@
    • knip@6.18.0
      • get-tsconfig@4.14.0

  • root@
    • tsdown@0.22.3
      • rolldown-plugin-dts@0.26.0
        • get-tsconfig@5.0.0-beta.5

semver
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • istanbul-lib-report@3.0.1
        • make-dir@4.0.0
          • semver@7.8.0

  • root@
    • tsdown@0.22.3
      • semver@7.8.5

@oxc-project/types
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • ...
        • vite@8.0.16
          • rolldown@1.0.3
            • @oxc-project/types@0.133.0

  • root@
    • knip@6.18.0
      • oxc-parser@0.137.0
        • @oxc-project/types@0.137.0

rolldown
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • vitest@4.1.9
        • @vitest/mocker@4.1.9
          • vite@8.0.16
            • rolldown@1.0.3

  • root@
    • tsdown@0.22.3
      • rolldown@1.1.2

@rolldown/binding-android-arm64
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • ...
        • vite@8.0.16
          • rolldown@1.0.3
            • @rolldown/binding-android-arm64@1.0.3

  • root@
    • tsdown@0.22.3
      • rolldown@1.1.2
        • @rolldown/binding-android-arm64@1.1.2

@rolldown/binding-darwin-arm64
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • ...
        • vite@8.0.16
          • rolldown@1.0.3
            • @rolldown/binding-darwin-arm64@1.0.3

  • root@
    • tsdown@0.22.3
      • rolldown@1.1.2
        • @rolldown/binding-darwin-arm64@1.1.2

@rolldown/binding-darwin-x64
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • ...
        • vite@8.0.16
          • rolldown@1.0.3
            • @rolldown/binding-darwin-x64@1.0.3

  • root@
    • tsdown@0.22.3
      • rolldown@1.1.2
        • @rolldown/binding-darwin-x64@1.1.2

@rolldown/binding-freebsd-x64
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • ...
        • vite@8.0.16
          • rolldown@1.0.3
            • @rolldown/binding-freebsd-x64@1.0.3

  • root@
    • tsdown@0.22.3
      • rolldown@1.1.2
        • @rolldown/binding-freebsd-x64@1.1.2

@rolldown/binding-linux-arm-gnueabihf
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • ...
        • vite@8.0.16
          • rolldown@1.0.3
            • @rolldown/binding-linux-arm-gnueabihf@1.0.3

  • root@
    • tsdown@0.22.3
      • rolldown@1.1.2
        • @rolldown/binding-linux-arm-gnueabihf@1.1.2

@rolldown/binding-linux-arm64-gnu
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • ...
        • vite@8.0.16
          • rolldown@1.0.3
            • @rolldown/binding-linux-arm64-gnu@1.0.3

  • root@
    • tsdown@0.22.3
      • rolldown@1.1.2
        • @rolldown/binding-linux-arm64-gnu@1.1.2

@rolldown/binding-linux-arm64-musl
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • ...
        • vite@8.0.16
          • rolldown@1.0.3
            • @rolldown/binding-linux-arm64-musl@1.0.3

  • root@
    • tsdown@0.22.3
      • rolldown@1.1.2
        • @rolldown/binding-linux-arm64-musl@1.1.2

@rolldown/binding-linux-ppc64-gnu
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • ...
        • vite@8.0.16
          • rolldown@1.0.3
            • @rolldown/binding-linux-ppc64-gnu@1.0.3

  • root@
    • tsdown@0.22.3
      • rolldown@1.1.2
        • @rolldown/binding-linux-ppc64-gnu@1.1.2

@rolldown/binding-linux-s390x-gnu
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • ...
        • vite@8.0.16
          • rolldown@1.0.3
            • @rolldown/binding-linux-s390x-gnu@1.0.3

  • root@
    • tsdown@0.22.3
      • rolldown@1.1.2
        • @rolldown/binding-linux-s390x-gnu@1.1.2

@rolldown/binding-linux-x64-gnu
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • ...
        • vite@8.0.16
          • rolldown@1.0.3
            • @rolldown/binding-linux-x64-gnu@1.0.3

  • root@
    • tsdown@0.22.3
      • rolldown@1.1.2
        • @rolldown/binding-linux-x64-gnu@1.1.2

@rolldown/binding-linux-x64-musl
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • ...
        • vite@8.0.16
          • rolldown@1.0.3
            • @rolldown/binding-linux-x64-musl@1.0.3

  • root@
    • tsdown@0.22.3
      • rolldown@1.1.2
        • @rolldown/binding-linux-x64-musl@1.1.2

@rolldown/binding-openharmony-arm64
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • ...
        • vite@8.0.16
          • rolldown@1.0.3
            • @rolldown/binding-openharmony-arm64@1.0.3

  • root@
    • tsdown@0.22.3
      • rolldown@1.1.2
        • @rolldown/binding-openharmony-arm64@1.1.2

@rolldown/binding-win32-arm64-msvc
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • ...
        • vite@8.0.16
          • rolldown@1.0.3
            • @rolldown/binding-win32-arm64-msvc@1.0.3

  • root@
    • tsdown@0.22.3
      • rolldown@1.1.2
        • @rolldown/binding-win32-arm64-msvc@1.1.2

@rolldown/binding-win32-x64-msvc
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • ...
        • vite@8.0.16
          • rolldown@1.0.3
            • @rolldown/binding-win32-x64-msvc@1.0.3

  • root@
    • tsdown@0.22.3
      • rolldown@1.1.2
        • @rolldown/binding-win32-x64-msvc@1.1.2

tinyexec
2 versions
  • root@
    • @vitest/coverage-v8@4.1.9
      • vitest@4.1.9
        • tinyexec@1.1.2

  • root@
    • tsdown@0.22.3
      • tinyexec@1.2.4

💡 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 kB 41.1 kB +78 B

@bartveneman bartveneman merged commit c428a0b into main Jul 11, 2026
8 checks passed
@bartveneman bartveneman deleted the claude/layer-prelude-dot-parsing-r3kwql branch July 11, 2026 18:11
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.

2 participants