stylelint-plugin-rhythmguard 1.8.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/CHANGELOG.md +24 -0
- package/README.md +85 -2
- package/package.json +13 -1
- package/src/audit/index.js +17 -0
- package/src/audit/index.mjs +11 -0
- package/src/cli/audit.js +476 -115
- package/src/cli/doctor.js +95 -0
- package/src/cli/index.js +1 -1
- package/src/configs/motion.js +13 -0
- package/src/configs/motion.mjs +4 -0
- package/src/eslint/index.js +3 -0
- package/src/eslint/rules/tailwind-class-use-motion-scale.js +116 -0
- package/src/index.js +5 -1
- package/src/index.mjs +1 -0
- package/src/rules/use-motion-scale/index.js +245 -0
- package/src/rules/use-motion-scale/index.mjs +7 -0
- package/src/utils/constants.js +4 -0
- package/src/utils/tailwind-motion-analysis.js +174 -0
- package/src/utils/time.js +89 -0
- package/src/utils/token-sources.js +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,30 @@ The format follows Keep a Changelog principles and semantic versioning.
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [2.0.0] - 2026-05-23
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- `rhythmguard audit --format json` now emits the stable audit contract with `schemaVersion: "2.0"`.
|
|
14
|
+
- Moved the pre-2.0 audit JSON shape to `--format json-v1` for migration compatibility.
|
|
15
|
+
- Updated audit defaults to use the explicit spacing token pattern `^--(space|spacing)-`.
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- Added `stylelint-plugin-rhythmguard/audit` with `createAuditReport`, `loadAuditConfig`, `parseTokenSources`, and `toAuditContractReport`.
|
|
20
|
+
- Added `rhythmguard audit --format html`, `--output <file>`, and `--schema`.
|
|
21
|
+
- Added `rhythmguard doctor` checks for `.rhythmguardrc.json`, configured token sources, motion audit config, and baseline files.
|
|
22
|
+
- Added `docs/MIGRATING_TO_2.md`.
|
|
23
|
+
|
|
24
|
+
## [1.9.0] - 2026-05-23
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- Added opt-in `rhythmguard/use-motion-scale` for duration/delay scale enforcement and raw easing reporting.
|
|
29
|
+
- Added `stylelint-plugin-rhythmguard/configs/motion`.
|
|
30
|
+
- Added ESLint companion rule `rhythmguard-tailwind/tailwind-class-use-motion-scale` for Tailwind `duration-[...]`, `delay-[...]`, and `ease-[...]` arbitrary values.
|
|
31
|
+
- Added `rhythmguard audit --include-motion` and `.rhythmguardrc.json` `includeMotion` support.
|
|
32
|
+
|
|
9
33
|
## [1.8.0] - 2026-05-23
|
|
10
34
|
|
|
11
35
|
### Added
|
package/README.md
CHANGED
|
@@ -66,6 +66,7 @@ This gives you spacing governance in both CSS files and JSX/TSX templates.
|
|
|
66
66
|
| `rhythmguard/use-scale` | Enforces spacing values must be on your configured scale | Yes, nearest safe value |
|
|
67
67
|
| `rhythmguard/prefer-token` | Enforces token usage over raw spacing literals | Yes, with `tokenMap` |
|
|
68
68
|
| `rhythmguard/no-offscale-transform` | Enforces scale-aligned `translate*` motion offsets | Yes, nearest safe value |
|
|
69
|
+
| `rhythmguard/use-motion-scale` | Enforces opt-in duration/delay rhythm and flags raw easing curves | Yes, for duration/delay values |
|
|
69
70
|
|
|
70
71
|
## Demo
|
|
71
72
|
|
|
@@ -95,9 +96,12 @@ npx rhythmguard audit ./src --since-baseline --fail-on-new-drift
|
|
|
95
96
|
npx rhythmguard audit ./src --staged --max-findings 0
|
|
96
97
|
npx rhythmguard audit ./src --token-source ./tokens.json
|
|
97
98
|
npx rhythmguard audit ./src --token-source ./theme.css --token-source-format css
|
|
99
|
+
npx rhythmguard audit ./src --include-motion
|
|
100
|
+
npx rhythmguard audit ./src --format html --output rhythmguard-report.html
|
|
101
|
+
npx rhythmguard audit --schema
|
|
98
102
|
```
|
|
99
103
|
|
|
100
|
-
The report covers authored CSS declarations, Tailwind arbitrary spacing values in common template/source files, and token-contract drift such as missing spacing tokens, unused spacing tokens, repeated raw values that deserve token review, raw values that match known tokens,
|
|
104
|
+
The report covers authored CSS declarations, Tailwind arbitrary spacing values in common template/source files, and token-contract drift such as missing spacing tokens, unused spacing tokens, repeated raw values that deserve token review, raw values that match known tokens, conflicting token values, and opt-in motion rhythm drift. Scan paths are scoped to the directory argument. Use `--ignore`, `.rhythmguardignore`, or `--ignore-path` for generated or legacy subtrees, then add baselines and CI thresholds when you are ready to gate new drift. Markdown output is PR-ready for UX developers, UX designers, and design-system owners:
|
|
101
105
|
|
|
102
106
|
```md
|
|
103
107
|
# Rhythmguard Design-System Audit
|
|
@@ -125,6 +129,7 @@ For large codebases, put shared audit settings in `.rhythmguardrc.json`:
|
|
|
125
129
|
{ "path": "./src/theme.css", "format": "css" }
|
|
126
130
|
],
|
|
127
131
|
"tokenKind": "spacing",
|
|
132
|
+
"includeMotion": false,
|
|
128
133
|
"tokenCandidateMinCount": 2,
|
|
129
134
|
"minCleanliness": 90
|
|
130
135
|
}
|
|
@@ -133,6 +138,44 @@ For large codebases, put shared audit settings in `.rhythmguardrc.json`:
|
|
|
133
138
|
|
|
134
139
|
`rhythmguard audit` loads `.rhythmguardrc.json` automatically when present. Use `--config <file>` for another config, `--no-config` to skip config discovery, and `--token-source <file>` for extra canonical token files. Token source paths in config files resolve from the config file directory; CLI token source paths resolve from the current working directory. Supported source formats are CSS custom properties and Tailwind v4 `@theme`, flat JSON maps, Style Dictionary JSON, and DTCG JSON.
|
|
135
140
|
|
|
141
|
+
### Audit JSON 2.0 and API
|
|
142
|
+
|
|
143
|
+
In Rhythmguard 2.0, `--format json` emits the stable audit contract:
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"schemaVersion": "2.0",
|
|
148
|
+
"command": { "directory": "./src", "scanScope": "full" },
|
|
149
|
+
"summary": { "totalFindings": 12, "scaleCleanliness": 94 },
|
|
150
|
+
"scanned": { "cssFiles": 10, "templateFiles": 20 },
|
|
151
|
+
"contracts": {
|
|
152
|
+
"scale": {},
|
|
153
|
+
"tokens": {},
|
|
154
|
+
"motion": {}
|
|
155
|
+
},
|
|
156
|
+
"findings": {
|
|
157
|
+
"css": [],
|
|
158
|
+
"tailwind": [],
|
|
159
|
+
"motion": []
|
|
160
|
+
},
|
|
161
|
+
"baseline": null
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Use `--format json-v1` for the pre-2.0 JSON shape during migration.
|
|
166
|
+
|
|
167
|
+
Programmatic usage:
|
|
168
|
+
|
|
169
|
+
```js
|
|
170
|
+
const {
|
|
171
|
+
createAuditReport,
|
|
172
|
+
toAuditContractReport,
|
|
173
|
+
} = require('stylelint-plugin-rhythmguard/audit');
|
|
174
|
+
|
|
175
|
+
const report = await createAuditReport({ dir: './src', noConfig: true });
|
|
176
|
+
const contract = toAuditContractReport(report);
|
|
177
|
+
```
|
|
178
|
+
|
|
136
179
|
## Installation
|
|
137
180
|
|
|
138
181
|
```bash
|
|
@@ -221,6 +264,16 @@ npm install --save-dev stylelint-plugin-rhythmguard
|
|
|
221
264
|
|
|
222
265
|
`react-tailwind` extends the tailwind config with CSS Modules overrides (spacing + radius enforcement) and ignores Next.js build directories.
|
|
223
266
|
|
|
267
|
+
### Motion config
|
|
268
|
+
|
|
269
|
+
```json
|
|
270
|
+
{
|
|
271
|
+
"extends": ["stylelint-plugin-rhythmguard/configs/motion"]
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
`motion` enables opt-in duration/delay rhythm checks with `rhythmguard/use-motion-scale`.
|
|
276
|
+
|
|
224
277
|
Stable shared config entry points:
|
|
225
278
|
|
|
226
279
|
- `stylelint-plugin-rhythmguard/configs/recommended`
|
|
@@ -230,6 +283,7 @@ Stable shared config entry points:
|
|
|
230
283
|
- `stylelint-plugin-rhythmguard/configs/expanded`
|
|
231
284
|
- `stylelint-plugin-rhythmguard/configs/logical`
|
|
232
285
|
- `stylelint-plugin-rhythmguard/configs/migration`
|
|
286
|
+
- `stylelint-plugin-rhythmguard/configs/motion`
|
|
233
287
|
|
|
234
288
|
Framework-specific setup for Vue, Lit, Astro, and SvelteKit: [`docs/FRAMEWORKS.md`](https://github.com/PetriLahdelma/stylelint-plugin-rhythmguard/blob/main/docs/FRAMEWORKS.md)
|
|
235
289
|
|
|
@@ -471,7 +525,7 @@ Options:
|
|
|
471
525
|
| `enforceInsideMathFunctions` | `boolean` | `false` | Lints `calc()/clamp()/min()/max()` internals |
|
|
472
526
|
| `mathFunctionArguments` | `Record<mathFn, number[]>` | `{}` | Restricts linting to specific 1-based argument indexes per math function |
|
|
473
527
|
| `ignoreMathFunctionArguments` | `Record<mathFn, number[]>` | `{}` | Excludes specific 1-based argument indexes per math function |
|
|
474
|
-
| `propertyGroups` | `Array<'spacing' \| 'radius' \| 'typography' \| 'size'>` | `['spacing']` | Selects built-in property groups when `properties` is not provided |
|
|
528
|
+
| `propertyGroups` | `Array<'spacing' \| 'radius' \| 'typography' \| 'size' \| 'motion'>` | `['spacing']` | Selects built-in property groups when `properties` is not provided |
|
|
475
529
|
| `properties` | `Array<string|RegExp>` | built-in spacing patterns | Override targeted property set; string values may be supported property names or regex-like strings (`/pattern/flags`) |
|
|
476
530
|
| `propertyScales` | `Record<propertyOrRegex, scaleOrPreset>` | `{}` | Per-property scale overrides (supports exact names or `/regex/flags` keys; stateful `g`/`y` flags are normalized for deterministic matching) |
|
|
477
531
|
|
|
@@ -543,6 +597,35 @@ Options:
|
|
|
543
597
|
|
|
544
598
|
`rhythmguard/no-offscale-transform` accepts the same scale options as `rhythmguard/use-scale` (including `unitStrategy`, math argument targeting, and deterministic autofix), but only for transform translation properties. Its secondary options are also validated for unknown keys and invalid value shapes.
|
|
545
599
|
|
|
600
|
+
### `rhythmguard/use-motion-scale`
|
|
601
|
+
|
|
602
|
+
Opt-in guardrail for duration, delay, and easing rhythm.
|
|
603
|
+
|
|
604
|
+
Example:
|
|
605
|
+
|
|
606
|
+
```css
|
|
607
|
+
/* ❌ Off-scale timing + raw easing */
|
|
608
|
+
.button {
|
|
609
|
+
transition: opacity 175ms cubic-bezier(.2, 0, 0, 1);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
/* ✅ Timing on motion scale */
|
|
613
|
+
.button {
|
|
614
|
+
transition: opacity 150ms var(--ease-snappy);
|
|
615
|
+
}
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
Options:
|
|
619
|
+
|
|
620
|
+
| Option | Type | Default | Description |
|
|
621
|
+
| --- | --- | --- | --- |
|
|
622
|
+
| `durationScale` | `number[]` | `[0,75,100,150,200,300,500,700,1000]` | Allowed duration and delay values in milliseconds |
|
|
623
|
+
| `durationUnits` | `Array<'ms' \| 's'>` | `['ms','s']` | Time units considered by the rule |
|
|
624
|
+
| `fixToScale` | `boolean` | `true` | Autofixes simple duration/delay values to the nearest scale value |
|
|
625
|
+
| `easingTokenMap` | `Record<string,string>` | `{}` | Optional exact replacements for raw easing functions |
|
|
626
|
+
|
|
627
|
+
Tailwind class strings can use the ESLint companion rule `rhythmguard-tailwind/tailwind-class-use-motion-scale` for `duration-[...]`, `delay-[...]`, and `ease-[...]` arbitrary values.
|
|
628
|
+
|
|
546
629
|
## Tailwind CSS Integration
|
|
547
630
|
|
|
548
631
|
Rhythmguard works well in Tailwind projects, but it enforces what Stylelint can parse: CSS declarations.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stylelint-plugin-rhythmguard",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Token governance for CSS and Tailwind — enforce spacing scales, require design tokens, catch arbitrary values",
|
|
5
5
|
"bin": {
|
|
6
6
|
"rhythmguard": "src/cli/index.js"
|
|
@@ -49,6 +49,10 @@
|
|
|
49
49
|
"require": "./src/configs/migration.js",
|
|
50
50
|
"import": "./src/configs/migration.mjs"
|
|
51
51
|
},
|
|
52
|
+
"./configs/motion": {
|
|
53
|
+
"require": "./src/configs/motion.js",
|
|
54
|
+
"import": "./src/configs/motion.mjs"
|
|
55
|
+
},
|
|
52
56
|
"./configs/react-tailwind": {
|
|
53
57
|
"require": "./src/configs/react-tailwind.js",
|
|
54
58
|
"import": "./src/configs/react-tailwind.mjs"
|
|
@@ -57,6 +61,10 @@
|
|
|
57
61
|
"require": "./src/presets/index.js",
|
|
58
62
|
"import": "./src/presets/index.mjs"
|
|
59
63
|
},
|
|
64
|
+
"./audit": {
|
|
65
|
+
"require": "./src/audit/index.js",
|
|
66
|
+
"import": "./src/audit/index.mjs"
|
|
67
|
+
},
|
|
60
68
|
"./rules/use-scale": {
|
|
61
69
|
"require": "./src/rules/use-scale/index.js",
|
|
62
70
|
"import": "./src/rules/use-scale/index.mjs"
|
|
@@ -69,6 +77,10 @@
|
|
|
69
77
|
"require": "./src/rules/no-offscale-transform/index.js",
|
|
70
78
|
"import": "./src/rules/no-offscale-transform/index.mjs"
|
|
71
79
|
},
|
|
80
|
+
"./rules/use-motion-scale": {
|
|
81
|
+
"require": "./src/rules/use-motion-scale/index.js",
|
|
82
|
+
"import": "./src/rules/use-motion-scale/index.mjs"
|
|
83
|
+
},
|
|
72
84
|
"./eslint": {
|
|
73
85
|
"require": "./src/eslint/index.js",
|
|
74
86
|
"import": "./src/eslint/index.mjs"
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
AUDIT_JSON_SCHEMA,
|
|
5
|
+
createAuditReport,
|
|
6
|
+
loadAuditConfig,
|
|
7
|
+
toAuditContractReport,
|
|
8
|
+
} = require('../cli/audit');
|
|
9
|
+
const { parseTokenSources } = require('../utils/token-sources');
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
AUDIT_JSON_SCHEMA,
|
|
13
|
+
createAuditReport,
|
|
14
|
+
loadAuditConfig,
|
|
15
|
+
parseTokenSources,
|
|
16
|
+
toAuditContractReport,
|
|
17
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
|
|
3
|
+
const require = createRequire(import.meta.url);
|
|
4
|
+
const audit = require('./index.js');
|
|
5
|
+
|
|
6
|
+
export default audit;
|
|
7
|
+
export const AUDIT_JSON_SCHEMA = audit.AUDIT_JSON_SCHEMA;
|
|
8
|
+
export const createAuditReport = audit.createAuditReport;
|
|
9
|
+
export const loadAuditConfig = audit.loadAuditConfig;
|
|
10
|
+
export const parseTokenSources = audit.parseTokenSources;
|
|
11
|
+
export const toAuditContractReport = audit.toAuditContractReport;
|