Skip to content

feat(mint): add CSS Cascade Layers @layer structure audit - #111

Draft
nujovich wants to merge 5 commits into
mainfrom
hermes/build/mint-css-cascade-layers-audit
Draft

feat(mint): add CSS Cascade Layers @layer structure audit#111
nujovich wants to merge 5 commits into
mainfrom
hermes/build/mint-css-cascade-layers-audit

Conversation

@nujovich

@nujovich nujovich commented Aug 25, 2026

Copy link
Copy Markdown
Owner

Card: https://github.com/nujovich/mint-radar/issues/21

What: Adds a static lint rule that detects CSS Cascade Layers (@layer) structure. Milestone 1 introduced the CascadeLayerAudit type in lib/types.ts with layer names, declaration order, and rules-outside-layers detection, plus the lintCascadeLayers() function in lib/css-lint-rules.mjs that scans CSS source for @layer statements, @layer block declarations, and identifies style rules not enclosed in any layer (unlayered styles). Milestone 2 extends the parser to group rules by layer and detect two anti-patterns: !important inside layers and post-layer specificity. Milestone 3 adds a layer hierarchy visualization to the CLI lint output, with warnings when layer order is implicit rather than explicitly declared.

Why: CSS Cascade Layers (@layer) is Baseline since 2023 but no existing CLI tool audits layer ordering, detects rules outside layers, or surfaces unlayered style conflicts. Rules outside @layer take precedence over ALL layers, making them an anti-pattern in layered architectures. Mint can fill this gap with deterministic static analysis.

Milestones

  • Milestone 1 -- Add CascadeLayerAudit type system with detection of layer names, declaration order, and rules outside any layer
  • Milestone 2 -- Implement @layer parser that groups rules by layer and detects anti-patterns (post-layer specificity, !important inside layers)
  • Milestone 3 -- Add layer hierarchy visualization to the CLI output, with warnings for implicit vs explicit order
  • Milestone 4 -- Add test fixture with real-world multi-layer projects and tests

Milestone 2 detail

Extended lintCascadeLayers() in lib/css-lint-rules.mjs to:

  • Group rules by layer: a new rulesByLayer map on CascadeLayerAudit records each named @layer block's directly-nested style-rule selectors (anonymous @layer { } blocks are ignored).
  • Detect !important inside layers: any !important declaration inside a named layer emits an important-in-layer issue (severity warning) carrying the layer name, explaining that !important reverses layer priority and can make low-priority layers like resets win.
  • Detect post-layer specificity: an unlayered rule that appears after the first @layer declaration AND carries high specificity (an ID selector or !important) is flagged as post-layer-specificity (severity warning) instead of the generic rules-outside-layers suggestion, since unlayered styles already override every layer regardless of specificity.

CascadeLayerIssue now supports both suggestion and warning severities plus an optional layer field. Seven new unit tests cover grouping, both anti-patterns, and the low-specificity / no-layer edge cases.

Milestone 3 detail

Added a layer hierarchy visualization to the mint-ds lint CLI output plus implicit/explicit ordering warnings:

  • lib/types.ts: new LayerHierarchyEntry interface (name, rank, order, rulesCount) and two new fields on CascadeLayerAudit -- orderExplicit (boolean) and hierarchy (ordered entries, lowest priority first).
  • lib/css-lint-rules.mjs: lintCascadeLayers() now detects whether an explicit @layer a, b, c; statement established the order, and marks each layer as explicit (named in an order statement) or implicit (order derived from first appearance only).
  • bin/mint-ds.mjs: cmdLint renders a "Cascade Layers" section listing the hierarchy lowest-priority-first, tagging each layer as explicit/implicit with its rule count, and showing unlayered styles at the top. When no explicit order statement exists, it emits a WARN suggesting an explicit order statement.

Four new unit tests cover implicit vs explicit order detection, hierarchy shape (rank/order/rulesCount), and the empty-CSS case.

Milestone 4 detail

Added a real-world multi-layer test fixture and integration tests:

  • lib/__fixtures__/cascade-layers.css -- a design-system stylesheet with an explicit @layer reset, base, components, utilities; order statement, four named @layer blocks, legacy unlayered overrides (.legacy-clearfix::after, .footer), a high-specificity unlayered #hero { ... !important } rule declared after the layer order, and an !important inside the reset layer.
  • lib/__tests__/css-lint-rules.test.mjs -- new lintCascadeLayers with the multi-layer fixture describe block with 5 tests asserting the explicit layer order, per-layer rule grouping (with whitespace-normalized selector matching for the multi-line h1, h2, h3 selector), unlayered / post-layer-specificity / important-in-layer issue classification, and the hierarchy shape with per-layer rule counts.

How to test:

npm test
# Or target the lint rules specifically:
npx vitest run lib/__tests__/css-lint-rules.test.mjs
# Manual smoke test:
node bin/mint-ds.mjs lint <directory-with-css>

@nujovich

Copy link
Copy Markdown
Owner Author

All milestones complete. Ready for review when you are.

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