Summary
.css / .scss appear in none of detect.py's extension sets — not CODE_EXTENSIONS, not
DOC_EXTENSIONS — so a stylesheet contributes zero nodes even when it is the authority for a
project's design system. On a codebase whose colours, spacing and radii all resolve through CSS
custom properties, the graph cannot answer "what defines --color-brand" or "which components
use it", and a token rename's blast radius is invisible.
(Related but different: #2498 covers the filename-based sensitive filter dropping a
tokens.css that would otherwise be scanned. This is the missing extractor underneath it —
even un-skipped, the file has no extraction path.)
What a minimal extractor recovers
I measured this by writing an external pass over the same repo (4 stylesheets: a token layer, a
brand ramp, an admin theme, a globals file) and merging its output into graph.json:
|
|
token nodes (--name: definitions) |
714 |
defines_token edges (stylesheet → token) |
714 |
uses_token edges (var(--name) in .css/.ts/.tsx) |
620 |
Two things that turned out to matter, in case they save someone the same iteration:
- Brace depth, not a flat regex. One globals file had 609
--name: declarations of which
only 22 were definitions — the other 587 were components locally overriding an inherited
token (.some-scope { --spacing: ...; }). Counting those as definitions makes every
consumer look like a definer.
- Token identity is per-file, not per-name. Two separate design systems in one repo both
defined --color-card; merging them by name would have fused two deliberately unshared
themes. Scoping the node to (file, name) and fanning uses_token out to same-named
candidates kept them distinct.
Deliberately excluded: resolving Tailwind-style utility class names back to tokens. var()
references are unambiguous; utility-name inference is not.
Suggested shape
Add .css/.scss to CODE_EXTENSIONS with an extractors/css.py that emits a node per
custom-property definition (with source_location) plus defines_token / uses_token edges.
tree-sitter-css exists, though for custom properties specifically a brace-depth scan was
enough — no grammar needed, which may matter given the packaging discussion in #2959.
Version: 0.9.56.
Summary
.css/.scssappear in none ofdetect.py's extension sets — notCODE_EXTENSIONS, notDOC_EXTENSIONS— so a stylesheet contributes zero nodes even when it is the authority for aproject's design system. On a codebase whose colours, spacing and radii all resolve through CSS
custom properties, the graph cannot answer "what defines
--color-brand" or "which componentsuse it", and a token rename's blast radius is invisible.
(Related but different: #2498 covers the filename-based sensitive filter dropping a
tokens.cssthat would otherwise be scanned. This is the missing extractor underneath it —even un-skipped, the file has no extraction path.)
What a minimal extractor recovers
I measured this by writing an external pass over the same repo (4 stylesheets: a token layer, a
brand ramp, an admin theme, a globals file) and merging its output into
graph.json:--name:definitions)defines_tokenedges (stylesheet → token)uses_tokenedges (var(--name)in.css/.ts/.tsx)Two things that turned out to matter, in case they save someone the same iteration:
--name:declarations of whichonly 22 were definitions — the other 587 were components locally overriding an inherited
token (
.some-scope { --spacing: ...; }). Counting those as definitions makes everyconsumer look like a definer.
defined
--color-card; merging them by name would have fused two deliberately unsharedthemes. Scoping the node to (file, name) and fanning
uses_tokenout to same-namedcandidates kept them distinct.
Deliberately excluded: resolving Tailwind-style utility class names back to tokens.
var()references are unambiguous; utility-name inference is not.
Suggested shape
Add
.css/.scsstoCODE_EXTENSIONSwith anextractors/css.pythat emits a node percustom-property definition (with
source_location) plusdefines_token/uses_tokenedges.tree-sitter-cssexists, though for custom properties specifically a brace-depth scan wasenough — no grammar needed, which may matter given the packaging discussion in #2959.
Version: 0.9.56.