guard-my-design-system 1.9.0 → 2.0.0

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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # guard-my-design-system
2
2
 
3
- [![npm](https://img.shields.io/npm/v/guard-my-design-system?color=2dd4bf&label=npm)](https://www.npmjs.com/package/guard-my-design-system) [![downloads](https://img.shields.io/npm/dm/guard-my-design-system?color=2dd4bf&label=downloads)](https://www.npmjs.com/package/guard-my-design-system) [![license](https://img.shields.io/badge/license-MIT-blue)](LICENSE) [![no telemetry](https://img.shields.io/badge/no-telemetry-2dd4bf)](https://github.com/gregkozakiewicz/guard-my-design-system#what-makes-the-verdict-trustworthy) [![GitHub Action](https://img.shields.io/badge/GitHub_Action-v1-2dd4bf)](#on-a-pull-request)
3
+ [![npm](https://img.shields.io/npm/v/guard-my-design-system?color=2dd4bf&label=npm)](https://www.npmjs.com/package/guard-my-design-system) [![downloads](https://img.shields.io/npm/dm/guard-my-design-system?color=2dd4bf&label=downloads)](https://www.npmjs.com/package/guard-my-design-system) [![license](https://img.shields.io/badge/license-MIT-blue)](LICENSE) [![no telemetry](https://img.shields.io/badge/no-telemetry-2dd4bf)](https://github.com/gregkozakiewicz/guard-my-design-system#what-makes-the-verdict-trustworthy) [![GitHub Action](https://img.shields.io/badge/GitHub_Action-v2-2dd4bf)](#on-a-pull-request)
4
4
 
5
5
  ## Your design system dies one pull request at a time. This makes sure it doesn't.
6
6
 
@@ -70,6 +70,17 @@ it updates that same comment. It never adds more comments:
70
70
  - **A palette colour where a theme variable exists.** On a shadcn repo whose
71
71
  theme file holds the variables, `text-slate-500` in the app's own code is
72
72
  flagged and the theme file named. Off on utility-class installs.
73
+ - **A chart colour written by hand.** A chart needs several colours that
74
+ differ from each other, and most design systems never name them, so the
75
+ chart rule (roast 8.8) has three answers. Where the repo keeps a chart
76
+ palette (`--chart-*` or `--series-*` tokens, a `chartColors` entry in the
77
+ theme, or shadcn's `--chart-1` to `--chart-5` when a chart actually reads
78
+ them), a hex in a chart file is flagged and the palette named. Where the
79
+ repo has charts but no palette, a new chart painting by hand gets one line
80
+ that names the existing chart doing the same and asks for the palette
81
+ once. The first chart in a repo gets one line asking for a name. The
82
+ generic colour rule stays out of chart files, the same way it does in
83
+ `roast_validate`.
73
84
  - **A colour or a pixel size written onto a kit component.** On a product
74
85
  built on MUI, Mantine, Chakra UI or Ant Design, `color: '#667085'` in an
75
86
  `sx` prop or a style object is flagged and the finding says whether the
@@ -134,7 +145,7 @@ jobs:
134
145
  - uses: actions/checkout@v5
135
146
  with:
136
147
  fetch-depth: 0
137
- - uses: gregkozakiewicz/guard-my-design-system@v1
148
+ - uses: gregkozakiewicz/guard-my-design-system@v2
138
149
  ```
139
150
 
140
151
  After that it runs on every pull request and needs no attention from you.
@@ -143,7 +154,7 @@ If you want the check to fail instead of commenting, turn on strict mode.
143
154
  It is the only setting:
144
155
 
145
156
  ```yaml
146
- - uses: gregkozakiewicz/guard-my-design-system@v1
157
+ - uses: gregkozakiewicz/guard-my-design-system@v2
147
158
  with:
148
159
  strict: true
149
160
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "guard-my-design-system",
3
- "version": "1.9.0",
3
+ "version": "2.0.0",
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": "8.6.1"
14
+ "roast-my-design-system": "9.0.0"
15
15
  },
16
16
  "keywords": [
17
17
  "design-system",
package/src/judge.mjs CHANGED
@@ -13,7 +13,7 @@ import {
13
13
  definedComponents, exemptReason,
14
14
  EXTRA_KINDS, extraValue, fontDeclarations,
15
15
  WIDGET_CSS_RE, isLibraryClass, PALETTE_CLASS_RE, blankComments, kitPaintFindings,
16
- tokenTwinFindings, avoidedImportFindings,
16
+ tokenTwinFindings, avoidedImportFindings, isChartFile, chartFindings,
17
17
  } from 'roast-my-design-system/engine';
18
18
 
19
19
  // Folder membership, the way the engine's own splits do it.
@@ -88,7 +88,7 @@ function exemptFiles(added, readFile) {
88
88
  * Returns [{ file, line, kind, value, advice }] sorted by file then line.
89
89
  * kinds: color | spacing | radius | fontsize | shadow | arbitrary |
90
90
  * important | font | inline | component | palette | kit-colour |
91
- * kit-px | twin-token | avoided-copy
91
+ * kit-px | twin-token | avoided-copy | chart-colour | chart-palette
92
92
  * readFile(file) gives the file as it stands; readBase(file) the file at the
93
93
  * base (null when the change creates it), so a token or an import the change
94
94
  * adds can be told from one that was already there.
@@ -221,6 +221,18 @@ export function judge(added, system, { readFile, readBase } = {}) {
221
221
 
222
222
  const findings = [];
223
223
 
224
+ // A chart's series colours are judged against the chart palette, or its
225
+ // absence, by the engine (roast 8.8.0, lib/charts): the report never
226
+ // counted them, the live checks counted every one, and the guard did too.
227
+ // On a chart file the chart rule owns colours, the same way it does in
228
+ // roast_validate: the kit judge and the generic colour rule stay out.
229
+ const chartColours = new Map(); // file → [{ value, index: line }]
230
+ const isChart = (file) => {
231
+ if (!system.charts) return false;
232
+ const w = wholeText(file);
233
+ return isChartFile(file, w ?? '');
234
+ };
235
+
224
236
  for (const { file, line, text } of added) {
225
237
  if (exempt(file) || outOfScope(file)) continue;
226
238
  const css = isStyleFile(file);
@@ -228,7 +240,14 @@ export function judge(added, system, { readFile, readBase } = {}) {
228
240
 
229
241
  const seen = extractStyling(text, { css });
230
242
 
231
- const onKit = css ? null : kitLines(file);
243
+ const chart = !css && isChart(file);
244
+ if (chart) {
245
+ const list = chartColours.get(file) ?? [];
246
+ for (const c of seen.colors) if (!tokenSet.has(c.value)) list.push({ value: c.value, index: line });
247
+ chartColours.set(file, list);
248
+ }
249
+
250
+ const onKit = css || chart ? null : kitLines(file);
232
251
  const kitPx = new Set();
233
252
  for (const f of onKit?.get(line) ?? []) {
234
253
  if (f.rule === 'kit-px') kitPx.add(f.value.split(': ')[1]);
@@ -239,7 +258,7 @@ export function judge(added, system, { readFile, readBase } = {}) {
239
258
  }
240
259
 
241
260
  for (const c of seen.colors) {
242
- if (onKit) break; // the kit rule owns colours on a kit file
261
+ if (onKit || chart) break; // the kit rule or the chart rule owns colours here
243
262
  if (tokenSet.has(c.value)) continue; // disciplined token use
244
263
  const near = c.value.startsWith('#') ? nearestColor(c.value, system.tokens) : null;
245
264
  findings.push({
@@ -406,6 +425,21 @@ export function judge(added, system, { readFile, readBase } = {}) {
406
425
  }
407
426
  }
408
427
 
428
+ // The chart rule, once per chart file, in the engine's words: with a
429
+ // palette every hand-written colour is a finding that names it; without
430
+ // one the file gets a single line that names the precedent chart and asks
431
+ // for the palette once (roast 8.8.0). `index` carries the diff line.
432
+ for (const [file, colours] of chartColours) {
433
+ if (!colours.length) continue;
434
+ for (const f of chartFindings({ file, colours, charts: system.charts, tokenFile: system.tokenFile ?? null })) {
435
+ findings.push({
436
+ file, line: f.index, kind: f.rule,
437
+ value: f.rule === 'chart-colour' ? f.message.match(/Chart colour (\S+)/)?.[1] ?? 'colour' : `${colours.length} series colour${colours.length === 1 ? '' : 's'} by hand`,
438
+ advice: `${f.message} ${f.fix.replace(/\.$/, '')}`,
439
+ });
440
+ }
441
+ }
442
+
409
443
  // Two extractors can see the same value on the same line (a hex inside a
410
444
  // Tailwind class is also a hex in the raw sweep). One sin, one line.
411
445
  const seen = new Set();
package/src/report.mjs CHANGED
@@ -22,11 +22,15 @@ const KIND_LABEL = {
22
22
  // the engine's sentence names the token or the import itself (roast 8.6)
23
23
  'twin-token': 'token that copies an existing one',
24
24
  'avoided-copy': 'import of a duplicate',
25
+ // the chart rule (roast 8.8): a colour beside a chart palette, or a chart
26
+ // painting by hand where the repo keeps none
27
+ 'chart-colour': 'chart colour written by hand',
28
+ 'chart-palette': 'chart painted by hand',
25
29
  };
26
30
  const labelOf = (f) => f.label ?? KIND_LABEL[f.kind];
27
31
 
28
32
  // Kinds whose label already says everything; printing the value repeats it.
29
- const VALUELESS = new Set(['important', 'inline', 'twin-token', 'avoided-copy']);
33
+ const VALUELESS = new Set(['important', 'inline', 'twin-token', 'avoided-copy', 'chart-palette']);
30
34
 
31
35
  const FOOTER = 'Full picture of the whole codebase: `npx roast-my-design-system`';
32
36