guard-my-design-system 1.3.3 → 1.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +96 -96
  2. package/package.json +2 -2
  3. package/src/judge.mjs +4 -1
package/README.md CHANGED
@@ -4,11 +4,9 @@
4
4
 
5
5
  ## Your design system dies one pull request at a time. This makes sure it doesn't.
6
6
 
7
- A pull request guard that checks **only the lines a change adds**, says nothing
8
- about the past, and points each new sin at the on-system value the author
9
- probably meant. Old wiring is not its business; new sparks are.
10
-
11
- It speaks in nearests, not scoldings:
7
+ The guard checks pull requests for design-system drift. It looks only at the
8
+ lines a change adds. It never judges the code that was already there. For each
9
+ problem it finds, it names the closest value your system already has:
12
10
 
13
11
  > `Card.tsx:24` — new colour `#4a7be8`. Nearest token: `var(--blue-500)`, `#3b6fe0`.
14
12
  >
@@ -20,64 +18,66 @@ It speaks in nearests, not scoldings:
20
18
  >
21
19
  > `site.css:35` — `!important`. The cascade admitting defeat; raise specificity or fix the source order.
22
20
 
23
- It learns your system by scanning your repo with the
21
+ It learns your design system by scanning your repository with the
24
22
  [roast-my-design-system](https://github.com/gregkozakiewicz/roast-my-design-system)
25
- engine, then judges the diff against what it learned. CSS, SCSS, styled
26
- components, and the web-component world too: Lit's `` css`…` `` templates and
27
- Stencil styling are read like any stylesheet. No config files, no rules to
28
- write, no tokens to register. Your codebase is the rulebook.
23
+ engine. It reads CSS, SCSS, styled components, Lit `` css`…` `` templates and
24
+ Stencil styling. You do not write any config, rules or token lists. Your
25
+ codebase is the rulebook.
29
26
 
30
- This is what a pull request sees, on real code, with the guard's own comment:
27
+ This is the guard's comment on a real pull request:
31
28
 
32
29
  ![The guard's comment on a pull request: six new issues, each with a file path and line, the stray colours shown with swatches next to their nearest token, an off-scale spacing value next to its nearest step, a new typeface, an !important, and an arbitrary Tailwind value, ending with the note that only added lines are checked](https://raw.githubusercontent.com/gregkozakiewicz/guard-my-design-system/main/docs/pr-comment.png?v=1.0.2)
33
30
 
34
- One comment per pull request, updated in place as the author fixes things. Push
35
- a fix and the same comment counts down instead of piling up:
31
+ The guard posts one comment per pull request. When the author pushes fixes,
32
+ it updates that same comment. It never adds more comments:
36
33
 
37
34
  ![The same pull request after fixes were pushed: the guard's single comment has updated in place, now showing three remaining issues, with the fix commits visible in the timeline above it and all checks passing below](https://raw.githubusercontent.com/gregkozakiewicz/guard-my-design-system/main/docs/pr-comment-updated.png?v=1.0.2)
38
35
 
39
36
  ## What it catches
40
37
 
41
- - **A hard-coded colour where a token exists**, with the nearest token named by
42
- its variable: `var(--blue-500)`, not a hex to go hunting for.
43
- - **A spacing value the codebase has never used**, with the nearest step named.
44
- - **A border radius, font size or shadow** the system does not declare, with
38
+ - **A hard-coded colour where a token exists.** The finding names the token:
39
+ `var(--blue-500)`, not just a hex code. This works across colour notations:
40
+ a hex stray is matched to an hsl or oklch token, including shadcn's
41
+ bare-triplet variables.
42
+ - **A spacing value your codebase has never used**, with the nearest existing
43
+ step named.
44
+ - **A border radius, font size or shadow your system does not declare**, with
45
45
  the nearest existing value named.
46
- - **A typeface the system does not declare.**
47
- - **`!important`**, the cascade admitting defeat.
48
- - **Arbitrary Tailwind values** (`w-[137px]`, `mt-[37px]`) that sidestep the scale.
46
+ - **A typeface your system does not declare.**
47
+ - **`!important`.**
48
+ - **Arbitrary Tailwind values** such as `w-[137px]` and `mt-[37px]`.
49
49
 
50
- And what it deliberately ignores: everything that was already there. Even if
51
- the codebase carries years of mess, the guard asks one question of a change:
52
- does it make things worse?
50
+ It ignores everything that was already in the codebase. It asks one question
51
+ of a change: does it make things worse?
53
52
 
54
53
  ## When the guard is wrong
55
54
 
56
- Sometimes an off-system value is the right call: a partner's brand colour, a
57
- gradient that needs its own stops. Say so on the line above, and the guard
58
- lets that one line pass:
55
+ Sometimes an off-system value is correct. A partner's brand colour, for
56
+ example. Write a comment on the line above, and the guard lets that one line
57
+ pass:
59
58
 
60
59
  ```css
61
60
  /* guard-ignore-next-line — partner brand colour, agreed with design */
62
61
  background: #e4002b;
63
62
  ```
64
63
 
65
- Works in any file the guard reads (`//` in components, `/* */` in styles).
66
- The exception is visible in code review by nature, silences exactly one line,
67
- and keeps working on later pull requests that touch the same line. No config
68
- file, no rule IDs — a sentence a reviewer can read is the whole mechanism.
64
+ This works in any file the guard reads: `//` in components, `/* */` in styles.
65
+ The comment is visible in code review. It silences exactly one line. It keeps
66
+ working on later pull requests that touch the same line. There is no config
67
+ file and there are no rule IDs.
69
68
 
70
69
  ## Why this exists
71
70
 
72
- Nobody can win the argument "please go and clean up the codebase". Everyone can
73
- win "let us at least stop digging". The guard makes not-digging automatic, and
74
- it matters more now than ever: AI agents write a growing share of UI code, and
75
- they drift off-system faster than review can catch. Rules files ask nicely; the
76
- guard checks.
71
+ You cannot ask a team to clean up years of styling. You can stop new problems
72
+ getting in. The guard does that automatically, on every pull request.
73
+
74
+ It matters more now than ever. AI tools write a growing share of UI code, and
75
+ they drift off-system faster than review can catch. Rules files ask nicely;
76
+ the guard checks.
77
77
 
78
78
  ## On a pull request
79
79
 
80
- Five minutes, once:
80
+ Set it up once. It takes about five minutes:
81
81
 
82
82
  ```yaml
83
83
  # .github/workflows/guard.yml
@@ -96,9 +96,10 @@ jobs:
96
96
  - uses: gregkozakiewicz/guard-my-design-system@v1
97
97
  ```
98
98
 
99
- After that you forget it exists, which is the whole point of a smoke alarm.
99
+ After that it runs on every pull request and needs no attention from you.
100
100
 
101
- Prefer a failed check over a comment? Strict mode is the one setting:
101
+ If you want the check to fail instead of commenting, turn on strict mode.
102
+ It is the only setting:
102
103
 
103
104
  ```yaml
104
105
  - uses: gregkozakiewicz/guard-my-design-system@v1
@@ -106,14 +107,15 @@ Prefer a failed check over a comment? Strict mode is the one setting:
106
107
  strict: true
107
108
  ```
108
109
 
109
- `exclude` keeps folders out of the system scan, same syntax as the CLI below.
110
+ `exclude` keeps folders out of the system scan. It uses the same syntax as
111
+ the CLI below.
110
112
 
111
- Security-conscious teams can pin to an exact commit instead of a version tag:
112
- `uses: gregkozakiewicz/guard-my-design-system@<commit-sha>`.
113
+ If your team pins actions for security, use an exact commit instead of a
114
+ version tag: `uses: gregkozakiewicz/guard-my-design-system@<commit-sha>`.
113
115
 
114
116
  ## On your machine
115
117
 
116
- Judge your uncommitted work before anyone else sees it:
118
+ Check your own work before you open a pull request:
117
119
 
118
120
  ```bash
119
121
  npx guard-my-design-system@latest
@@ -121,21 +123,21 @@ npx guard-my-design-system@latest
121
123
 
122
124
  | Command&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | What you get |
123
125
  |---|---|
124
- | <code>npx&nbsp;guard-my-design-system@latest</code> | Your working tree's added lines judged against main, in the terminal |
125
- | <code>npx&nbsp;guard-my-design-system@latest&nbsp;&lt;path&gt;</code> | Judge a different repo than the current directory |
126
- | <code>...&nbsp;--base&nbsp;&lt;ref&gt;</code> | Diff against something other than main |
127
- | `... --strict` | Exit 1 on findings, so it slots into scripts and hooks |
126
+ | <code>npx&nbsp;guard-my-design-system@latest</code> | The lines you have added, judged against main, in the terminal |
127
+ | <code>npx&nbsp;guard-my-design-system@latest&nbsp;&lt;path&gt;</code> | Judge a different repository |
128
+ | <code>...&nbsp;--base&nbsp;&lt;ref&gt;</code> | Compare against a branch other than main |
129
+ | `... --strict` | Exit with code 1 when there are findings, for scripts and hooks |
128
130
  | `... --markdown` | The verdict as markdown, the same text the PR comment carries |
129
- | `... --json` | Findings as JSON on stdout, for scripts and pipelines |
130
- | <code>...&nbsp;--exclude&nbsp;lab/</code> | Leave folders out of the system scan (comma-separate for more). A `.roastignore` file at the repo root works too |
131
+ | `... --json` | Findings as JSON, for scripts and pipelines |
132
+ | <code>...&nbsp;--exclude&nbsp;lab/</code> | Keep folders out of the system scan (separate more with commas). A `.roastignore` file at the repository root works too |
133
+ | `... --version` | The version number |
131
134
 
132
- Requires Node 18+ and git.
135
+ You need Node 18 or later, and git.
133
136
 
134
137
  ## Not on GitHub?
135
138
 
136
- The CLI works anywhere git works; only the comment-posting Action is
137
- GitHub-specific. On GitLab, the merge request pipeline gets the failing check
138
- with two lines in `.gitlab-ci.yml`:
139
+ The CLI works anywhere git works. Only the comment-posting Action needs
140
+ GitHub. On GitLab, add this to `.gitlab-ci.yml`:
139
141
 
140
142
  ```yaml
141
143
  guard:
@@ -147,7 +149,7 @@ guard:
147
149
  - npx guard-my-design-system@latest --strict --base origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME
148
150
  ```
149
151
 
150
- Bitbucket Pipelines, same idea in `bitbucket-pipelines.yml`:
152
+ On Bitbucket, add this to `bitbucket-pipelines.yml`:
151
153
 
152
154
  ```yaml
153
155
  pipelines:
@@ -160,59 +162,57 @@ pipelines:
160
162
  - npx guard-my-design-system@latest --strict --base origin/$BITBUCKET_PR_DESTINATION_BRANCH
161
163
  ```
162
164
 
163
- The verdict prints in the pipeline log and `--strict` fails the step; the
164
- sticky PR comment stays a GitHub luxury for now.
165
+ The verdict prints in the pipeline log, and `--strict` fails the step. The
166
+ updating PR comment works on GitHub only, for now.
165
167
 
166
168
  ## What makes the verdict trustworthy
167
169
 
168
170
  - **Only added lines are checked.** The existing codebase is never judged,
169
- never counted, never mentioned. Nobody rips out a smoke alarm because it
170
- criticised their old wiring.
171
- - **Deterministic, not AI sampling.** The same engine that powers
171
+ never counted, never mentioned.
172
+ - **The results are deterministic.** The same engine that powers
172
173
  roast-my-design-system reads the diff and returns the same verdict every
173
- run. No model, no sampling, no drift.
174
- - **Read-only, no network, no telemetry.** The scan and the diff both happen
175
- locally in your CI runner or terminal. Nothing about your code leaves the
176
- machine it runs on.
177
- - **Honest exemptions, inherited from roast.** Email and print styling must be
178
- inline, so it is never flagged. Artwork files carry hex that is drawing, not
179
- styling. Defining a new token is extending the system, not a sin.
180
- - **Findings are blunt, advice starts from intent.** Every flag names the
181
- on-system value the author probably meant, so the fix takes thirty seconds
182
- and no meeting.
174
+ time. No AI model is involved.
175
+ - **Read-only. No network. No telemetry.** Everything runs on your machine or
176
+ your CI runner. Nothing about your code leaves it.
177
+ - **Fair exemptions, inherited from roast.** Email and print styling must be
178
+ inline, so the guard never flags it. Files that draw SVG artwork are not
179
+ judged on their colours. Defining a new token is extending the system, not
180
+ a problem.
181
+ - **Every finding comes with a fix.** The guard names the on-system value the
182
+ author probably meant, so most fixes take under a minute and no meeting.
183
183
 
184
184
  ## Honest limits
185
185
 
186
- Things the guard deliberately does not do, said here so they never surprise you
187
- in a pull request:
188
-
189
- - **Monorepos are judged as one world.** The system is learned from the whole
190
- repo, so a colour that is legitimate in `packages/ui` counts as known when it
191
- appears in `apps/web`. Per-package judgement is roast's territory today.
192
- - **Spacing is compared within one unit.** A repo on a rem scale that receives
193
- `13px` gets the flag, but "nearest existing value" never converts units:
194
- claiming `0.75rem` is nearest to `13px` would be a judgement faked, not made.
195
- - **Taste is not judged, and tokens are a passport.** The right token in the
196
- wrong place sails through, and defining a new token is never a sin. The
197
- guard polices drift, not decisions: extending the system is legitimate work.
198
- - **On a fork's pull request, the comment cannot be posted** (GitHub hands the
199
- workflow a read-only token). The guard still runs; the verdict lands in the
200
- workflow log instead, with a line saying why. The same happens if the
201
- workflow is missing `pull-requests: write`.
202
- - **Not on GitHub?** Covered — copy-paste GitLab and Bitbucket recipes live in
203
- [Not on GitHub?](#not-on-github) above. Only the comment-posting Action is
204
- GitHub-specific.
205
- - **Inside `` css`…` `` templates, colours are caught line by line; spacing,
206
- radii and friends are not yet.** The whole-repo learning reads those
207
- templates in full, so the system is learned correctly either way; the
208
- line-level gap closes with a future engine release.
186
+ Things the guard deliberately does not do, listed here so they never surprise
187
+ you in a pull request:
188
+
189
+ - **Monorepos are judged as one codebase.** The guard learns the system from
190
+ the whole repository. A colour that is legitimate in `packages/ui` counts
191
+ as known when it appears in `apps/web`. For per-package scores, use roast.
192
+ - **Spacing is compared within one unit.** If your scale uses rem and someone
193
+ adds `13px`, the guard flags it. But it will not claim `0.75rem` is the
194
+ nearest value to `13px`. Converting units would be a guess, and the guard
195
+ does not guess.
196
+ - **Taste is not judged.** The right token in the wrong place passes.
197
+ Defining a new token is never flagged. The guard checks drift, not
198
+ decisions.
199
+ - **On a pull request from a fork, the comment cannot be posted.** GitHub
200
+ gives the workflow a read-only token. The guard still runs, and the verdict
201
+ appears in the workflow log with a line explaining why. The same happens if
202
+ the workflow is missing `pull-requests: write`.
203
+ - **Not on GitHub?** Covered: GitLab and Bitbucket recipes are in
204
+ [Not on GitHub?](#not-on-github) above.
205
+ - **Inside `` css`…` `` templates, the line-by-line check catches colours but
206
+ not yet spacing, radii or shadows.** The whole-repository scan reads those
207
+ templates in full, so the system is still learned correctly. The
208
+ line-level gap will close with a future engine release.
209
209
 
210
210
  ## The family
211
211
 
212
212
  [roast-my-design-system](https://github.com/gregkozakiewicz/roast-my-design-system)
213
- diagnoses the whole codebase: a health score against a 34-repo benchmark, the
214
- receipts behind it, and the agent rules that keep AI-written UI on-system.
215
- guard keeps new work from adding to the pile.
213
+ examines your whole codebase: a health score against a 34-repo benchmark, the
214
+ evidence behind it, and the agent rules that keep AI-written UI on-system.
215
+ The guard stops new work adding to the pile.
216
216
 
217
217
  Roast diagnoses it. Guard protects it.
218
218
 
@@ -222,7 +222,7 @@ Roast diagnoses it. Guard protects it.
222
222
 
223
223
  ## License
224
224
 
225
- MIT. The code is yours to fork, modify and redistribute; the copyright notice
225
+ MIT. You may fork, modify and redistribute the code. The copyright notice
226
226
  travels with it.
227
227
 
228
228
  If you build a report, summary or audit of your own from this tool's findings,
@@ -231,7 +231,7 @@ keep one line in it: *Built with
231
231
  by Greg Kozakiewicz*.
232
232
 
233
233
  **guard-my-design-system**™ and the GK mark are trademarks of Greg Kozakiewicz.
234
- Forking is welcome, republishing under this name is not: see
234
+ Forking is welcome. Republishing under this name is not. See
235
235
  [brand and attribution](https://gregkozakiewicz.github.io/guard-my-design-system/brand.html).
236
236
 
237
237
  Built and designed by <a href="https://gregkozakiewicz.com"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/gregkozakiewicz/roast-my-design-system/main/assets/gk-mark-dark.png?v=3.10.1"><img src="https://raw.githubusercontent.com/gregkozakiewicz/roast-my-design-system/main/assets/gk-mark.png?v=3.10.1" height="15" alt="GK mark"></picture> Greg Kozakiewicz</a>.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "guard-my-design-system",
3
- "version": "1.3.3",
3
+ "version": "1.3.5",
4
4
  "description": "Your design system dies one pull request at a time. This makes sure it doesn't. A guard that judges only the lines a change adds, against the system the repo already has, and names the on-system value the author probably meant.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -11,7 +11,7 @@
11
11
  "src/"
12
12
  ],
13
13
  "dependencies": {
14
- "roast-my-design-system": "5.7.2"
14
+ "roast-my-design-system": "5.10.2"
15
15
  },
16
16
  "keywords": [
17
17
  "design-system",
package/src/judge.mjs CHANGED
@@ -90,7 +90,10 @@ export function judge(added, system) {
90
90
  // "use var(--blue-500)", not "go hunt this hex": name a value when the
91
91
  // system defines it as a custom property.
92
92
  const named = (value) => {
93
- const n = system.tokenNames?.[value];
93
+ // shadcn-style tokens are defined as bare triplets (--primary: 222.2 47.4%
94
+ // 11.2%) but normalised to hsl(...); try the unwrapped form too.
95
+ const n = system.tokenNames?.[value]
96
+ ?? system.tokenNames?.[value.replace(/^hsla?\((.*)\)$/i, '$1')];
94
97
  return n ? `var(${n}), ${value}` : value;
95
98
  };
96
99
  const faceCounts = new Map();