Following up on @davideast's suggestion in #68:
One thing your PR has that #103 does not: collision detection for cases where a flat key and a grouped key produce the same name. That's a good idea and worth tracking. If you're interested, filing a separate issue for collision detection would be welcome and we can work on it from there. Create an issue and tag me in it.
Problem
Since #103 merged forEachLeaf and arbitrary-depth nesting for colors, rounded, and spacing, it is now possible to author a DESIGN.md that produces silent name collisions in the symbol table. Two distinct cases:
Case 1 — Duplicate dot path (a flat key whose literal text mirrors an existing nested token's dot-path):
colors:
utility-info:
50: "#EEF7FC"
utility-info.50: "#FFFFFF" # same symbol table key: colors.utility-info.50
Case 2 — Flat/grouped name collision (a nested token that normalizes, dots → hyphens, to the same string as an already-registered flat key):
colors:
utility-info-50: "#EEF7FC" # registers as utility-info-50
utility-info:
50: "#FFFFFF" # also normalizes to utility-info-50 in flat output
In both cases the second value silently overwrites the first in the symbol table. The Tailwind v4 emitter then exports whichever value happened to win the race — with no diagnostic emitted to the user.
The same issue applies to rounded and spacing since they also use forEachLeaf as of #103.
Proposed solution
During ModelHandler Phase 1 (primitive token resolution), track two sets per token category (colors, rounded, spacing):
seenKeys: Set<string> — exact dot-separated path, to detect Case 1
seenNormalized: Map<string, string> — hyphen-normalized name, to detect Case 2
Emit an error-severity finding for each violation before writing to the symbol table, and skip the offending token so the winning value is deterministic and the user sees the diagnostic at lint time.
@davideast — tagging you as requested in #68.
Following up on @davideast's suggestion in #68:
Problem
Since #103 merged
forEachLeafand arbitrary-depth nesting forcolors,rounded, andspacing, it is now possible to author aDESIGN.mdthat produces silent name collisions in the symbol table. Two distinct cases:Case 1 — Duplicate dot path (a flat key whose literal text mirrors an existing nested token's dot-path):
Case 2 — Flat/grouped name collision (a nested token that normalizes, dots → hyphens, to the same string as an already-registered flat key):
In both cases the second value silently overwrites the first in the symbol table. The Tailwind v4 emitter then exports whichever value happened to win the race — with no diagnostic emitted to the user.
The same issue applies to
roundedandspacingsince they also useforEachLeafas of #103.Proposed solution
During
ModelHandlerPhase 1 (primitive token resolution), track two sets per token category (colors,rounded,spacing):seenKeys: Set<string>— exact dot-separated path, to detect Case 1seenNormalized: Map<string, string>— hyphen-normalized name, to detect Case 2Emit an
error-severity finding for each violation before writing to the symbol table, and skip the offending token so the winning value is deterministic and the user sees the diagnostic at lint time.@davideast — tagging you as requested in #68.