Skip to content

Add ValidScopedCSSClass theme check#1172

Draft
aswamy wants to merge 1 commit intomainfrom
cross-file-css-usage-check
Draft

Add ValidScopedCSSClass theme check#1172
aswamy wants to merge 1 commit intomainfrom
cross-file-css-usage-check

Conversation

@aswamy
Copy link
Copy Markdown
Contributor

@aswamy aswamy commented Apr 9, 2026

Summary

Adds a new theme check ValidScopedCSSClass that warns when a CSS class used in an HTML class attribute may be defined outside the scope of the current file.

This helps theme developers catch cases where a CSS class is used in a file but is only defined in a stylesheet tag that isn't accessible from that file's scope — indicating a potential dependency issue or misplaced style.

What is considered "in scope"

A CSS class is considered in scope for a file if it is defined in any of the following:

  • Local {% stylesheet %} tag — the file's own stylesheet
  • Ancestor {% stylesheet %} tags — any file that directly renders this file (via {% render %}, {% section %}, etc.), traversed upward through the full ancestor chain. Only direct type references count (not indirect or preset)
  • Rendered snippet stylesheets — any snippet the file renders via {% render %}, including that snippet's own snippet descendants (recursive)
  • Ancestor-rendered snippet stylesheets — any snippet rendered by an ancestor file, including descendants
  • CSS asset files — all .css files in the theme's assets/ directory are globally in scope

What is NOT reported

  • Classes not defined anywhere in the theme — classes from external sources (CDNs, utility frameworks like Tailwind, inline JS injection, etc.) are silently ignored. The check only reports a class if it exists somewhere in the theme but isn't reachable from the current file's scope
  • Dynamic class attributes — Liquid output tags ({{ variable }}) in class attributes are skipped since they can't be statically analyzed
  • Files with no CSS classes defined in scope — if no stylesheet tags or CSS assets exist, the check produces no warnings

Changes

New files

  • packages/theme-check-common/src/checks/valid-scoped-css-class/ — check implementation + tests (27 test cases)
  • packages/theme-check-common/src/utils/styles.ts — CSS class extraction utilities (postcss-based parsing, asset/liquid file scanning) + tests (25 test cases)
  • packages/theme-check-common/src/utils/traversal.ts — graph traversal utilities (ancestor BFS, snippet descendant BFS) + tests (15 test cases)

Infrastructure changes

  • packages/theme-check-common/src/types.ts — added getDependencies to Dependencies interface (mirrors existing getReferences)
  • packages/theme-language-server-common/src/diagnostics/runChecks.ts — wired getDependencies to ThemeGraphManager
  • packages/theme-check-node/src/index.ts — builds ThemeGraph in CLI mode and provides getReferences/getDependencies to checks
  • packages/theme-graph/package.json — moved @shopify/theme-check-node from dependencies to devDependencies (only used in test helpers, eliminates circular dep)

Performance

  • Theme-wide CSS class collection and per-URI liquid file parsing are cached (WeakMap on fs instance + Map on URI) so expensive operations run once per check run, not once per file
  • Tested on Horizon theme (240 liquid files): ~23s total check run

Test plan

  • yarn vitest run packages/theme-check-common/ — all 923 tests pass
  • yarn vitest run packages/theme-check-node/ — all 77 tests pass
  • yarn tsc --noEmit in theme-check-common, theme-check-node, theme-language-server-common — all compile clean
  • CLI: node packages/theme-check-node/dist/cli.js <theme-path> produces correct warnings
  • VSCode extension: check fires in the editor with correct diagnostics

🤖 Generated with Claude Code

@aswamy aswamy force-pushed the cross-file-css-usage-check branch from bf4018b to c4d206f Compare April 10, 2026 14:49
Add a new theme check that warns when a CSS class used in an HTML
class attribute may be defined outside the scope of the current file,
helping catch misplaced styles and dependency issues.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@aswamy aswamy force-pushed the cross-file-css-usage-check branch from c4d206f to 70d6111 Compare April 10, 2026 15:23
@aswamy aswamy changed the title Add ValidCSSClassWithinStylesheet theme check Add ValidScopedCSSClass theme check Apr 10, 2026
"vscode-uri": "^3.0.7"
},
"devDependencies": {
"@shopify/theme-check-node": "^3.24.0"
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to move it to a dev-dependency so we can let theme-check-node be dependent on the theme-graph.

Why? Because CLI needs the theme-graph to be able to run the theme-check to detect cross-file CSS usage.

fs: NodeFileSystem,
getSectionSchema: getSectionSchemaFn as any,
getBlockSchema: getBlockSchemaFn as any,
getWebComponentDefinitionReference: () => undefined,
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want to recreate the whole graph because we don't need it for this theme-check, but might silently error out if we add a theme-check that needs this in the future 🤔

(but then again, we would silently fail if getReferences or getDependencies wasn't defined either so maybe not a HUGE deal 🤷)

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