stylelint-plugin-rhythmguard 1.4.2 → 1.6.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/CHANGELOG.md +8 -0
- package/README.md +150 -30
- package/package.json +10 -3
- package/src/cli/audit.js +645 -0
- package/src/cli/doctor.js +231 -0
- package/src/cli/index.js +39 -0
- package/src/cli/init.js +128 -0
- package/src/configs/react-tailwind.js +25 -0
- package/src/configs/react-tailwind.mjs +4 -0
- package/src/configs/tailwind.js +9 -0
- package/src/eslint/rules/tailwind-class-use-scale.js +25 -120
- package/src/utils/tailwind-class-analysis.js +221 -0
- package/src/utils/token-map.js +44 -3
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,14 @@ The format follows Keep a Changelog principles and semantic versioning.
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.6.0] - 2026-05-19
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `rhythmguard audit` now reports design-system drift across CSS declarations and Tailwind arbitrary spacing class strings.
|
|
14
|
+
- Added `--format markdown` / `--markdown` audit output for PR-ready design-system health reports.
|
|
15
|
+
- Audit JSON now includes format version, CSS findings, Tailwind class-string findings, scan counts, top affected files, and summary totals while preserving existing top-level count fields.
|
|
16
|
+
|
|
9
17
|
## [1.4.2] - 2026-02-21
|
|
10
18
|
|
|
11
19
|
### Changed
|
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="https://raw.githubusercontent.com/petrilahdelma/stylelint-plugin-rhythmguard/main/assets/rhythmguard-banner.svg" width="100%" alt="Rhythmguard banner
|
|
2
|
+
<img src="https://raw.githubusercontent.com/petrilahdelma/stylelint-plugin-rhythmguard/main/assets/rhythmguard-banner.svg?v=3" width="100%" alt="Rhythmguard banner showing spacing scale ruler and lint output" />
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
# stylelint-plugin-rhythmguard
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Token governance for CSS and Tailwind. Enforce spacing scales, require design tokens, and catch arbitrary values before they ship.
|
|
8
8
|
|
|
9
9
|
[](https://github.com/petrilahdelma/stylelint-plugin-rhythmguard/actions/workflows/ci.yml)
|
|
10
10
|
[](https://www.npmjs.com/package/stylelint-plugin-rhythmguard)
|
|
@@ -12,25 +12,48 @@ High-precision spacing governance for CSS and design systems.
|
|
|
12
12
|
[](./LICENSE)
|
|
13
13
|
[](https://nodejs.org/)
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Rhythmguard enforces scale and token discipline across spacing, radius, typography, size, and motion offsets — in CSS declarations and Tailwind class strings.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Built for teams that want:
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
</p>
|
|
19
|
+
- zero random spacing values in production
|
|
20
|
+
- token-first workflows with autofix migration
|
|
21
|
+
- Tailwind arbitrary value governance (`p-[13px]` → `p-[12px]`)
|
|
22
|
+
- consistent layout rhythm across components and pages
|
|
24
23
|
|
|
25
|
-
|
|
24
|
+
## Quick Start: Next.js + Tailwind
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
```bash
|
|
27
|
+
npm install --save-dev stylelint stylelint-plugin-rhythmguard
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**.stylelintrc.json:**
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"extends": ["stylelint-plugin-rhythmguard/configs/tailwind"]
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**eslint.config.js** (for Tailwind class-string governance):
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
import rhythmguard from 'stylelint-plugin-rhythmguard/eslint';
|
|
42
|
+
|
|
43
|
+
export default [
|
|
44
|
+
{
|
|
45
|
+
plugins: { 'rhythmguard-tailwind': rhythmguard },
|
|
46
|
+
rules: {
|
|
47
|
+
'rhythmguard-tailwind/tailwind-class-use-scale': [
|
|
48
|
+
'error',
|
|
49
|
+
{ scale: [0, 4, 8, 12, 16, 24, 32] }
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
];
|
|
54
|
+
```
|
|
28
55
|
|
|
29
|
-
|
|
30
|
-
- consistent numeric scales for radius, typography, and sizing primitives
|
|
31
|
-
- token-first spacing workflows
|
|
32
|
-
- predictable autofix behavior for large migrations
|
|
33
|
-
- consistent layout rhythm across web surfaces
|
|
56
|
+
This gives you spacing governance in both CSS files and JSX/TSX templates.
|
|
34
57
|
|
|
35
58
|
## Rule Matrix
|
|
36
59
|
|
|
@@ -44,6 +67,44 @@ It is built for teams that want:
|
|
|
44
67
|
| `rhythmguard/prefer-token` | Enforces token usage over raw spacing literals | Yes, with `tokenMap` |
|
|
45
68
|
| `rhythmguard/no-offscale-transform` | Enforces scale-aligned `translate*` motion offsets | Yes, nearest safe value |
|
|
46
69
|
|
|
70
|
+
## Demo
|
|
71
|
+
|
|
72
|
+
<p align="center">
|
|
73
|
+
<a href="https://github.com/petrilahdelma/stylelint-plugin-rhythmguard/blob/main/assets/rhythmguard-campaign-60s.webm">
|
|
74
|
+
<img src="https://raw.githubusercontent.com/petrilahdelma/stylelint-plugin-rhythmguard/main/assets/rhythmguard-campaign-60s.gif" width="100%" alt="Rhythmguard 60-second demo" />
|
|
75
|
+
</a>
|
|
76
|
+
</p>
|
|
77
|
+
|
|
78
|
+
I built Rhythmguard after 20 years of watching teams ignore spacing scales and ship arbitrary pixel values everywhere.
|
|
79
|
+
|
|
80
|
+
## Try It in Your Browser
|
|
81
|
+
|
|
82
|
+
**[petrilahdelma.github.io/stylelint-plugin-rhythmguard](https://petrilahdelma.github.io/stylelint-plugin-rhythmguard/)** — paste CSS, see violations and token opportunities live. No install, no config.
|
|
83
|
+
|
|
84
|
+
## Audit Before You Enforce
|
|
85
|
+
|
|
86
|
+
Use the audit CLI to create a design-system drift report before turning rules into hard CI gates:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
npx rhythmguard audit ./src
|
|
90
|
+
npx rhythmguard audit ./src --format markdown
|
|
91
|
+
npx rhythmguard audit ./src --json
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The report covers authored CSS declarations and Tailwind arbitrary spacing values in common template/source files. Markdown output is PR-ready for UX developers, UX designers, and design-system owners:
|
|
95
|
+
|
|
96
|
+
```md
|
|
97
|
+
# Rhythmguard Design-System Audit
|
|
98
|
+
|
|
99
|
+
| Metric | Value |
|
|
100
|
+
| --- | ---: |
|
|
101
|
+
| CSS files scanned | 47 |
|
|
102
|
+
| Template files scanned | 83 |
|
|
103
|
+
| Files with issues | 12 |
|
|
104
|
+
| Total findings | 52 |
|
|
105
|
+
| Scale cleanliness | 91% |
|
|
106
|
+
```
|
|
107
|
+
|
|
47
108
|
## Installation
|
|
48
109
|
|
|
49
110
|
```bash
|
|
@@ -66,32 +127,32 @@ npm install --save-dev stylelint-plugin-rhythmguard
|
|
|
66
127
|
|
|
67
128
|
## Quick Start
|
|
68
129
|
|
|
69
|
-
###
|
|
130
|
+
### Tailwind config
|
|
70
131
|
|
|
71
132
|
```json
|
|
72
133
|
{
|
|
73
|
-
"extends": ["stylelint-plugin-rhythmguard/configs/
|
|
134
|
+
"extends": ["stylelint-plugin-rhythmguard/configs/tailwind"]
|
|
74
135
|
}
|
|
75
136
|
```
|
|
76
137
|
|
|
77
|
-
###
|
|
138
|
+
### Recommended config
|
|
78
139
|
|
|
79
140
|
```json
|
|
80
141
|
{
|
|
81
|
-
"extends": ["stylelint-plugin-rhythmguard/configs/
|
|
142
|
+
"extends": ["stylelint-plugin-rhythmguard/configs/recommended"]
|
|
82
143
|
}
|
|
83
144
|
```
|
|
84
145
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
### Tailwind config
|
|
146
|
+
### Strict config
|
|
88
147
|
|
|
89
148
|
```json
|
|
90
149
|
{
|
|
91
|
-
"extends": ["stylelint-plugin-rhythmguard/configs/
|
|
150
|
+
"extends": ["stylelint-plugin-rhythmguard/configs/strict"]
|
|
92
151
|
}
|
|
93
152
|
```
|
|
94
153
|
|
|
154
|
+
`strict` intentionally delegates transform translation enforcement to `rhythmguard/no-offscale-transform` to reduce overlapping warnings from `use-scale`.
|
|
155
|
+
|
|
95
156
|
### Expanded config
|
|
96
157
|
|
|
97
158
|
```json
|
|
@@ -122,18 +183,32 @@ npm install --save-dev stylelint-plugin-rhythmguard
|
|
|
122
183
|
|
|
123
184
|
`migration` keeps on-scale numeric values temporarily while auto-building token mappings from CSS custom properties and optional Tailwind spacing config.
|
|
124
185
|
|
|
186
|
+
### React / Next.js + Tailwind config
|
|
187
|
+
|
|
188
|
+
```json
|
|
189
|
+
{
|
|
190
|
+
"extends": ["stylelint-plugin-rhythmguard/configs/react-tailwind"]
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
`react-tailwind` extends the tailwind config with CSS Modules overrides (spacing + radius enforcement) and ignores Next.js build directories.
|
|
195
|
+
|
|
125
196
|
Stable shared config entry points:
|
|
126
197
|
|
|
127
198
|
- `stylelint-plugin-rhythmguard/configs/recommended`
|
|
128
199
|
- `stylelint-plugin-rhythmguard/configs/strict`
|
|
129
200
|
- `stylelint-plugin-rhythmguard/configs/tailwind`
|
|
201
|
+
- `stylelint-plugin-rhythmguard/configs/react-tailwind`
|
|
130
202
|
- `stylelint-plugin-rhythmguard/configs/expanded`
|
|
131
203
|
- `stylelint-plugin-rhythmguard/configs/logical`
|
|
132
204
|
- `stylelint-plugin-rhythmguard/configs/migration`
|
|
133
205
|
|
|
206
|
+
Framework-specific setup for Vue, Lit, Astro, and SvelteKit: [`docs/FRAMEWORKS.md`](https://github.com/PetriLahdelma/stylelint-plugin-rhythmguard/blob/main/docs/FRAMEWORKS.md)
|
|
207
|
+
|
|
134
208
|
## Comparison and Migration Recipes
|
|
135
209
|
|
|
136
210
|
- Side-by-side tool fit guide with migration snippets: [`docs/COMPARISON.md`](https://github.com/petrilahdelma/stylelint-plugin-rhythmguard/blob/main/docs/COMPARISON.md)
|
|
211
|
+
- Audit 2.0 validation and roadmap: [`docs/AUDIT_2_VALIDATION.md`](https://github.com/petrilahdelma/stylelint-plugin-rhythmguard/blob/main/docs/AUDIT_2_VALIDATION.md)
|
|
137
212
|
- Real-world before/after excerpts from public repos: [`docs/ADOPTION_DIFFS.md`](https://github.com/petrilahdelma/stylelint-plugin-rhythmguard/blob/main/docs/ADOPTION_DIFFS.md)
|
|
138
213
|
- Distribution submissions to Stylelint discovery surfaces: [`docs/DISTRIBUTION.md`](https://github.com/petrilahdelma/stylelint-plugin-rhythmguard/blob/main/docs/DISTRIBUTION.md)
|
|
139
214
|
|
|
@@ -409,7 +484,7 @@ Options:
|
|
|
409
484
|
| `mathFunctionArguments` | `Record<mathFn, number[]>` | `{}` | Restricts linting to specific 1-based argument indexes per math function |
|
|
410
485
|
| `ignoreMathFunctionArguments` | `Record<mathFn, number[]>` | `{}` | Excludes specific 1-based argument indexes per math function |
|
|
411
486
|
| `tokenMap` | `Record<string,string>` | `{}` | Enables autofix from raw value to token |
|
|
412
|
-
| `tokenMapFile` | `string` | `null` | JSON file path to merge additional token mappings |
|
|
487
|
+
| `tokenMapFile` | `string` | `null` | JSON file path to merge additional token mappings (supports flat, Style Dictionary, and W3C DTCG formats) |
|
|
413
488
|
| `tokenMapFromCssCustomProperties` | `boolean` | `false` | Auto-builds mappings from matching custom property declarations in the same stylesheet |
|
|
414
489
|
| `tokenMapFromTailwindSpacing` | `boolean` | `false` | Auto-builds mappings from `theme.spacing` and `theme.extend.spacing` in Tailwind config |
|
|
415
490
|
| `tailwindConfigPath` | `string` | `null` | Path to Tailwind config used by `tokenMapFromTailwindSpacing` (`.js`, `.cjs`, `.mjs`) |
|
|
@@ -450,13 +525,19 @@ Rhythmguard works well in Tailwind projects, but it enforces what Stylelint can
|
|
|
450
525
|
- CSS Modules (for example `*.module.css`)
|
|
451
526
|
- declarations inside `@layer` blocks
|
|
452
527
|
|
|
453
|
-
###
|
|
528
|
+
### Tailwind v4 @theme tokens
|
|
529
|
+
|
|
530
|
+
The `tailwind` config preset automatically extracts spacing tokens from Tailwind v4 `@theme` blocks and uses them for `prefer-token` enforcement. Raw values like `padding: 16px` are autofixed to `padding: var(--spacing-4)`.
|
|
531
|
+
|
|
532
|
+
See [`docs/TAILWIND.md`](https://github.com/PetriLahdelma/stylelint-plugin-rhythmguard/blob/main/docs/TAILWIND.md) for full setup.
|
|
533
|
+
|
|
534
|
+
### What the Stylelint layer does not cover
|
|
454
535
|
|
|
455
536
|
- Tailwind class strings in templates/JSX/TSX, for example:
|
|
456
537
|
- `class="p-4 gap-2"`
|
|
457
538
|
- `class="p-[13px] translate-y-[18px]"`
|
|
458
539
|
|
|
459
|
-
Those are not Stylelint declaration nodes, so they are outside Stylelint rule scope.
|
|
540
|
+
Those are not Stylelint declaration nodes, so they are outside Stylelint rule scope. Use the ESLint companion rule below for scale-aware class-string enforcement.
|
|
460
541
|
|
|
461
542
|
### Companion ESLint layer for class strings
|
|
462
543
|
|
|
@@ -480,6 +561,18 @@ export default [
|
|
|
480
561
|
|
|
481
562
|
This rule targets arbitrary spacing utilities such as `p-[13px]`, `gap-[18px]`, `translate-x-[10px]`, and autofixes to the nearest configured scale value.
|
|
482
563
|
|
|
564
|
+
#### Supported patterns
|
|
565
|
+
|
|
566
|
+
The rule checks every string literal in your code, so it works automatically with common utility functions:
|
|
567
|
+
|
|
568
|
+
- `cn("p-[13px]")` / `cn("p-[13px]", condition && "m-[7px]")`
|
|
569
|
+
- `clsx("p-[13px]", "gap-[18px]")`
|
|
570
|
+
- `twMerge("p-[13px]", otherClasses)`
|
|
571
|
+
- `cva("base", { variants: { size: { sm: "p-[5px]" } } })`
|
|
572
|
+
- `<div className={cn("p-[13px]")} />`
|
|
573
|
+
|
|
574
|
+
No extra config needed — if the string contains an arbitrary spacing value, it gets caught and autofixed.
|
|
575
|
+
|
|
483
576
|
### Recommended stack for full Tailwind enforcement
|
|
484
577
|
|
|
485
578
|
Use both layers:
|
|
@@ -498,7 +591,7 @@ Suggested setup:
|
|
|
498
591
|
Then pair with:
|
|
499
592
|
|
|
500
593
|
- `stylelint-plugin-rhythmguard/eslint` for arbitrary spacing class-string scale enforcement.
|
|
501
|
-
- `eslint-plugin-tailwindcss` for broader class-string linting and conventions.
|
|
594
|
+
- `eslint-plugin-tailwindcss` for broader class-string linting and conventions. If your policy is to ban every arbitrary value, enable its `tailwindcss/no-arbitrary-value` rule; use Rhythmguard when you want spacing-specific scale checks and nearest-value fixes.
|
|
502
595
|
- `prettier-plugin-tailwindcss` for deterministic class ordering.
|
|
503
596
|
|
|
504
597
|
Detailed setup reference: [`docs/TAILWIND.md`](https://github.com/PetriLahdelma/stylelint-plugin-rhythmguard/blob/main/docs/TAILWIND.md).
|
|
@@ -521,6 +614,35 @@ console.log(rhythmguard.presets.scales['rhythmic-4']);
|
|
|
521
614
|
console.log(Object.keys(rhythmguard.eslint.rules));
|
|
522
615
|
```
|
|
523
616
|
|
|
617
|
+
## Token File Formats
|
|
618
|
+
|
|
619
|
+
The `tokenMapFile` option supports multiple JSON formats:
|
|
620
|
+
|
|
621
|
+
**Flat token-to-value:**
|
|
622
|
+
|
|
623
|
+
```json
|
|
624
|
+
{ "--spacing-4": "16px", "--spacing-3": "12px" }
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
**Style Dictionary:**
|
|
628
|
+
|
|
629
|
+
```json
|
|
630
|
+
{ "--spacing-4": { "value": "16px" } }
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
**W3C DTCG (Design Token Community Group):**
|
|
634
|
+
|
|
635
|
+
```json
|
|
636
|
+
{
|
|
637
|
+
"spacing": {
|
|
638
|
+
"4": { "$value": "16px", "$type": "dimension" },
|
|
639
|
+
"2": { "$value": "8px", "$type": "dimension" }
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
Nested DTCG groups are walked recursively. The key path becomes the CSS variable name: `spacing.4` → `var(--spacing-4)`. Non-length values (colors, fonts) are ignored automatically.
|
|
645
|
+
|
|
524
646
|
## Autofix Philosophy
|
|
525
647
|
|
|
526
648
|
Rhythmguard only applies deterministic fixes:
|
|
@@ -565,8 +687,6 @@ Detailed methodology and custom args are documented in [`docs/BENCHMARKING.md`](
|
|
|
565
687
|
## Article
|
|
566
688
|
|
|
567
689
|
- Dev.to: [Enforcing your spacing standards with Rhythmguard](https://dev.to/petrilahdelma/enforcing-your-spacing-standards-with-rhythmguard-a-custom-stylelint-plugin-1ojj)
|
|
568
|
-
- Original article update note (Feb 21, 2026): [`docs/DEVTO_ORIGINAL_UPDATE_NOTE_2026-02-21.md`](https://github.com/petrilahdelma/stylelint-plugin-rhythmguard/blob/main/docs/DEVTO_ORIGINAL_UPDATE_NOTE_2026-02-21.md)
|
|
569
|
-
- Continuation draft (ready to publish): [`docs/DEVTO_CONTINUATION_2026-02-21.md`](https://github.com/petrilahdelma/stylelint-plugin-rhythmguard/blob/main/docs/DEVTO_CONTINUATION_2026-02-21.md)
|
|
570
690
|
|
|
571
691
|
## Used by and Community Examples
|
|
572
692
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stylelint-plugin-rhythmguard",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.6.0",
|
|
4
|
+
"description": "Token governance for CSS and Tailwind — enforce spacing scales, require design tokens, catch arbitrary values",
|
|
5
|
+
"bin": {
|
|
6
|
+
"rhythmguard": "src/cli/index.js"
|
|
7
|
+
},
|
|
5
8
|
"keywords": [
|
|
6
9
|
"stylelint",
|
|
7
10
|
"stylelint-plugin",
|
|
@@ -46,6 +49,10 @@
|
|
|
46
49
|
"require": "./src/configs/migration.js",
|
|
47
50
|
"import": "./src/configs/migration.mjs"
|
|
48
51
|
},
|
|
52
|
+
"./configs/react-tailwind": {
|
|
53
|
+
"require": "./src/configs/react-tailwind.js",
|
|
54
|
+
"import": "./src/configs/react-tailwind.mjs"
|
|
55
|
+
},
|
|
49
56
|
"./presets": {
|
|
50
57
|
"require": "./src/presets/index.js",
|
|
51
58
|
"import": "./src/presets/index.mjs"
|
|
@@ -92,7 +99,7 @@
|
|
|
92
99
|
},
|
|
93
100
|
"repository": {
|
|
94
101
|
"type": "git",
|
|
95
|
-
"url": "
|
|
102
|
+
"url": "https://github.com/PetriLahdelma/stylelint-plugin-rhythmguard"
|
|
96
103
|
},
|
|
97
104
|
"homepage": "https://github.com/petrilahdelma/stylelint-plugin-rhythmguard#readme",
|
|
98
105
|
"bugs": {
|