spiracss/rel-comments
Validates parent-child links via @rel comments.
Purpose
- Make the relationship between page entry SCSS and Blocks / child Blocks explicit
- Stabilize automatic navigation by comment links
What it checks
- Parent Block
@relmust be placed at the top of the root scope (@use/@forward/@importcan come before it; it is not allowed inside the root Block) - Parent Block must be the first rule in the same scope (when parent-link is required)
- The first node under a
> .child-blockrule must be an@relcomment - The shared section is in scope; the interaction section is excluded by default
- Optionally verifies that the path in the comment exists
- The expected filename for child links follows
fileCase(default:preserve) - When the @rel path includes
childDir, the expected filename followschildFileCase(falls back tofileCase) - Allowed values:
preserve|kebab|snake|camel|pascal *.module.scssis also accepted for child links (useful for CSS Modules)
OK
// @rel/../components/card-list.scss
.page-home { > .card-list { // @rel/scss/card-list.scss margin-top: 8px; }}NG
.page-home { // @rel/../components/card-list.scss // NG: not at the top of the root scope > .card-list { margin-top: 8px; }}.page-home { > .card-list { margin-top: 8px; // NG: @rel is not the first node }}fileCase example
When fileCase: 'pascal' is set, the expected file name is PascalCase.
If childFileCase is set, it only applies to @rel paths that include childDir.
.page-home { > .card-list { // OK // @rel/scss/CardList.scss }}.page-home { > .card-list { // OK (CSS Modules) // @rel/scss/card-list.module.scss }}Why
- Fixing the parent-child entry point stabilizes link resolution
Error list
missingParentRel (missing parent @rel)
Example:
// NG.page-home { color: #111;}
// OK// @rel/../components/page-home.scss.page-home { color: #111;}Reason: fix the entry point for the parent link
misplacedParentRel (invalid parent @rel placement)
Example:
// NG.page-home { // @rel/../components/page-home.scss color: #111;}
// OK// @rel/../components/page-home.scss.page-home { color: #111;}Reason: make the parse entry point unambiguous
rootBlockNotFirst (root Block is not the first rule)
Example:
// NG.util-reset { box-sizing: border-box;}.page-home { color: #111;}
// OK.page-home { color: #111;}.util-reset { box-sizing: border-box;}Reason: keep consistency with the parent-link entry placement
missingChildRel (missing child @rel)
Example:
// NG.page-home { > .card-list { margin-top: 8px; }}
// OK.page-home { > .card-list { // @rel/scss/card-list.scss margin-top: 8px; }}Reason: make links to child Blocks explicit
notFound (target path does not exist)
Example:
// NG// @rel/../components/missing-block.scss.page-home { color: #111;}
// OK// @rel/../components/card-list.scss.page-home { color: #111;}Reason: keep navigation consistent
childMismatch (child Block name does not match @rel)
Example:
// NG.page-home { > .card-list { // @rel/scss/hero-banner.scss margin-top: 8px; }}
// OK.page-home { > .card-list { // @rel/scss/card-list.scss margin-top: 8px; }}Reason: expected filenames follow fileCase / childFileCase (*.module.scss is also allowed)
selectorParseFailed (selector parse failed)
Example:
// NG.page-home { > : { margin-top: 8px; }}
// OK.page-home { > .card-list { margin-top: 8px; }}Reason: unparseable selectors cannot be validated