@variance-authority/core 0.15.0 → 0.17.1
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 +424 -0
- package/README.md +25 -7
- package/dist/attribute/component-hash.d.ts +11 -3
- package/dist/attribute/component-hash.js +11 -3
- package/dist/attribute/component-hash.js.map +1 -1
- package/dist/attribute/movement.d.ts +1 -1
- package/dist/attribute/movement.js.map +1 -1
- package/dist/attribute/region.d.ts +47 -4
- package/dist/attribute/region.js +90 -17
- package/dist/attribute/region.js.map +1 -1
- package/dist/attribute/source.d.ts +1 -1
- package/dist/attribute/source.js +1 -1
- package/dist/attribute/source.js.map +1 -1
- package/dist/compare/band.d.ts +8 -2
- package/dist/compare/band.js +7 -2
- package/dist/compare/band.js.map +1 -1
- package/dist/compare/diff/attribution.js +6 -4
- package/dist/compare/diff/attribution.js.map +1 -1
- package/dist/compare/diff/compare-nodes.js +9 -1
- package/dist/compare/diff/compare-nodes.js.map +1 -1
- package/dist/compare/diff/match.d.ts +2 -1
- package/dist/compare/diff/match.js +52 -0
- package/dist/compare/diff/match.js.map +1 -1
- package/dist/compare/parting.js +6 -4
- package/dist/compare/parting.js.map +1 -1
- package/dist/format/document.d.ts +26 -3
- package/dist/format/document.js.map +1 -1
- package/dist/format/index.d.ts +7 -0
- package/dist/format/index.js +4 -0
- package/dist/format/index.js.map +1 -1
- package/dist/format/packed.d.ts +32 -0
- package/dist/format/packed.js +23 -0
- package/dist/format/packed.js.map +1 -0
- package/dist/format/shape.d.ts +31 -0
- package/dist/format/shape.js +269 -0
- package/dist/format/shape.js.map +1 -0
- package/dist/format/stabilize.d.ts +7 -1
- package/dist/format/stabilize.js +10 -3
- package/dist/format/stabilize.js.map +1 -1
- package/dist/format/steps.d.ts +44 -0
- package/dist/format/steps.js +67 -0
- package/dist/format/steps.js.map +1 -0
- package/dist/format/width.d.ts +35 -0
- package/dist/format/width.js +38 -0
- package/dist/format/width.js.map +1 -0
- package/dist/judge/docket.js +1 -0
- package/dist/judge/docket.js.map +1 -1
- package/dist/judge/index.d.ts +1 -0
- package/dist/judge/index.js +1 -0
- package/dist/judge/index.js.map +1 -1
- package/dist/judge/restamp.d.ts +20 -0
- package/dist/judge/restamp.js +20 -0
- package/dist/judge/restamp.js.map +1 -0
- package/dist/relate/before.js +2 -2
- package/dist/relate/before.js.map +1 -1
- package/dist/relate/carried.d.ts +1 -1
- package/dist/relate/carried.js +5 -5
- package/dist/relate/carried.js.map +1 -1
- package/dist/relate/graph.d.ts +14 -12
- package/dist/relate/graph.js +12 -11
- package/dist/relate/graph.js.map +1 -1
- package/dist/relate/index.d.ts +1 -2
- package/dist/relate/index.js +1 -2
- package/dist/relate/index.js.map +1 -1
- package/dist/relate/reach.d.ts +5 -5
- package/dist/relate/reach.js.map +1 -1
- package/dist/relate/records.d.ts +5 -4
- package/dist/relate/records.js +3 -2
- package/dist/relate/records.js.map +1 -1
- package/dist/rules/normalize/fixture.d.ts +2 -0
- package/dist/rules/normalize/fixture.js +2 -1
- package/dist/rules/normalize/fixture.js.map +1 -1
- package/dist/shard/placement.d.ts +10 -8
- package/dist/shard/placement.js +7 -21
- package/dist/shard/placement.js.map +1 -1
- package/dist/share/index.d.ts +1 -1
- package/dist/share/index.js +1 -1
- package/dist/share/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/relate/dominate.d.ts +0 -19
- package/dist/relate/dominate.js +0 -77
- package/dist/relate/dominate.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,429 @@
|
|
|
1
1
|
# @variance-authority/core
|
|
2
2
|
|
|
3
|
+
## 0.17.1
|
|
4
|
+
|
|
5
|
+
Lockstep release — nothing in this package changed. Every `@variance-authority/*` package shares one version.
|
|
6
|
+
|
|
7
|
+
## 0.17.0
|
|
8
|
+
|
|
9
|
+
Lockstep release — nothing in this package changed. Every `@variance-authority/*` package shares one version.
|
|
10
|
+
|
|
11
|
+
## 0.16.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- 40a19b9: A committed baseline is named for its story or test
|
|
16
|
+
|
|
17
|
+
Under `directory` and `lfs`, a baseline was written to
|
|
18
|
+
`<root>/<identity digest>/<percent-encoded subject id>.png`, so a pull request
|
|
19
|
+
that accepted one listed a 32-character hex directory nobody could check against
|
|
20
|
+
the change, and each machine that accepted wrote its own copy. `baselines.path`
|
|
21
|
+
is now a template rendered from what the subject is: `{dir}` and `{file}` (the
|
|
22
|
+
file that declares it), `{title}`, `{name}`, `{id}`, `{project}` (the
|
|
23
|
+
Playwright project's name, in the fixture's `varianceBaselinePath` only) and
|
|
24
|
+
`{engine}` (the engine's family). The default, `{title}/{name}-{engine}`,
|
|
25
|
+
writes `Ui/Button/Primary-chromium.png`;
|
|
26
|
+
`{dir}/__baselines__/{file}/{name}-{engine}` with `root: "."` writes
|
|
27
|
+
`src/ui/Button/__baselines__/Button.stories.tsx/Primary-chromium.png` beside the
|
|
28
|
+
code. A label is spelled `Primary__dark-chromium.png`.
|
|
29
|
+
|
|
30
|
+
The machine that painted a baseline is read from the record beside it. One file
|
|
31
|
+
holds each subject per engine family, the last accept writes it, and a run on
|
|
32
|
+
another platform, scale factor or engine version compares against it, reading
|
|
33
|
+
unchanged or changed as the pixels say, with the moved field named as the cause.
|
|
34
|
+
A laptop and CI that take turns accepting rewrite the record each time; set
|
|
35
|
+
`baselines.records` to keep the records out of version control. The tribunal's
|
|
36
|
+
bucket store answers the same way: a lookup reads the last accept on the
|
|
37
|
+
engine family, where it used to prefer this machine's own row.
|
|
38
|
+
|
|
39
|
+
Two subjects that render one path, compared case-folded, stop the run with an
|
|
40
|
+
error naming both subjects and the template. Nothing is renumbered. The record
|
|
41
|
+
names the subject it was accepted for, so a shard, a Playwright worker or a
|
|
42
|
+
later run that renders the same path for another subject stops too. Two
|
|
43
|
+
Playwright projects that differ only in scale factor, colour scheme or viewport
|
|
44
|
+
render one path; the error names both projects and `{project}`. A record left by
|
|
45
|
+
a project the config no longer runs is a renamed project's, and the first run
|
|
46
|
+
under the new name takes it over.
|
|
47
|
+
|
|
48
|
+
The Vitest plugin reads a test's `describe` path from the runner, so a title
|
|
49
|
+
that contains ` > ` stays one directory under `{title}`.
|
|
50
|
+
|
|
51
|
+
**Breaking:** `baselines.layout` is removed, and a config that sets it is
|
|
52
|
+
refused with an error naming `path`. Baselines under the identity directories
|
|
53
|
+
are still read: the subject is compared against them, unchanged or changed as
|
|
54
|
+
the pixels say, with the move from the old path to the new one given as a cause,
|
|
55
|
+
and the next accept writes the template's path and deletes the old pair, so the
|
|
56
|
+
pull request shows a rename. An accept deletes only a pair this machine's
|
|
57
|
+
identity or engine line painted; another machine's stays until that machine
|
|
58
|
+
accepts. `BaselineKey` carries `file`, `title`, `name` and
|
|
59
|
+
`project` in place of `path`; the Playwright fixture, the Vitest plugin and
|
|
60
|
+
Storybook's index supply them, and `varianceBaselinePath` and `baselinePath`
|
|
61
|
+
set the template for a suite run without the CLI.
|
|
62
|
+
|
|
63
|
+
The git-LFS store's `.gitattributes` pattern and the action's commit-back
|
|
64
|
+
pathspecs are the template's glob, so a collocated baseline is tracked and
|
|
65
|
+
committed where it is written. An `lfs` config whose root is `.` and whose
|
|
66
|
+
template has no directory of its own is refused, because its glob would track
|
|
67
|
+
every hyphenated image in the repository; give the template a directory such
|
|
68
|
+
as `__baselines__`, give the baselines a root of their own, or set
|
|
69
|
+
`baselines.pattern`. A `directory` config at root `.` with such a template is
|
|
70
|
+
refused for the same reason: the action would commit every hyphenated image
|
|
71
|
+
back. An existing LFS root gets the template's pattern as a new
|
|
72
|
+
`.gitattributes` line the next time a run opens it; commit it with the baselines.
|
|
73
|
+
- 09f60c8: A reach walks type-only imports unless you name the runtime edges
|
|
74
|
+
|
|
75
|
+
`dependentsOf`, `dependenciesOf`, `affectedBy` and `carried` in
|
|
76
|
+
`@variance-authority/core/relate` now walk every edge kind, `type` included,
|
|
77
|
+
when you pass no `through`. A type-only import is still a dependency: a changed
|
|
78
|
+
type can break the file that imports it, and the walk said nothing about that
|
|
79
|
+
file. Test selection asks what a run loads, so every selection walk in Sense and
|
|
80
|
+
the CLI passes `RUNTIME_EDGES`, and what it selects does not change.
|
|
81
|
+
|
|
82
|
+
If you called one of these and relied on `type` edges being left out, pass
|
|
83
|
+
`{ through: RUNTIME_EDGES }`.
|
|
84
|
+
- 0b6af81: A changed region is joined against the baseline's nodes as well as this render's
|
|
85
|
+
|
|
86
|
+
A change that replaces an element paints over the old element's box and the new
|
|
87
|
+
one's, and `attributeRegions` read only one snapshot. On todomvc's broken toggle,
|
|
88
|
+
71% of the changed region is inside the checkbox that left and 88.75% inside the
|
|
89
|
+
div that arrived. Neither reaches the 0.9 containment, so the region named the
|
|
90
|
+
row around both.
|
|
91
|
+
|
|
92
|
+
`AttributionOptions.before` is now required: the snapshot of the revision the
|
|
93
|
+
pixels are compared against, or `undefined`. Each node is joined against the
|
|
94
|
+
area its own box and the box of the node the differ's matcher pairs it with in
|
|
95
|
+
`before` cover together: the two places, not the rectangle that holds both.
|
|
96
|
+
A box that left is placed by where it was in its own image, whose corner is the
|
|
97
|
+
new `AttributionOptions.beforeOrigin`: by default the before snapshot's root, so
|
|
98
|
+
a subject the page moved between two clipped shots joins where its pixels are.
|
|
99
|
+
A call that states `origin` with a `before` snapshot and no `beforeOrigin`
|
|
100
|
+
throws, since a corner guessed from the other image is right only when the page
|
|
101
|
+
did not move.
|
|
102
|
+
|
|
103
|
+
A baseline keeps that snapshot. `Raster.snapshot` is a `PackedSnapshot`, the
|
|
104
|
+
tree gzipped and in base64, written by the Playwright fixture, its promotion,
|
|
105
|
+
the Vitest browser provider and the CLI's image sidecars. `packSnapshot` and
|
|
106
|
+
`unpackSnapshot` are exported from `@variance-authority/observe`. Every store
|
|
107
|
+
carries it as text: `sidecarFrom` keeps it, `variance push` forwards it, and
|
|
108
|
+
tribunal stores it in new `baselines.snapshot` and
|
|
109
|
+
`build_subjects.candidate_snapshot` columns (schema 21, migration
|
|
110
|
+
`0019_baseline-snapshot.sql`) and promotes it on approval. On
|
|
111
|
+
`cases/storybook-case` it adds 3.2–5.4 KB to each sidecar.
|
|
112
|
+
|
|
113
|
+
A baseline without a snapshot says so. When a changed verdict has regions and
|
|
114
|
+
its baseline kept no snapshot, or one that will not unpack, the reason ends
|
|
115
|
+
*the baseline records no snapshot of its nodes, so regions were joined against
|
|
116
|
+
this render's boxes alone: an accepting run records one on a revision where
|
|
117
|
+
this subject is unchanged*. An accepting run — `--update-snapshots`, Vitest's
|
|
118
|
+
`--update`, `variance accept` — now re-stamps an unchanged baseline that kept no
|
|
119
|
+
snapshot, as it re-stamps one painted under another identity, and the
|
|
120
|
+
observation marks it `signals.snapshot: 'unrecorded'`; `restamps` in
|
|
121
|
+
`@variance-authority/core/judge` is the one rule all three ask. Every other
|
|
122
|
+
verdict the mark is on ends *the baseline records no snapshot of its nodes, and
|
|
123
|
+
an accepting run records this one*. Two images
|
|
124
|
+
compared directly get the same clause, naming the before image, without the
|
|
125
|
+
remedy, and are never marked.
|
|
126
|
+
|
|
127
|
+
A subject whose document has not moved settles on its digest and builds no
|
|
128
|
+
observation to mark, so `settle` now renders a pictured baseline that kept no
|
|
129
|
+
snapshot when this run collected one, with the reason *the baseline records no
|
|
130
|
+
snapshot of its nodes, so this run renders it for an accepting run to record
|
|
131
|
+
one*. A suite of baselines accepted before this release renders them on every
|
|
132
|
+
run until an accepting run re-stamps them. Tribunal records one on ingest
|
|
133
|
+
instead: a pushed candidate's snapshot is written onto a baseline that has an
|
|
134
|
+
image and kept none, when it was painted from the same document under the same
|
|
135
|
+
identity, and never over one it kept, so such a subject renders once. The
|
|
136
|
+
snapshot's runtime fields (`provenance` and its `createdBy`, `wiring`, `holding`,
|
|
137
|
+
`styleProvenance`, `styleTokens`, `ignoredBy`) are then the recording run's: the
|
|
138
|
+
first push, from a build on any branch, that drew that document, as they are the
|
|
139
|
+
accepting run's on a re-stamp. `Described.keepsSnapshot`
|
|
140
|
+
is the new required field it reads:
|
|
141
|
+
the durable, LFS and tribunal stores derive it from the sidecar with
|
|
142
|
+
`keepsSnapshot` from `@variance-authority/core/format`, and the remote store
|
|
143
|
+
refuses a description without it. A packed snapshot now opens with a `v1:`
|
|
144
|
+
header naming its format version, `PACKED_SNAPSHOT_HEADER`, and a snapshot
|
|
145
|
+
without it counts as not kept. `unpackSnapshot` reads one as not recorded
|
|
146
|
+
unless every node in it is one, with `isSemanticSnapshot`, new in
|
|
147
|
+
`@variance-authority/core/format` beside `isRenderDocument` and
|
|
148
|
+
`isSubjectRef`: the checks `@variance-authority/unit-test` already made of a
|
|
149
|
+
capture file's snapshot, document and subject, which it now asks. Tribunal serves API 6, which describes a
|
|
150
|
+
baseline with `keepsSnapshot`; `variance push` against an older deployment names
|
|
151
|
+
the refused descriptions when the project's `remote` baselines are stored there,
|
|
152
|
+
and the remote store's refusal names tribunal before API 6 and a
|
|
153
|
+
`serveRasterStore` from an earlier `@variance-authority/remote`: upgrade the
|
|
154
|
+
server, tribunal or your own, before the client. `settle` takes this run's snapshot as a
|
|
155
|
+
fifth argument. `variance accept` and the MCP changelog call these subjects
|
|
156
|
+
*unchanged and re-stamped* rather than re-stamped under this run's identity,
|
|
157
|
+
which was untrue of them. The render cache no longer hands on a snapshot an
|
|
158
|
+
entry kept.
|
|
159
|
+
- 18c70d3: A run collects in parallel by default, and the report says where each subject's time went
|
|
160
|
+
|
|
161
|
+
Without `workers` in the config, a run collected in one browser world, so a
|
|
162
|
+
route suite read its pages one after another on any machine. It now collects in
|
|
163
|
+
half the machine's logical cores, at least one and never more worlds than there
|
|
164
|
+
are files: two on a 4-vCPU CI runner, eight on a 16-core laptop. A `concurrency`
|
|
165
|
+
you set holds it lower, since every world keeps a page and a subject in flight.
|
|
166
|
+
A `workers` you set still wins over both. Set `workers: 1` for a server under
|
|
167
|
+
test that cannot take concurrent pages. A collector with no `openWorker` still
|
|
168
|
+
collects in one world, and the run warns about it only when you set `workers`. Verdicts and the order
|
|
169
|
+
of observations do not depend on the count, and the report's new `workers` field
|
|
170
|
+
records it. `variance collect` takes the same width.
|
|
171
|
+
|
|
172
|
+
A changed subject read in a second world is now run alone like one read in the
|
|
173
|
+
first. A worker opens no clean world of its own, so the run asked the worker and
|
|
174
|
+
reported "not re-run alone: collector has no `collectAlone`"; it now asks the
|
|
175
|
+
collector that can open one.
|
|
176
|
+
|
|
177
|
+
The `alone.limit` budget now goes to the first subjects to change in the order
|
|
178
|
+
the run takes them. It went to whichever changed subjects reached it first, so
|
|
179
|
+
with more changed subjects than the limit, which ones carried `again` and
|
|
180
|
+
`alone` evidence depended on the number of worlds and on timing.
|
|
181
|
+
|
|
182
|
+
Each observation in the report also carries `steps` beside `costMs`: every
|
|
183
|
+
phase the subject went through, in the order it ran, with its wall time. The
|
|
184
|
+
collector's phases are named `collect.*` (`collect.navigate`,
|
|
185
|
+
`collect.wait-for-fonts`, `collect.capture`), the run's own are `compose`,
|
|
186
|
+
`inspect`, `settle`, `baseline`, `cache.get`, `cache.put`, `decode`, `compare`,
|
|
187
|
+
`write`, `again.collect` and `alone.collect`, and a painted subject adds the
|
|
188
|
+
renderer's under `render.*`. The report's `steps` sums each phase over the
|
|
189
|
+
subjects that ran it and counts them. A phase a subject skipped is absent, not
|
|
190
|
+
zero. Timings are part of no digest, so images, records and baselines do not
|
|
191
|
+
move when only timing does.
|
|
192
|
+
|
|
193
|
+
`settleRecipe`, `stabilizeForObservation`, `compareRasters` and the raster
|
|
194
|
+
`Renderer.render` take an optional step clock and report the steps they ran on
|
|
195
|
+
it. The route page agent and `readRoute` always return the steps they took.
|
|
196
|
+
`stepClock`, `timeOn` and `totalsOf` are exported from
|
|
197
|
+
`@variance-authority/core/format`.
|
|
198
|
+
|
|
199
|
+
A run that is not sharded now reads the mainline's subject costs at every
|
|
200
|
+
width, as a sharded run always did, and takes its slowest files first. One
|
|
201
|
+
world takes its subjects in the same order as several, so the budget above
|
|
202
|
+
reaches the same subjects.
|
|
203
|
+
|
|
204
|
+
`concurrency` is split evenly across the worlds and rounded up, at least one
|
|
205
|
+
per world, so by default the raster tier is as wide as the number of worlds.
|
|
206
|
+
|
|
207
|
+
The frame above a subject carries its classes in code-unit order. Storybook
|
|
208
|
+
swaps its layout class on a page it reuses, so their order said which story the
|
|
209
|
+
page showed before, and a run in parallel lanes gave the same story a different
|
|
210
|
+
document, and a render-cache miss, with the same pixels.
|
|
211
|
+
- 9b95dc1: A shard takes whole files in every runner, and is balanced by file count without times
|
|
212
|
+
|
|
213
|
+
Under `--shard k/n`, a Playwright config wrapped by `withTestSelection` now
|
|
214
|
+
places each spec file whole in one shard, by the time it took on the last
|
|
215
|
+
recorded run, as Vitest and Jest shards are placed. Playwright's own split,
|
|
216
|
+
which under `fullyParallel` divides a file's tests between shards, does not run.
|
|
217
|
+
The reporter places the shard in `preprocess`, after `--project`, `--grep` and
|
|
218
|
+
`.only`, and prints one line on stderr:
|
|
219
|
+
`variance-authority: shard 1/2 by file count: 2 of 3 files; no times at …`.
|
|
220
|
+
A file several projects run, or `repeatEach` repeats, goes with all its copies
|
|
221
|
+
to one shard; setup and teardown projects are not placed, and a project with no
|
|
222
|
+
file in the shard is left out whole. Playwright runs a setup project in every
|
|
223
|
+
shard that needs it, so combining the shards' records refuses its files as run
|
|
224
|
+
by two shards. `PWTEST_SHARD_WEIGHTS` is ignored for placement, though
|
|
225
|
+
Playwright still validates it.
|
|
226
|
+
|
|
227
|
+
This needs Playwright 1.62 or newer. `withTestSelection` refuses a run that asks
|
|
228
|
+
for a shard, by `--shard` or by `shard` in the configuration, when the
|
|
229
|
+
configuration is evaluated, before any test starts: on an older Playwright with
|
|
230
|
+
`variance-authority: refusing shard k/n: Playwright <version> would split it
|
|
231
|
+
test by test, …; placing whole files needs Playwright 1.62 or newer`, and when
|
|
232
|
+
a `--reporter` on the command line replaces the configuration's reporters
|
|
233
|
+
without naming `@variance-authority/playwright-test/reporter`, by that
|
|
234
|
+
specifier or by a path that resolves to it. The version is the one the
|
|
235
|
+
configuration's directory resolves, from `-c`/`--config` or the working
|
|
236
|
+
directory. A configuration that names the reporter without `withTestSelection`
|
|
237
|
+
is not refused. A run with no shard runs as before.
|
|
238
|
+
|
|
239
|
+
When the record has no times, or none for the files collected, a Vitest, Jest
|
|
240
|
+
or Playwright shard prices every file the same and places them by the same
|
|
241
|
+
rule, so the shards are balanced by file count and none is left empty while
|
|
242
|
+
there are as many files as shards. The line reads
|
|
243
|
+
`shard k/n by file count: <m> of <n> files; <why>`, in place of
|
|
244
|
+
`split by the runner, by count: <why>`. A file the runner hands in more than
|
|
245
|
+
once, for each project that runs it, is placed once at its recorded time, which
|
|
246
|
+
already sums every project, with every copy in one shard.
|
|
247
|
+
|
|
248
|
+
`place` in `@variance-authority/core/shard` is where that rule lives: with
|
|
249
|
+
nothing recorded, every group weighs one and is placed longest first on the
|
|
250
|
+
least-loaded shard like a timed one, ties broken by key in code-unit order and
|
|
251
|
+
then by the lowest shard. Its `by` reads `count` rather than `checksum`, and
|
|
252
|
+
its `cost` and `load` are always present, one per group when placed by count.
|
|
253
|
+
`variance run --shard` and `variance collect --shard` place stories and routes
|
|
254
|
+
by the same rule, and a subject another shard owns reads
|
|
255
|
+
`assigned to shard k/n by count, …`.
|
|
256
|
+
|
|
257
|
+
A Jest or Vitest configuration wrapped by `withTestSelection` and evaluated
|
|
258
|
+
under `--shard` gets `passWithNoTests: true` unless it sets `passWithNoTests`
|
|
259
|
+
itself, so a shard left no file, because there are fewer files than shards,
|
|
260
|
+
passes as it does under Playwright. Vitest 4 refused such a run before any file
|
|
261
|
+
was placed. An unsharded run that finds no file still fails.
|
|
262
|
+
|
|
263
|
+
`shardOf(files, shard, times)`, `landingTimes(record, options)` and
|
|
264
|
+
`shardArgument(argv)`, which reads the `--shard k/n` a command line asks for, are exported
|
|
265
|
+
from `@variance-authority/sense/test-selection`, for a seam that places a shard
|
|
266
|
+
by the same rule.
|
|
267
|
+
|
|
268
|
+
A Vitest, Jest or Playwright shard that cannot read the record its times come
|
|
269
|
+
from now fails before any test runs, with
|
|
270
|
+
`variance-authority: the times this shard is placed by could not be read, …`
|
|
271
|
+
and the reason: a share that did not answer or answered with what does not
|
|
272
|
+
read, a record that is there and does not decode, or a CLI that throws as it
|
|
273
|
+
loads. It used to place by file count, beside shards that may have read the
|
|
274
|
+
times. A record that is not there, a share that holds none or is not
|
|
275
|
+
configured, and a CLI that is not installed still place by count. An unsharded
|
|
276
|
+
run reads no times and runs as before. `variance shards` fails the same way.
|
|
277
|
+
|
|
278
|
+
**Breaking:**
|
|
279
|
+
|
|
280
|
+
- A Vitest or Jest shard with no times is placed by file count, in code-unit
|
|
281
|
+
order of path, not by your sequencer's `shard`. Your sequencer still sorts
|
|
282
|
+
each shard.
|
|
283
|
+
- A Playwright run below 1.62 that asks for a shard is refused. Upgrade
|
|
284
|
+
Playwright, or run without `--shard`.
|
|
285
|
+
- A sharded Playwright run whose `--reporter` leaves out
|
|
286
|
+
`@variance-authority/playwright-test/reporter` is refused. Name it in
|
|
287
|
+
`--reporter` too.
|
|
288
|
+
- `variance run --shard` and `variance collect --shard` with no recorded costs
|
|
289
|
+
place each file by count, not by a checksum of the file and the shard. The
|
|
290
|
+
shards are balanced, but adding a file can move others to another shard.
|
|
291
|
+
A collection part's `assignment`, and the `assignment` in the provenance of
|
|
292
|
+
the suite index merged from it, read `count` where they read `checksum`. An
|
|
293
|
+
index that reads `checksum` still opens. `variance collect merge` refuses
|
|
294
|
+
sharded parts an earlier version cut by checksum; collect every shard again.
|
|
295
|
+
- A sharded run whose share does not answer fails rather than placing by
|
|
296
|
+
file count. Run the job again, or hand every shard the record fetched once.
|
|
297
|
+
- 402ce9f: A story's parameters are read when the story is reached, so no story file is imported before its story comes up
|
|
298
|
+
|
|
299
|
+
Your Storybook run used to read every story's `parameters.variance` before the
|
|
300
|
+
first story, through the preview's `extract()`. That imported every story file
|
|
301
|
+
up front: on a large Storybook you paid for the whole build before seeing one
|
|
302
|
+
story, and each file's first story then timed its import as 0 in `collect`.
|
|
303
|
+
|
|
304
|
+
The run now plans from `index.json` alone. When it reaches a story, it asks the
|
|
305
|
+
preview for that story's merged parameters, which imports only that story's
|
|
306
|
+
file, the import showing the story would have made anyway. That import is
|
|
307
|
+
charged to the story's `collect`, so the first story of each file carries what
|
|
308
|
+
its file costs. A story that excludes itself is still skipped and listed in the
|
|
309
|
+
report with its reason, and a story whose parameters cannot be read is read at
|
|
310
|
+
your run's `viewport` with a warning naming it. A preview too old to read one
|
|
311
|
+
story's parameters says so once per run, not once per story.
|
|
312
|
+
|
|
313
|
+
A story that declares `widths` is still read as `<story id>@<width>` at each
|
|
314
|
+
width, with its own baseline, and all its widths are read on the same page in
|
|
315
|
+
one visit: nothing is opened, booted or loaded again for a second width. A
|
|
316
|
+
run that does not read such a story, because `--subjects`, `--since` or a shard
|
|
317
|
+
left it out, because its visit failed, or because its parameters could not be read, still counts its width baselines as
|
|
318
|
+
planned rather than naming them as baselines your plan no longer holds. A
|
|
319
|
+
story that excludes itself when it is reached holds no subject of the run, so
|
|
320
|
+
every baseline it left, under its own id and at each width, is named. A
|
|
321
|
+
shard prices the story at the sum of the widths its last visit read.
|
|
322
|
+
|
|
323
|
+
If you write a collector, `collect` may now return a `Visit` instead of a
|
|
324
|
+
`Collected`: every subject the visit to the planned one produced, each with its own
|
|
325
|
+
result, each id the planned id or the planned id at a width (`<id>@<width>`),
|
|
326
|
+
and any warnings the visit raised. A visit that could not learn every subject
|
|
327
|
+
it realizes, such as a story read without its parameters, says `incomplete: true`.
|
|
328
|
+
A visit that produced no subject is
|
|
329
|
+
reported as a failed one, and so is a visit that produced any other id. The run and `variance collect` report each subject
|
|
330
|
+
at the position the plan gave the planned subject, and evidence parts record
|
|
331
|
+
the planned id as `of`; a merge refuses a part whose subject is neither. A
|
|
332
|
+
`--subjects` glob that names one width, such as `*@375`, now reaches the story
|
|
333
|
+
it comes from, and only a width suffix extends a story id: `button--primary`
|
|
334
|
+
no longer reaches `button--primary-large`.
|
|
335
|
+
|
|
336
|
+
`@variance-authority/core/format` exports `atWidth`, which writes a subject's
|
|
337
|
+
id and name at a width, and `widenedFrom`, which reads the planned id back
|
|
338
|
+
from a width id, and `realizes`, which says whether a visit to one id may
|
|
339
|
+
produce another.
|
|
340
|
+
|
|
341
|
+
`readParameters(page)` is now `readParameters(page, storyId)` and returns one
|
|
342
|
+
story's parameters; the up-front read of every story is gone.
|
|
343
|
+
- f18c00c: The differ pairs the one element its author replaced, and says what it became
|
|
344
|
+
|
|
345
|
+
When, under one matched parent, exactly one element left and exactly one
|
|
346
|
+
arrived, and the same component's `createdBy` wrote both, `matchTrees` pairs
|
|
347
|
+
them. The pair is compared like any other and leads with a new `tag-changed`
|
|
348
|
+
delta, in the geometry band and counted as structural, followed by whatever else
|
|
349
|
+
differs: role, name, state, attributes, styles and box. Before, the same change
|
|
350
|
+
was a `node-removed` and a `node-added`. Two or more replaced by one author under
|
|
351
|
+
one parent stay unpaired, because either could be either, and so do two that
|
|
352
|
+
each carry an alias or a role and name of their own: every `<Button>` is created
|
|
353
|
+
by `Button`, and a Save button replaced by an Export link is two elements.
|
|
354
|
+
|
|
355
|
+
`tag-changed` is reported on every pair across two tags, so a pair that a
|
|
356
|
+
declared alias or a shared role and name joined — a `<button>` and a
|
|
357
|
+
`<div role="button">` with one name — now says its tag changed, where before it
|
|
358
|
+
reported nothing for it.
|
|
359
|
+
|
|
360
|
+
A `style-changed` or `token-changed` delta on a pair across two tags is banded
|
|
361
|
+
`geometry`, with the `tag-changed` it follows, rather than `token`: the style is
|
|
362
|
+
the new element's, and the structure a `token` delta says held did not. A
|
|
363
|
+
`bands: ['token']` ignore rule no longer reads it. `bandOf` owns the rule, as
|
|
364
|
+
`bandOf(kind, { retagged })`, and a parting row's bands now read each delta's
|
|
365
|
+
own band, so the row and the docket agree.
|
|
366
|
+
- 4aa7b16: Content inserted into a page is the inserted rows, not everything under them
|
|
367
|
+
|
|
368
|
+
Two images of the same width are compared row by row after their rows are
|
|
369
|
+
aligned: each row is hashed, runs of equal rows are one token, and Myers finds
|
|
370
|
+
the shortest edit between the two sequences. Each after row is then compared
|
|
371
|
+
with the before row that shows the same content, and `pixelmatch` still judges
|
|
372
|
+
every pairing; a row that moved, came or went is a change in itself, so no
|
|
373
|
+
pairing makes a page read as unchanged. A section added to a long page marks that
|
|
374
|
+
section, and the content it pushed down matches. A pairing is kept only when it
|
|
375
|
+
leaves fewer pixels differing than position does, a row it leaves unpaired
|
|
376
|
+
charged in full, so a line that changed in place is not shifted against its
|
|
377
|
+
neighbours. The rows a gap grew by are inserted, as the rows it lost are
|
|
378
|
+
removed, so a button whose padding grew has a region where it grew. Images of
|
|
379
|
+
different widths, or an edit longer than 2,000 runs of rows, are compared
|
|
380
|
+
position by position on the union box, as before.
|
|
381
|
+
|
|
382
|
+
An inserted row is marked edge to edge, since nothing says where its content
|
|
383
|
+
begins, so a region inside one is joined by its rows rather than its area: to
|
|
384
|
+
the tightest box whose rows span it. `attributeRegions` takes the inserted rows
|
|
385
|
+
as `inserted`. Joined by area, every such band went to the subject's root, and
|
|
386
|
+
a card whose button grew named the card rather than the button.
|
|
387
|
+
|
|
388
|
+
`RasterComparison.alignment` carries the pairing as `RowAlignment`: the after
|
|
389
|
+
rows `inserted`, the before rows `removed` with the after row they left from,
|
|
390
|
+
and the rows `shifted` with how far. A comparison without it was not aligned.
|
|
391
|
+
|
|
392
|
+
Content that moved is a change. A gap that grew in one place and shrank in
|
|
393
|
+
another moves what lies between them and leaves the page as tall as it was, and
|
|
394
|
+
every moved row matches the row it came from; such a subject reports `changed`,
|
|
395
|
+
never `unchanged` or `ignored`. The reason names the edit:
|
|
396
|
+
*120 pixels differ across 1 region; 3 pixel rows inserted in 1 place, moving
|
|
397
|
+
the content under them by up to 3 rows, and the subject resized from 40×5 to
|
|
398
|
+
40×8*. The Playwright fixture's evidence now writes a diff for a subject that
|
|
399
|
+
resized, drawn on the after image.
|
|
400
|
+
- 16e7c76: `dominatorsOf` is removed from `@variance-authority/core/relate`
|
|
401
|
+
|
|
402
|
+
Nothing ran it once distill read its records in the sense addon, which finds
|
|
403
|
+
the import every path from a test file runs through with its own dominator
|
|
404
|
+
pass. A caller that needs immediate dominators of a file graph computes them
|
|
405
|
+
over `Relations` directly.
|
|
406
|
+
|
|
407
|
+
### Patch Changes
|
|
408
|
+
|
|
409
|
+
- 8d1bcc1: A link in a doc comment opens from `node_modules`
|
|
410
|
+
|
|
411
|
+
Doc comments linked to documentation by repository paths such as
|
|
412
|
+
`../../../../docs/flakiness.md`, which resolve to nothing in an installed
|
|
413
|
+
package. They now link to the page on variance-authority.dev, or to the file on
|
|
414
|
+
GitHub when the site does not publish it, so the link works on hover in your
|
|
415
|
+
editor and in what `variance ask symbol` prints.
|
|
416
|
+
|
|
417
|
+
The MCP server's instructions and its observability answer linked to
|
|
418
|
+
`/start-cli` and `/presentation`, which the site does not serve. They now link
|
|
419
|
+
to `/start/cli` and `/docs/presentation`, and the `@variance-authority/cli`,
|
|
420
|
+
`@variance-authority/help`, `@variance-authority/mcp` and
|
|
421
|
+
`@variance-authority/vitest-browser` READMEs link to the guides where the site
|
|
422
|
+
publishes them.
|
|
423
|
+
|
|
424
|
+
`variancePrecondition`, `wiringOf`, `tapCommits` and `provenanceOf` carry an
|
|
425
|
+
`@see` link to the section of the guide that documents them.
|
|
426
|
+
|
|
3
427
|
## 0.15.0
|
|
4
428
|
|
|
5
429
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
> The Variance Authority format, rules, comparison, attribution and verdicts. Pure data in, pure data out, no DOM and no I/O.
|
|
6
6
|
|
|
7
7
|
Part of [Variance Authority](https://variance-authority.dev).
|
|
8
|
+
Point your coding agent at [`llms.txt`](https://variance-authority.dev/llms.txt).
|
|
8
9
|
|
|
9
10
|
## What this is for
|
|
10
11
|
|
|
@@ -187,13 +188,13 @@ are five, loudest first:
|
|
|
187
188
|
| band | what changed | example delta kinds |
|
|
188
189
|
|---|---|---|
|
|
189
190
|
| `a11y` | a role, accessible name, description or ARIA state | `role-changed`, `name-changed`, `state-changed` |
|
|
190
|
-
| `geometry` | boxes appeared, vanished, moved or
|
|
191
|
-
| `token` | style values changed while structure stayed the same | `style-changed`, `token-changed` |
|
|
191
|
+
| `geometry` | boxes appeared, vanished, moved, resized or were replaced | `node-added`, `node-moved`, `tag-changed`, `rect-changed`, `attribute-changed` |
|
|
192
|
+
| `token` | style values changed while structure stayed the same | `style-changed`, `token-changed`, except on a pair across two tags, where they are `geometry` |
|
|
192
193
|
| `content` | text changed and nothing else did | `text-changed` |
|
|
193
194
|
| `texture` | sub-semantic rendering variance | `raster-residue` |
|
|
194
195
|
|
|
195
|
-
`bandOf(kind)` performs that assignment and is the default
|
|
196
|
-
answer — policy may promote or demote per project, subject, region or
|
|
196
|
+
`bandOf(kind, { retagged })` performs that assignment and is the default
|
|
197
|
+
rather than the answer — policy may promote or demote per project, subject, region or
|
|
197
198
|
component. `loudestBand(bands)` collapses a set to the loudest one present, and
|
|
198
199
|
returns `null` for an empty set so that *nothing changed* and *something changed
|
|
199
200
|
at the quietest band* stay apart.
|
|
@@ -231,7 +232,10 @@ const after = normalize(recapture);
|
|
|
231
232
|
const diff = diffSnapshots(before, after); // deltas and roots, no verdict
|
|
232
233
|
|
|
233
234
|
const places = isolateRegions(mask, { cell: 8 }); // pixels → regions
|
|
234
|
-
const named = attributeRegions(places.regions, after, {
|
|
235
|
+
const named = attributeRegions(places.regions, after, {
|
|
236
|
+
scale: 2,
|
|
237
|
+
before, // where the pixels it replaced were
|
|
238
|
+
});
|
|
235
239
|
```
|
|
236
240
|
|
|
237
241
|
`diffSnapshots` returns `identical`, the flat `deltas`, the `roots` a docket
|
|
@@ -245,6 +249,20 @@ runner.
|
|
|
245
249
|
screenshot at 1x and every region lands in the top-left quadrant with the wrong
|
|
246
250
|
component named — a full, plausible, entirely wrong report.
|
|
247
251
|
|
|
252
|
+
`before` is required too: the snapshot of the revision the pixels are compared
|
|
253
|
+
against, or `undefined` when nobody kept it. A change that replaces an element
|
|
254
|
+
paints over the old box and the new one, so each node is joined against its own
|
|
255
|
+
box and the box of the node the differ's matcher pairs it with. A stored baseline
|
|
256
|
+
carries that snapshot packed, as its `snapshot`; `unpackSnapshot` in
|
|
257
|
+
`@variance-authority/observe` reads it back.
|
|
258
|
+
|
|
259
|
+
Each box that left is placed by where it was in its own image. A screenshot
|
|
260
|
+
clipped to the subject starts at the subject's root, and `beforeOrigin` is the
|
|
261
|
+
before image's top-left corner in page CSS pixels. It defaults to the before
|
|
262
|
+
snapshot's root, as `origin` defaults to this render's. When you pass `origin`
|
|
263
|
+
and a `before` snapshot, pass `beforeOrigin` too, or the call throws: the page
|
|
264
|
+
can move what you clipped to between the two shots.
|
|
265
|
+
|
|
248
266
|
Rendered comparisons throw when the two subjects differ, or when their
|
|
249
267
|
observation profiles differ.
|
|
250
268
|
|
|
@@ -253,7 +271,7 @@ observation profiles differ.
|
|
|
253
271
|
| call | useful controls |
|
|
254
272
|
|---|---|
|
|
255
273
|
| `normalize` | `collapseWrappers` removes layout-only wrapper boundaries, `digestText` includes text content, and `sourceRoot` relativizes source locations |
|
|
256
|
-
| `isolateRegions` / `attributeRegions` | `cell` and `limit` bound mask work; `origin` and `containment` describe the coordinate origin and how much a node must contain a region |
|
|
274
|
+
| `isolateRegions` / `attributeRegions` | `cell` and `limit` bound mask work; `origin` and `containment` describe the coordinate origin and how much a node must contain a region; `inserted` names the rows the after image added, and a region inside them goes to the tightest box whose rows span it |
|
|
257
275
|
| `fingerprintOfMask` | `grid` controls the shape sample and `coverage` the minimum occupied share |
|
|
258
276
|
| `compareLocales` / ignore validation | `slack` permits a declared locale distance; `sites` supplies resolved ignore locations and `now` evaluates expiry |
|
|
259
277
|
| `buildDocket` / dependency reach | `sampleSize` limits review examples; `through` selects graph edge kinds, `avoid` names nodes a walk never covers, and `shadows` lists per file the modules its run never loads, so `affectedBy` leaves out a file every trail to which crosses one of its own shadows; `depends` adds the install — which package rests on which — so a dependency bump is a seed like any other and affects only the files that import it; `uses` names what each import binds and each re-export republishes, and `moved` lists per seed the exports its change changed, so `affectedBy` covers only the files that import one of them |
|
|
@@ -364,4 +382,4 @@ the comparison is refused rather than reported as a difference in the product.
|
|
|
364
382
|
|
|
365
383
|
---
|
|
366
384
|
|
|
367
|
-
**[@variance-authority/core](https://variance-authority.dev/reference/packages/core)** is part of [Variance Authority](https://variance-authority.dev) — [documentation](https://variance-authority.dev/docs) · MIT
|
|
385
|
+
**[@variance-authority/core](https://variance-authority.dev/reference/packages/core)** is part of [Variance Authority](https://variance-authority.dev) — [documentation](https://variance-authority.dev/docs) · [GitHub](https://github.com/Variance-Authority/variance-authority/tree/main/packages/core) · MIT
|
|
@@ -49,7 +49,7 @@ export declare function hashComponents(snapshot: SemanticSnapshot): readonly Com
|
|
|
49
49
|
* The arithmetic behind cause-first ranking, and the reason a baseline carries
|
|
50
50
|
* its component hashes at all. `rankRegions` takes a list of cause names and,
|
|
51
51
|
* given none, falls back to area — which
|
|
52
|
-
* [journal 0013](
|
|
52
|
+
* [journal 0013](https://github.com/Variance-Authority/variance-authority/blob/main/docs/context/journal/0013-observability.md)
|
|
53
53
|
* measured as backwards by 6×, because area measures displacement rather than
|
|
54
54
|
* cause. This is where that list comes from on a path with no second document.
|
|
55
55
|
*
|
|
@@ -81,12 +81,20 @@ export declare function causesBetween(before: readonly ComponentHash[], after: r
|
|
|
81
81
|
* and a boolean cannot serve a route-level test, whose entire request is *tell
|
|
82
82
|
* me when the page stops assembling and never when it is repainted*.
|
|
83
83
|
*
|
|
84
|
-
* The mapping is
|
|
85
|
-
* is the property that matters: a subject relaxed to `layout` must absorb the
|
|
84
|
+
* The mapping is the same one `bandOf` applies to a delta, but for the one case
|
|
85
|
+
* below, and that is the property that matters: a subject relaxed to `layout` must absorb the
|
|
86
86
|
* same things whether the run held two documents or two sidecars. Two mappings
|
|
87
87
|
* would be one drift away from a config key meaning different things on the two
|
|
88
88
|
* paths, discovered as a regression somebody let through.
|
|
89
89
|
*
|
|
90
|
+
* One delta the digests cannot band as `bandOf` does: the style of an element
|
|
91
|
+
* its author replaced, which `bandOf` bands `geometry` with the tag change. Two
|
|
92
|
+
* hashes do not say the tag changed under the style, so the `style` digest still
|
|
93
|
+
* reads `token` beside it. The `structure` digest moves with the tag, so both
|
|
94
|
+
* paths report `geometry`, and the one level that asserts `token`, `strict`,
|
|
95
|
+
* asserts `geometry` too: the verdict agrees. What differs is the list a
|
|
96
|
+
* relaxed reason gives as absorbed, which names `token` on this path only.
|
|
97
|
+
*
|
|
90
98
|
* | digest | band | what it covers |
|
|
91
99
|
* |---|---|---|
|
|
92
100
|
* | `semantics` | `a11y` | role, accessible name, ARIA state |
|
|
@@ -92,7 +92,7 @@ function byCodeUnit(a, b) {
|
|
|
92
92
|
* The arithmetic behind cause-first ranking, and the reason a baseline carries
|
|
93
93
|
* its component hashes at all. `rankRegions` takes a list of cause names and,
|
|
94
94
|
* given none, falls back to area — which
|
|
95
|
-
* [journal 0013](
|
|
95
|
+
* [journal 0013](https://github.com/Variance-Authority/variance-authority/blob/main/docs/context/journal/0013-observability.md)
|
|
96
96
|
* measured as backwards by 6×, because area measures displacement rather than
|
|
97
97
|
* cause. This is where that list comes from on a path with no second document.
|
|
98
98
|
*
|
|
@@ -176,12 +176,20 @@ function ownContentMoved(before, after) {
|
|
|
176
176
|
* and a boolean cannot serve a route-level test, whose entire request is *tell
|
|
177
177
|
* me when the page stops assembling and never when it is repainted*.
|
|
178
178
|
*
|
|
179
|
-
* The mapping is
|
|
180
|
-
* is the property that matters: a subject relaxed to `layout` must absorb the
|
|
179
|
+
* The mapping is the same one `bandOf` applies to a delta, but for the one case
|
|
180
|
+
* below, and that is the property that matters: a subject relaxed to `layout` must absorb the
|
|
181
181
|
* same things whether the run held two documents or two sidecars. Two mappings
|
|
182
182
|
* would be one drift away from a config key meaning different things on the two
|
|
183
183
|
* paths, discovered as a regression somebody let through.
|
|
184
184
|
*
|
|
185
|
+
* One delta the digests cannot band as `bandOf` does: the style of an element
|
|
186
|
+
* its author replaced, which `bandOf` bands `geometry` with the tag change. Two
|
|
187
|
+
* hashes do not say the tag changed under the style, so the `style` digest still
|
|
188
|
+
* reads `token` beside it. The `structure` digest moves with the tag, so both
|
|
189
|
+
* paths report `geometry`, and the one level that asserts `token`, `strict`,
|
|
190
|
+
* asserts `geometry` too: the verdict agrees. What differs is the list a
|
|
191
|
+
* relaxed reason gives as absorbed, which names `token` on this path only.
|
|
192
|
+
*
|
|
185
193
|
* | digest | band | what it covers |
|
|
186
194
|
* |---|---|---|
|
|
187
195
|
* | `semantics` | `a11y` | role, accessible name, ARIA state |
|