Repository navigation
feat(enforce-canonical): report canonical forms that also set --tw-* variables (#217) - #222
Merged
Merged
Conversation
…variables (#217) Tailwind canonicalizes `[line-height:var(--x)]` to `leading-(--x)`, but the canonical form also sets `--tw-leading`, which every `text-*` size reads for its line height, so the two can render differently next to one. The #78 guard left these as written (reason 'value') and said nothing, so a CI lint never caught them. The canonicalize worker now strips MIRRORS before comparing: a `--tw-*` declaration repeating, verbatim with its `!important`, the value of a sibling real property in the same block, plus the `@property` of each stripped variable (what Tailwind's own signature drops). Equal once stripped, with the canonical form adding mirrors and dropping none, is the new reason 'variable', carrying the variables. The variant/selector check compares stripped CSS too, so a project variant that also adds a mirror stays 'variant'. 86 forms of the stock theme land here: border-dashed, duration-*, font-*, leading-*, tracking-*, ease-*, outline-*, content-none. With `reportNonEquivalent: true`, enforce-canonical reports them as `nonEquivalentVariable`, naming the variable, with a suggestion and never an autofix. The option stays off by default. - utils/report: `reportClassSuggestion`, the one-class suggestion pattern prefer-scale-token and no-unknown-classes each had a copy of; it never joins the shared autofix. - The persisted canon tuple grows to [canonical, safe, reason?, variables?], the variables with 'variable' and only with it; older entries still read. Only CANONICALIZE_HANDLER changed, so the canon cache is renamed and the precompute is untouched. - On shadcn/ui apps/v4 the option still adds 23 reports, all data-[disabled]:; bench corpus and synthetic are identical with the default config. Claude-Session: https://claude.ai/code/session_019vTh6S5A41M1HLkmk3FaM1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #217.
Summary
Tailwind canonicalizes
[line-height:var(--x)]→leading-(--x), but the canonical form also sets--tw-leading, which everytext-*size reads for its line height. The two can render differently next to one, so the #78 guard leaves them as written. Until now it also said nothing, so CI never caught them.CANONICALIZE_HANDLERstrips mirrors before comparing.--tw-*declaration that repeats a sibling real property's value verbatim,!importantincluded, plus the@propertyof each stripped variable. This is what Tailwind's own signature drops.'variable', which carries the variables.'variant'.reportNonEquivalent: true,enforce-canonicalreports them asnonEquivalentVariable. The message names the variable, and the report carries a suggestion and never an autofix. The option stays off by default.utils/report.ts:reportClassSuggestionreplaces the one-class suggestion pattern thatprefer-scale-tokenandno-unknown-classeseach had a copy of. It never joins the shared autofix.[canonical, safe, reason?, variables?], and older entries still read. Only the handler changed, so the canon cache file is renamed and the precompute is untouched.## Unreleased).Test plan
canonicalize-reason.test.ts:'variable','value'and the mixed variant case.!important, value,var(--tw-*)reads, a;in a value, an@property-only difference, a dropped mirror. A mutation of the dropped guard was checked to fail.canonicalize-persistence.test.ts: 4-element round-trip, invalid entries skipped, 3-element entries still read.enforce-canonical.test.ts: off by default; suggestion without an output;!position; a mixed string where the autofix excludes the suggestion.template-fragments.test.tsand the newtests/utils/report.test.ts.lint:types,format:check, typecheck, build andpnpm test(3552 + 312).npm test. The corpus and synthetic runs are identical to the baseline (--expect-identical).data-[disabled]:.🤖 Generated with Claude Code
https://claude.ai/code/session_019vTh6S5A41M1HLkmk3FaM1