styleproof 1.7.0 → 1.7.2
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 +20 -0
- package/dist/describe.d.ts +2 -0
- package/dist/describe.js +22 -6
- package/dist/report.js +12 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,26 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.7.2]
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **Responsive variants of one change no longer show as duplicate sections.** A
|
|
15
|
+
grid whose `grid-template-columns/rows` computes to different pixels per width
|
|
16
|
+
(`282px ×2` vs `282px 228px`) was given a different signature per width, so the
|
|
17
|
+
same change rendered once per breakpoint. The signature now keys grid tracks by
|
|
18
|
+
their COUNT, so responsive widths collapse into one grouped section.
|
|
19
|
+
- The `e.g. …` fold line no longer names the `+N more` overflow marker as if it
|
|
20
|
+
were a change.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- A colour bullet no longer repeats a role word that matches its token name
|
|
25
|
+
(`text \`text\` (#bfe9f5)` becomes `` `text` (`#bfe9f5`) ``).
|
|
26
|
+
- When several same-label elements fold but share no change, the line names the
|
|
27
|
+
most common changes (`e.g. … _(vary)_`) instead of an uninformative
|
|
28
|
+
`restyled _(details vary)_`.
|
|
29
|
+
|
|
10
30
|
## [1.7.0]
|
|
11
31
|
|
|
12
32
|
Colour changes are named by their theme token, shown as hex with a live swatch,
|
package/dist/describe.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ export declare function toHex(v: string): string;
|
|
|
25
25
|
/** Reverse-index a token map (`--red-200` → `rgb(...)`) to value → token name,
|
|
26
26
|
* preferring a scale step (`red-200`) over an alias, then the shorter name. */
|
|
27
27
|
export declare function tokenIndex(tokens?: Record<string, string>): Map<string, string>;
|
|
28
|
+
/** Count grid tracks in a `grid-template-*` value, honouring the `Npx ×K` form. */
|
|
29
|
+
export declare function trackCount(v: string): number;
|
|
28
30
|
/** Token reverse-indexes for each side, so colour rules can name `red-200`. */
|
|
29
31
|
export type DescribeCtx = {
|
|
30
32
|
tokensBefore?: Map<string, string>;
|
package/dist/describe.js
CHANGED
|
@@ -117,7 +117,7 @@ const shift = (before, after, idxB, idxA) => {
|
|
|
117
117
|
};
|
|
118
118
|
// --- track counting for grid columns/rows ------------------------------------
|
|
119
119
|
/** Count grid tracks in a `grid-template-*` value, honouring the `Npx ×K` form. */
|
|
120
|
-
function trackCount(v) {
|
|
120
|
+
export function trackCount(v) {
|
|
121
121
|
if (v === 'none' || !v)
|
|
122
122
|
return 0;
|
|
123
123
|
const rep = v.match(/×(\d+)/); // summarizeProps collapses "8px 8px 8px" → "8px ×3"
|
|
@@ -198,6 +198,8 @@ const colorRule = (m, mark, ctx) => {
|
|
|
198
198
|
['border-color', 'border colour'],
|
|
199
199
|
];
|
|
200
200
|
const sh = (c) => shift(c.before, c.after, ctx.tokensBefore, ctx.tokensAfter);
|
|
201
|
+
// Collapse a role word that just repeats the token name: `text \`text\`` → `\`text\``.
|
|
202
|
+
const deRole = (s) => s.replace(/([\w-]+) (`\1`)/g, '$2');
|
|
201
203
|
const present = fields.map(([p, w]) => [m.get(p), w]).filter(([c]) => c);
|
|
202
204
|
if (!present.length)
|
|
203
205
|
return [];
|
|
@@ -205,8 +207,8 @@ const colorRule = (m, mark, ctx) => {
|
|
|
205
207
|
const same = present.length > 1 && present.every(([c]) => c.before === first[0].before && c.after === first[0].after);
|
|
206
208
|
fields.forEach(([p]) => m.has(p) && mark(p));
|
|
207
209
|
if (same)
|
|
208
|
-
return [`recoloured ${sh(first[0])}`];
|
|
209
|
-
return present.map(([c, w]) => `${w} ${sh(c)}`);
|
|
210
|
+
return [deRole(`recoloured ${sh(first[0])}`)];
|
|
211
|
+
return present.map(([c, w]) => deRole(`${w} ${sh(c)}`));
|
|
210
212
|
};
|
|
211
213
|
const fillRule = (m, mark) => {
|
|
212
214
|
const bgi = m.get('background-image');
|
|
@@ -306,14 +308,28 @@ function domVerbLines(els) {
|
|
|
306
308
|
return Object.entries(verbs).map(([verb, n]) => `**${n}** element${n === 1 ? '' : 's'} ${verb}`);
|
|
307
309
|
}
|
|
308
310
|
const sig = (phrases) => phrases.join(', ');
|
|
309
|
-
/** One line for a same-label group
|
|
310
|
-
*
|
|
311
|
+
/** One line for a same-label group. Identical members → their line. Otherwise the
|
|
312
|
+
* phrases shared by ALL (`details vary`); and if they share none, the most common
|
|
313
|
+
* phrases (`e.g. … vary`) so the line still tells you what to look for. */
|
|
311
314
|
function foldedLine(group, ctx) {
|
|
312
315
|
const lists = group.map((el) => phrasesFor(el.props, ctx));
|
|
313
316
|
if (lists.every((l) => sig(l) === sig(lists[0])))
|
|
314
317
|
return sig(lists[0]);
|
|
315
318
|
const common = lists[0].filter((p) => lists.every((l) => l.includes(p)));
|
|
316
|
-
|
|
319
|
+
if (common.length)
|
|
320
|
+
return `${common.join(', ')} _(details vary)_`;
|
|
321
|
+
// Rank the most common REAL changes — the `+N more` overflow marker isn't a
|
|
322
|
+
// change and shouldn't be named.
|
|
323
|
+
const freq = new Map();
|
|
324
|
+
for (const l of lists)
|
|
325
|
+
for (const p of new Set(l))
|
|
326
|
+
if (!/^\+\d+ more$/.test(p))
|
|
327
|
+
freq.set(p, (freq.get(p) ?? 0) + 1);
|
|
328
|
+
const top = [...freq.entries()]
|
|
329
|
+
.sort((a, b) => b[1] - a[1])
|
|
330
|
+
.slice(0, 3)
|
|
331
|
+
.map(([p]) => p);
|
|
332
|
+
return top.length ? `e.g. ${top.join(', ')} _(vary)_` : 'restyled _(vary)_';
|
|
317
333
|
}
|
|
318
334
|
/** Restyle phrases, folded by element label (so two near-identical `span.led`s
|
|
319
335
|
* become one `×2` line with their shared changes), then deduped across labels (so
|
package/dist/report.js
CHANGED
|
@@ -3,7 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
import { PNG } from 'pngjs';
|
|
4
4
|
import { loadStyleMap } from './capture.js';
|
|
5
5
|
import { diffStyleMapDirs } from './diff.js';
|
|
6
|
-
import { describeChange, tokenIndex, toHex } from './describe.js';
|
|
6
|
+
import { describeChange, tokenIndex, toHex, trackCount } from './describe.js';
|
|
7
7
|
// Re-export the plain-English summariser so consumers (and tests) reach it
|
|
8
8
|
// through the package's report module rather than a deep path.
|
|
9
9
|
export { describeChange, colorName, tokenIndex, toHex } from './describe.js';
|
|
@@ -339,6 +339,16 @@ function formatSurfaceList(surfaces) {
|
|
|
339
339
|
})
|
|
340
340
|
.join(' · ');
|
|
341
341
|
}
|
|
342
|
+
// Grid-track longhands compute to width-dependent pixels (`282px ×2` at one width,
|
|
343
|
+
// `282px 228px` at another), so the SAME responsive change would otherwise get a
|
|
344
|
+
// different signature per width. Key them by track COUNT — what actually
|
|
345
|
+
// identifies the change — so responsive variants group into one section.
|
|
346
|
+
function sigValue(c) {
|
|
347
|
+
if (c.prop === 'grid-template-columns' || c.prop === 'grid-template-rows') {
|
|
348
|
+
return `${c.prop}=${trackCount(c.before)}t>${trackCount(c.after)}t`;
|
|
349
|
+
}
|
|
350
|
+
return `${c.prop}=${c.before}>${c.after}`;
|
|
351
|
+
}
|
|
342
352
|
/** Canonical signature of a surface's findings: surfaces that changed in the
|
|
343
353
|
* same way collapse into one section + one image (the rects differ per width;
|
|
344
354
|
* the change itself does not). */
|
|
@@ -348,11 +358,7 @@ function signatureOf(findings) {
|
|
|
348
358
|
p: f.path,
|
|
349
359
|
k: f.kind,
|
|
350
360
|
t: f.kind === 'dom' ? f.change : f.kind === 'state' ? f.state : (f.pseudo ?? ''),
|
|
351
|
-
v: f.kind === 'dom'
|
|
352
|
-
? ''
|
|
353
|
-
: summarizeProps(f.props)
|
|
354
|
-
.map((c) => `${c.prop}=${c.before}>${c.after}`)
|
|
355
|
-
.join('|'),
|
|
361
|
+
v: f.kind === 'dom' ? '' : summarizeProps(f.props).map(sigValue).join('|'),
|
|
356
362
|
}))
|
|
357
363
|
.sort((a, b) => `${a.p}|${a.k}|${a.t}`.localeCompare(`${b.p}|${b.k}|${b.t}`)));
|
|
358
364
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "styleproof",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.2",
|
|
4
4
|
"description": "Catch every CSS change before it ships — review PRs and certify refactors by the browser's computed styles, not pixels. Works with any styling system.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"playwright",
|