stylelint-plugin-rhythmguard 3.10.2 → 3.12.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 +77 -0
- package/README.md +5 -1
- package/package.json +1 -1
- package/src/audit/args.js +22 -2
- package/src/audit/baseline.js +184 -27
- package/src/audit/codemod.js +39 -14
- package/src/audit/config.js +25 -31
- package/src/audit/contract.js +96 -10
- package/src/audit/render-github.js +4 -0
- package/src/audit/render-html.js +7 -0
- package/src/audit/render-markdown.js +27 -0
- package/src/audit/render-text.js +23 -1
- package/src/audit/report.js +60 -17
- package/src/audit/scan/files.js +154 -27
- package/src/audit/scan/stylesheets.js +87 -34
- package/src/audit/scan/templates.js +22 -7
- package/src/audit/token-chains.js +18 -7
- package/src/cli/audit.js +7 -3
- package/src/cli/doctor.js +48 -7
- package/src/cli/fix.js +56 -15
- package/src/cli/init.js +136 -23
- package/src/cli/quickstart.js +34 -8
- package/src/core/fs-cache.js +6 -0
- package/src/core/length.js +15 -0
- package/src/core/options.js +8 -1
- package/src/core/scale-inference.js +99 -68
- package/src/core/tailwind-class-analysis.js +26 -16
- package/src/core/tailwind-motion-analysis.js +12 -3
- package/src/core/token-index.js +76 -24
- package/src/core/token-map.js +23 -10
- package/src/core/token-source-entries.js +64 -0
- package/src/core/token-sources.js +361 -69
- package/src/core/value-nodes.js +280 -54
- package/src/eslint/literal-spans.js +319 -0
- package/src/eslint/rules/tailwind-class-use-motion-scale.js +9 -32
- package/src/eslint/rules/tailwind-class-use-scale.js +45 -40
- package/src/rules/no-offscale-transform/index.js +35 -14
- package/src/rules/prefer-token/index.js +72 -48
- package/src/rules/report.js +3 -1
- package/src/rules/use-motion-scale/index.js +68 -5
- package/src/rules/use-scale/index.js +54 -39
- package/types/__checks__/eslint-config.ts +37 -0
- package/types/audit.d.ts +10 -2
- package/types/shared.d.ts +21 -3
package/src/core/token-map.js
CHANGED
|
@@ -71,11 +71,12 @@ function addLengthValueMapping(map, rawLength, tokenReference, baseFontSize, ori
|
|
|
71
71
|
origins[token] = origin;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
// Keyed by the signed value: a -8px token stands for -8px, never for 8px
|
|
75
|
+
// (issue #221). prefer-token negates a positive token for a negative literal.
|
|
76
|
+
const normalizedRaw = formatLength(parsed.number, parsed.unit || 'px');
|
|
76
77
|
map[normalizedRaw] = token;
|
|
77
78
|
|
|
78
|
-
const px = toPx(
|
|
79
|
+
const px = toPx(parsed.number, parsed.unit, baseFontSize);
|
|
79
80
|
if (px !== null) {
|
|
80
81
|
map[`${px}px`] = token;
|
|
81
82
|
}
|
|
@@ -211,23 +212,36 @@ function mergeTokenMapFromCssCustomProperties({
|
|
|
211
212
|
};
|
|
212
213
|
const origin = displayOrigin(root && root.source && root.source.input ? root.source.input.file : null);
|
|
213
214
|
|
|
215
|
+
// Every value each custom property is given in the file. A property given
|
|
216
|
+
// two values (at the root and under a media query, a theme or a data
|
|
217
|
+
// attribute) renders differently there, so no fix writes it (issue #231).
|
|
218
|
+
const valuesByProp = new Map();
|
|
214
219
|
root.walkDecls((decl) => {
|
|
215
220
|
const prop = decl.prop.toLowerCase();
|
|
216
|
-
if (!prop.startsWith('--')) {
|
|
221
|
+
if (!prop.startsWith('--') || !tokenRegex.test(prop)) {
|
|
217
222
|
return;
|
|
218
223
|
}
|
|
224
|
+
const parsed = parseTokenValueLength(decl.value);
|
|
225
|
+
const px = parsed ? toPx(parsed.number, parsed.unit, baseFontSize) : null;
|
|
226
|
+
const key = px === null ? `raw:${decl.value.trim()}` : `px:${formatLength(px, 'px')}`;
|
|
227
|
+
if (!valuesByProp.has(decl.prop)) {
|
|
228
|
+
valuesByProp.set(decl.prop, { decl, keys: new Set() });
|
|
229
|
+
}
|
|
230
|
+
valuesByProp.get(decl.prop).keys.add(key);
|
|
231
|
+
});
|
|
219
232
|
|
|
220
|
-
|
|
221
|
-
|
|
233
|
+
for (const { decl, keys } of valuesByProp.values()) {
|
|
234
|
+
if (keys.size > 1) {
|
|
235
|
+
continue;
|
|
222
236
|
}
|
|
223
237
|
|
|
224
238
|
const parsed = parseTokenValueLength(decl.value);
|
|
225
239
|
if (!parsed || parsed.number === 0) {
|
|
226
|
-
|
|
240
|
+
continue;
|
|
227
241
|
}
|
|
228
242
|
|
|
229
243
|
addLengthValueMapping(nextMap, decl.value, `var(${decl.prop})`, baseFontSize, origins, origin);
|
|
230
|
-
}
|
|
244
|
+
}
|
|
231
245
|
|
|
232
246
|
return nextMap;
|
|
233
247
|
}
|
|
@@ -375,8 +389,7 @@ function mergeTokenMapFromTailwindSpacing({
|
|
|
375
389
|
continue;
|
|
376
390
|
}
|
|
377
391
|
|
|
378
|
-
const
|
|
379
|
-
const normalizedRaw = formatLength(absolute, parsed.unit || 'px');
|
|
392
|
+
const normalizedRaw = formatLength(parsed.number, parsed.unit || 'px');
|
|
380
393
|
nextMap[normalizedRaw] = `theme(spacing.${key})`;
|
|
381
394
|
if (origins && !origins[nextMap[normalizedRaw]]) {
|
|
382
395
|
origins[nextMap[normalizedRaw]] = displayOrigin(resolvedPath);
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
|
|
5
|
+
const { normalizeTokenSourceFormat } = require('./token-sources');
|
|
6
|
+
|
|
7
|
+
function isNonEmptyString(value) {
|
|
8
|
+
return typeof value === 'string' && value.trim().length > 0;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* One reading of a token source entry, shared by the lint (`scaleSources`,
|
|
13
|
+
* `.rhythmguardrc.json`) and the audit (config file, CLI, API), so both read
|
|
14
|
+
* the same files from the same config (issue #271). An entry is a path string
|
|
15
|
+
* or an object with `path` (or its alias `file`), and optionally `format`,
|
|
16
|
+
* `baseDir` (resolved from `baseDir` given here, the config file's directory
|
|
17
|
+
* for a config file) and `tokenPattern`.
|
|
18
|
+
*
|
|
19
|
+
* Returns `{ source }` with `{ baseDir, format, path, tokenPattern? }`, ready
|
|
20
|
+
* for parseTokenSources, or `{ error }` with a message; it never throws, so
|
|
21
|
+
* the lint can turn a bad entry into a warning and the audit into an error.
|
|
22
|
+
*/
|
|
23
|
+
function normalizeTokenSourceEntry(entry, baseDir, { defaultFormat = 'auto' } = {}) {
|
|
24
|
+
if (typeof entry === 'string') {
|
|
25
|
+
entry = { path: entry };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {
|
|
29
|
+
return { error: 'audit.tokenSources entries must be strings or objects.' };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const sourcePath = entry.path || entry.file;
|
|
33
|
+
if (!isNonEmptyString(sourcePath)) {
|
|
34
|
+
return { error: 'token source objects must include a path.' };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (entry.tokenPattern !== undefined && !isNonEmptyString(entry.tokenPattern)) {
|
|
38
|
+
return { error: 'token source tokenPattern must be a non-empty string.' };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (entry.baseDir !== undefined && !isNonEmptyString(entry.baseDir)) {
|
|
42
|
+
return { error: 'token source baseDir must be a non-empty string.' };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let format;
|
|
46
|
+
try {
|
|
47
|
+
format = normalizeTokenSourceFormat(entry.format || defaultFormat);
|
|
48
|
+
} catch (err) {
|
|
49
|
+
return { error: err.message };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
source: {
|
|
54
|
+
baseDir: entry.baseDir ? path.resolve(baseDir, entry.baseDir) : baseDir,
|
|
55
|
+
format,
|
|
56
|
+
path: sourcePath,
|
|
57
|
+
...(entry.tokenPattern ? { tokenPattern: entry.tokenPattern } : {}),
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = {
|
|
63
|
+
normalizeTokenSourceEntry,
|
|
64
|
+
};
|