@variance-authority/core 0.14.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.
Files changed (147) hide show
  1. package/CHANGELOG.md +878 -0
  2. package/README.md +38 -17
  3. package/dist/attribute/component-hash.d.ts +14 -5
  4. package/dist/attribute/component-hash.js +14 -5
  5. package/dist/attribute/component-hash.js.map +1 -1
  6. package/dist/attribute/composition.d.ts +16 -0
  7. package/dist/attribute/composition.js +4 -6
  8. package/dist/attribute/composition.js.map +1 -1
  9. package/dist/attribute/index.d.ts +3 -1
  10. package/dist/attribute/index.js +2 -1
  11. package/dist/attribute/index.js.map +1 -1
  12. package/dist/attribute/movement.d.ts +1 -1
  13. package/dist/attribute/movement.js.map +1 -1
  14. package/dist/attribute/region.d.ts +47 -4
  15. package/dist/attribute/region.js +91 -22
  16. package/dist/attribute/region.js.map +1 -1
  17. package/dist/attribute/source.d.ts +10 -24
  18. package/dist/attribute/source.js +4 -38
  19. package/dist/attribute/source.js.map +1 -1
  20. package/dist/attribute/subject-pieces.d.ts +37 -0
  21. package/dist/attribute/subject-pieces.js +122 -0
  22. package/dist/attribute/subject-pieces.js.map +1 -0
  23. package/dist/compare/band.d.ts +8 -2
  24. package/dist/compare/band.js +7 -2
  25. package/dist/compare/band.js.map +1 -1
  26. package/dist/compare/diff/attribution.js +6 -4
  27. package/dist/compare/diff/attribution.js.map +1 -1
  28. package/dist/compare/diff/compare-nodes.js +9 -1
  29. package/dist/compare/diff/compare-nodes.js.map +1 -1
  30. package/dist/compare/diff/match.d.ts +2 -1
  31. package/dist/compare/diff/match.js +52 -0
  32. package/dist/compare/diff/match.js.map +1 -1
  33. package/dist/compare/parting.js +6 -4
  34. package/dist/compare/parting.js.map +1 -1
  35. package/dist/format/capture.d.ts +25 -0
  36. package/dist/format/capture.js +6 -0
  37. package/dist/format/capture.js.map +1 -1
  38. package/dist/format/document.d.ts +28 -5
  39. package/dist/format/document.js +8 -2
  40. package/dist/format/document.js.map +1 -1
  41. package/dist/format/drive.d.ts +191 -0
  42. package/dist/format/drive.js +343 -0
  43. package/dist/format/drive.js.map +1 -0
  44. package/dist/format/environment.d.ts +20 -2
  45. package/dist/format/environment.js +7 -0
  46. package/dist/format/environment.js.map +1 -1
  47. package/dist/format/index.d.ts +13 -3
  48. package/dist/format/index.js +8 -2
  49. package/dist/format/index.js.map +1 -1
  50. package/dist/format/intervention.d.ts +79 -0
  51. package/dist/format/intervention.js.map +1 -1
  52. package/dist/format/origin.d.ts +32 -0
  53. package/dist/format/origin.js +54 -0
  54. package/dist/format/origin.js.map +1 -0
  55. package/dist/format/packed.d.ts +32 -0
  56. package/dist/format/packed.js +23 -0
  57. package/dist/format/packed.js.map +1 -0
  58. package/dist/format/shape.d.ts +31 -0
  59. package/dist/format/shape.js +269 -0
  60. package/dist/format/shape.js.map +1 -0
  61. package/dist/format/snapshot.d.ts +2 -0
  62. package/dist/format/snapshot.js.map +1 -1
  63. package/dist/format/stabilize.d.ts +35 -6
  64. package/dist/format/stabilize.js +58 -103
  65. package/dist/format/stabilize.js.map +1 -1
  66. package/dist/format/steps.d.ts +44 -0
  67. package/dist/format/steps.js +67 -0
  68. package/dist/format/steps.js.map +1 -0
  69. package/dist/format/waits.d.ts +12 -0
  70. package/dist/format/waits.js +156 -0
  71. package/dist/format/waits.js.map +1 -0
  72. package/dist/format/width.d.ts +35 -0
  73. package/dist/format/width.js +38 -0
  74. package/dist/format/width.js.map +1 -0
  75. package/dist/index.d.ts +2 -1
  76. package/dist/index.js +2 -1
  77. package/dist/index.js.map +1 -1
  78. package/dist/judge/docket.js +1 -0
  79. package/dist/judge/docket.js.map +1 -1
  80. package/dist/judge/index.d.ts +1 -0
  81. package/dist/judge/index.js +1 -0
  82. package/dist/judge/index.js.map +1 -1
  83. package/dist/judge/restamp.d.ts +20 -0
  84. package/dist/judge/restamp.js +20 -0
  85. package/dist/judge/restamp.js.map +1 -0
  86. package/dist/nearest.d.ts +46 -0
  87. package/dist/nearest.js +102 -0
  88. package/dist/nearest.js.map +1 -0
  89. package/dist/relate/before.d.ts +19 -24
  90. package/dist/relate/before.js +37 -39
  91. package/dist/relate/before.js.map +1 -1
  92. package/dist/relate/beyond.d.ts +59 -0
  93. package/dist/relate/beyond.js +98 -0
  94. package/dist/relate/beyond.js.map +1 -0
  95. package/dist/relate/carried.d.ts +122 -0
  96. package/dist/relate/carried.js +279 -0
  97. package/dist/relate/carried.js.map +1 -0
  98. package/dist/relate/graph.d.ts +14 -12
  99. package/dist/relate/graph.js +12 -11
  100. package/dist/relate/graph.js.map +1 -1
  101. package/dist/relate/index.d.ts +3 -1
  102. package/dist/relate/index.js +3 -1
  103. package/dist/relate/index.js.map +1 -1
  104. package/dist/relate/merkle.js +2 -11
  105. package/dist/relate/merkle.js.map +1 -1
  106. package/dist/relate/narrow.d.ts +2 -2
  107. package/dist/relate/narrow.js +26 -73
  108. package/dist/relate/narrow.js.map +1 -1
  109. package/dist/relate/reach.d.ts +6 -6
  110. package/dist/relate/reach.js +10 -53
  111. package/dist/relate/reach.js.map +1 -1
  112. package/dist/relate/records.d.ts +6 -5
  113. package/dist/relate/records.js +3 -2
  114. package/dist/relate/records.js.map +1 -1
  115. package/dist/rules/index.d.ts +3 -3
  116. package/dist/rules/index.js +3 -3
  117. package/dist/rules/index.js.map +1 -1
  118. package/dist/rules/normalize/cascade.d.ts +12 -0
  119. package/dist/rules/normalize/cascade.js +34 -16
  120. package/dist/rules/normalize/cascade.js.map +1 -1
  121. package/dist/rules/normalize/fixture.d.ts +3 -0
  122. package/dist/rules/normalize/fixture.js +3 -1
  123. package/dist/rules/normalize/fixture.js.map +1 -1
  124. package/dist/rules/normalize/index.d.ts +2 -2
  125. package/dist/rules/normalize/index.js +9 -2
  126. package/dist/rules/normalize/index.js.map +1 -1
  127. package/dist/rules/normalize/value.d.ts +13 -2
  128. package/dist/rules/normalize/value.js +42 -8
  129. package/dist/rules/normalize/value.js.map +1 -1
  130. package/dist/rules/normalize/wrapper.js +5 -0
  131. package/dist/rules/normalize/wrapper.js.map +1 -1
  132. package/dist/rules/ruleset.d.ts +24 -4
  133. package/dist/rules/ruleset.js +24 -4
  134. package/dist/rules/ruleset.js.map +1 -1
  135. package/dist/segment/index.d.ts +20 -4
  136. package/dist/segment/index.js +28 -7
  137. package/dist/segment/index.js.map +1 -1
  138. package/dist/shard/index.d.ts +11 -0
  139. package/dist/shard/index.js +11 -0
  140. package/dist/shard/index.js.map +1 -0
  141. package/dist/shard/placement.d.ts +119 -0
  142. package/dist/shard/placement.js +156 -0
  143. package/dist/shard/placement.js.map +1 -0
  144. package/dist/share/index.d.ts +1 -1
  145. package/dist/share/index.js +1 -1
  146. package/dist/share/index.js.map +1 -1
  147. package/package.json +8 -1
@@ -0,0 +1,122 @@
1
+ /**
2
+ * The one walk against the arrows: what a change carries from the files it
3
+ * started in to every file that loads one of them, and on.
4
+ *
5
+ * Every question about what a change reached is this walk with a different
6
+ * step. A plain closure carries the whole file everywhere. A narrowed one
7
+ * carries the exports that moved, and an importer that binds none of them is
8
+ * not entered. Selection carries names to a reader and stops behind the
9
+ * importer the record answers. The walk is the same each time — a worklist of
10
+ * facts `(file, name)`, each fact entered once — so it is written once, here,
11
+ * and each caller says only what one importer does with what reached it.
12
+ * Handed the forward adjacency instead, the same walk runs along the arrows,
13
+ * which is how `dependenciesOf` closes over what a file loads. One plain
14
+ * closure is written again: `Graph::search` in sense's native journey graph,
15
+ * because Rust cannot call this.
16
+ *
17
+ * ## What is carried
18
+ *
19
+ * A {@link Carry} is either {@link WHOLE} — the file moved as it loads, or
20
+ * nobody can say which of its names did — or a map from the names that moved
21
+ * to whatever the caller carries with each. An empty map is nothing, and
22
+ * nothing arrives nowhere: the importer is not entered.
23
+ *
24
+ * ## The kernel owns
25
+ *
26
+ * - **the worklist** — first in, first out, so a node is first entered from a
27
+ * node on a shortest path and the trail through `via` is a shortest one;
28
+ * - **what was entered** — the names each node holds only grow, a name is
29
+ * handed to a node once, and a node that holds the whole file takes nothing
30
+ * more. A name is held as a string, whichever file it arrived from: a caller
31
+ * that needs two files' `default` apart names them apart. The walk ends,
32
+ * whatever the steps return, after at most one entry per node and name, and
33
+ * one more when a node turns whole;
34
+ * - **cycles** — a cycle, a self-import included, is a revisit like any other;
35
+ * - **the step that cannot answer** — `undefined` from a step is
36
+ * {@link WHOLE}. A narrower walk has to be earned by an answer, so an
37
+ * unknown can only cost a wider one.
38
+ */
39
+ import { type Adjacency, type EdgeKind, type NodeId } from './graph.js';
40
+ /** The whole file: every name it exposes, and what it does as it loads. */
41
+ export declare const WHOLE: unique symbol;
42
+ export type Whole = typeof WHOLE;
43
+ /** What reaches a node: the whole file, or the names that moved, each with the caller's payload. */
44
+ export type Carry<T> = ReadonlyMap<string, T> | Whole;
45
+ /** Nothing: the importer is not entered, and nothing is handed on from it. */
46
+ export declare const NOTHING: Carry<never>;
47
+ /** What a node holds so far: the whole file, or the names handed to it. Live — read it, never keep it. */
48
+ export type Held = ReadonlySet<string> | Whole;
49
+ /**
50
+ * What one importer does with what reached it. A step left out passes what it
51
+ * was given on unchanged.
52
+ */
53
+ export interface CarriedStep<T> {
54
+ /**
55
+ * What crosses one edge: `carried` left `from`, and `importer` loads `from`
56
+ * through an edge of `kind` (an index into `EDGE_KINDS`). `held` is
57
+ * everything `from` holds when it is expanded, which `carried` is part of:
58
+ * the whole file when `carried` is, and a seed's starting names even when
59
+ * `seedsHold` is `false`.
60
+ * {@link NOTHING} keeps the edge from entering `importer`; `undefined` is
61
+ * the whole file. Not asked of an edge into a node that already holds the
62
+ * whole file, since nothing it returns could add to it.
63
+ */
64
+ arrive?(importer: NodeId, from: NodeId, kind: number, carried: Carry<T>, held: Held): Carry<T> | undefined;
65
+ /**
66
+ * What `importer` hands on, given what arrived that it did not already hold
67
+ * — never empty. Asked once per new arrival, as the walk expands it, in the
68
+ * order the walk reached them, and never of a seed as it starts. Every
69
+ * arrival is asked, so a step that answers {@link NOTHING} for one importer
70
+ * still sees each arrival that reached it. {@link NOTHING} stops the walk
71
+ * behind it; `undefined` hands on the whole file.
72
+ */
73
+ hand?(importer: NodeId, arrived: Carry<T>): Carry<T> | undefined;
74
+ }
75
+ export interface CarriedOptions {
76
+ /** Edge kinds to walk. Every kind when absent; `RUNTIME_EDGES` for what a run loads. */
77
+ readonly through?: Iterable<EdgeKind>;
78
+ /** Nodes the walk never enters, seeds included. */
79
+ readonly avoid?: Iterable<NodeId>;
80
+ /**
81
+ * Marks to write into instead of a fresh array; `1` where a node was entered.
82
+ * A node already marked when the walk starts counts as holding the whole
83
+ * file, so it is neither entered nor handed anything.
84
+ */
85
+ readonly mask?: Uint8Array;
86
+ /**
87
+ * Where to record the node each one was first entered from. Not recorded
88
+ * when absent. A seed's entry is left as it was, `-1` by convention.
89
+ */
90
+ readonly via?: Int32Array;
91
+ /**
92
+ * Whether a seed holds what it starts with. When `false` it holds nothing,
93
+ * so what a cycle carries back to it is new, and handed to it: a file can
94
+ * read its own names back through an importer.
95
+ */
96
+ readonly seedsHold?: boolean;
97
+ }
98
+ export interface Reached {
99
+ /** `1` where a node was entered, including the seeds. */
100
+ readonly mask: Uint8Array;
101
+ /** The entered nodes, in the order they were first entered. */
102
+ readonly entered: readonly NodeId[];
103
+ }
104
+ /**
105
+ * Walk `edges` from `seeds`, each with what its change carries, and hand each
106
+ * node it enters what reaches it through `step`. `edges` is the reverse
107
+ * adjacency for what a change reaches, the forward one for what a file loads.
108
+ * A seed listed more than once starts with everything its listings carry.
109
+ */
110
+ export declare function carried<T>(edges: Adjacency, seeds: Iterable<readonly [NodeId, Carry<T>]>, step?: CarriedStep<T>, options?: CarriedOptions): Reached;
111
+ /**
112
+ * The marked nodes in id order. The walk's own order depends on seed order;
113
+ * this one does not, so a report built from it is byte-stable whatever order
114
+ * the caller listed its changed files in.
115
+ */
116
+ export declare function inIdOrder(mask: Uint8Array): NodeId[];
117
+ /**
118
+ * A kind filter as a byte lookup, so the inner loop tests a byte; `fallback`
119
+ * when no kinds are named.
120
+ */
121
+ export declare function allowedKinds(through: Iterable<EdgeKind> | undefined, fallback?: readonly EdgeKind[]): Uint8Array;
122
+ //# sourceMappingURL=carried.d.ts.map
@@ -0,0 +1,279 @@
1
+ // compass: variance-authority.reach.relations
2
+ /**
3
+ * The one walk against the arrows: what a change carries from the files it
4
+ * started in to every file that loads one of them, and on.
5
+ *
6
+ * Every question about what a change reached is this walk with a different
7
+ * step. A plain closure carries the whole file everywhere. A narrowed one
8
+ * carries the exports that moved, and an importer that binds none of them is
9
+ * not entered. Selection carries names to a reader and stops behind the
10
+ * importer the record answers. The walk is the same each time — a worklist of
11
+ * facts `(file, name)`, each fact entered once — so it is written once, here,
12
+ * and each caller says only what one importer does with what reached it.
13
+ * Handed the forward adjacency instead, the same walk runs along the arrows,
14
+ * which is how `dependenciesOf` closes over what a file loads. One plain
15
+ * closure is written again: `Graph::search` in sense's native journey graph,
16
+ * because Rust cannot call this.
17
+ *
18
+ * ## What is carried
19
+ *
20
+ * A {@link Carry} is either {@link WHOLE} — the file moved as it loads, or
21
+ * nobody can say which of its names did — or a map from the names that moved
22
+ * to whatever the caller carries with each. An empty map is nothing, and
23
+ * nothing arrives nowhere: the importer is not entered.
24
+ *
25
+ * ## The kernel owns
26
+ *
27
+ * - **the worklist** — first in, first out, so a node is first entered from a
28
+ * node on a shortest path and the trail through `via` is a shortest one;
29
+ * - **what was entered** — the names each node holds only grow, a name is
30
+ * handed to a node once, and a node that holds the whole file takes nothing
31
+ * more. A name is held as a string, whichever file it arrived from: a caller
32
+ * that needs two files' `default` apart names them apart. The walk ends,
33
+ * whatever the steps return, after at most one entry per node and name, and
34
+ * one more when a node turns whole;
35
+ * - **cycles** — a cycle, a self-import included, is a revisit like any other;
36
+ * - **the step that cannot answer** — `undefined` from a step is
37
+ * {@link WHOLE}. A narrower walk has to be earned by an answer, so an
38
+ * unknown can only cost a wider one.
39
+ */
40
+ import { EDGE_KINDS } from './graph.js';
41
+ /** The whole file: every name it exposes, and what it does as it loads. */
42
+ export const WHOLE = Symbol('whole');
43
+ /** Nothing: the importer is not entered, and nothing is handed on from it. */
44
+ export const NOTHING = new Map();
45
+ /**
46
+ * Walk `edges` from `seeds`, each with what its change carries, and hand each
47
+ * node it enters what reaches it through `step`. `edges` is the reverse
48
+ * adjacency for what a change reaches, the forward one for what a file loads.
49
+ * A seed listed more than once starts with everything its listings carry.
50
+ */
51
+ export function carried(edges, seeds, step = {}, options = {}) {
52
+ const { offset, target, kind } = edges;
53
+ const nodes = offset.length - 1;
54
+ const mask = options.mask ?? new Uint8Array(nodes);
55
+ const { via } = options;
56
+ const allowed = options.through === undefined ? EVERY : allowedKinds(options.through);
57
+ let avoided;
58
+ if (options.avoid !== undefined) {
59
+ // A typed array ignores a write out of its range, so an id the graph does
60
+ // not hold avoids nothing.
61
+ for (const id of options.avoid) {
62
+ avoided ??= new Uint8Array(nodes);
63
+ avoided[id] = 1;
64
+ }
65
+ }
66
+ // An entered node absent here holds the whole file.
67
+ let partial;
68
+ // The worklist, one number an entry: the node itself when it carries the
69
+ // whole file, `~k` when it carries names, held at `k` aside. Each entry is
70
+ // what arrived, and is handed on as it is expanded: the same entries in the
71
+ // same order as asking on arrival, with the edge loop left free of the step.
72
+ // While every entry is a node's first, the worklist is the list of entered
73
+ // nodes too, so a walk pushes one number a node and nothing else. The first
74
+ // entry that is not a node's first sets `entered` apart, and from then on it
75
+ // is kept on its own.
76
+ const queued = [];
77
+ let aside;
78
+ let entered;
79
+ const { arrive, hand } = step;
80
+ const holdsNothing = options.seedsHold === false;
81
+ for (const [seed, carry] of seeds) {
82
+ if (seed < 0 || seed >= nodes || avoided?.[seed] === 1)
83
+ continue;
84
+ let start = carry;
85
+ if (mask[seed] !== 1) {
86
+ mask[seed] = 1;
87
+ entered?.push(seed);
88
+ if (holdsNothing)
89
+ (partial ??= new Map()).set(seed, new Set());
90
+ else if (carry !== WHOLE)
91
+ (partial ??= new Map()).set(seed, namesOf(carry));
92
+ }
93
+ else {
94
+ // Marked before the walk, which holds the whole file, or listed again.
95
+ const holds = partial?.get(seed);
96
+ if (holds === undefined)
97
+ continue;
98
+ // A seed that holds nothing of what it starts with starts every listing.
99
+ if (!holdsNothing) {
100
+ if (carry === WHOLE)
101
+ partial.delete(seed);
102
+ else
103
+ start = addedTo(holds, carry);
104
+ }
105
+ if (start !== WHOLE && start.size === 0)
106
+ continue;
107
+ entered ??= nodesOf(queued, aside, []);
108
+ }
109
+ queued.push(start === WHOLE ? seed : named((aside ??= { nodes: [], carries: [] }), seed, start));
110
+ }
111
+ const starts = queued.length;
112
+ // With no step on the edge and every seed whole, nothing is held by name
113
+ // until a hand answers with names, and the walk runs in a loop of its own
114
+ // until then: a closure and a cut walk are this loop, unslowed by the walks
115
+ // that narrow.
116
+ let from = 0;
117
+ let handed;
118
+ if (arrive === undefined && partial === undefined && aside === undefined) {
119
+ const stop = wholeFrom(edges, queued, starts, step, mask, via, allowed, avoided);
120
+ if (stop === undefined)
121
+ return { mask, entered: queued };
122
+ ({ head: from, carry: handed } = stop);
123
+ }
124
+ for (let head = from; head < queued.length; head += 1) {
125
+ const entry = queued[head];
126
+ const node = entry >= 0 ? entry : aside.nodes[~entry];
127
+ let carry = entry >= 0 ? WHOLE : aside.carries[~entry];
128
+ if (handed !== undefined && head === from)
129
+ carry = handed;
130
+ else if (hand !== undefined && head >= starts)
131
+ carry = step.hand(node, carry) ?? WHOLE;
132
+ if (carry !== WHOLE && carry.size === 0)
133
+ continue;
134
+ // What it holds, which what it carries is part of: a seed that holds
135
+ // nothing of what it starts with still starts with it.
136
+ const holds = carry === WHOLE ? undefined : partial?.get(node);
137
+ let held = holds ?? WHOLE;
138
+ if (holdsNothing && head < starts && holds !== undefined && carry !== WHOLE) {
139
+ const both = namesOf(carry);
140
+ for (const name of holds)
141
+ both.add(name);
142
+ held = both;
143
+ }
144
+ const end = offset[node + 1];
145
+ for (let edge = offset[node]; edge < end; edge += 1) {
146
+ const edgeKind = kind[edge];
147
+ if (allowed[edgeKind] !== 1)
148
+ continue;
149
+ const next = target[edge];
150
+ if (avoided?.[next] === 1)
151
+ continue;
152
+ // Entered and absent from `partial`: it holds the whole file already.
153
+ const seen = mask[next] === 1;
154
+ if (seen && (partial === undefined || !partial.has(next)))
155
+ continue;
156
+ const out = arrive === undefined ? carry : (step.arrive(next, node, edgeKind, carry, held) ?? WHOLE);
157
+ if (out !== WHOLE && out.size === 0)
158
+ continue;
159
+ let arrived = out;
160
+ if (!seen) {
161
+ mask[next] = 1;
162
+ if (via !== undefined)
163
+ via[next] = node;
164
+ entered?.push(next);
165
+ if (out !== WHOLE)
166
+ (partial ??= new Map()).set(next, namesOf(out));
167
+ }
168
+ else {
169
+ if (out === WHOLE)
170
+ partial.delete(next);
171
+ else {
172
+ arrived = addedTo(partial.get(next), out);
173
+ if (arrived.size === 0)
174
+ continue;
175
+ }
176
+ entered ??= nodesOf(queued, aside, []);
177
+ }
178
+ queued.push(arrived === WHOLE ? next : named((aside ??= { nodes: [], carries: [] }), next, arrived));
179
+ }
180
+ }
181
+ // Nothing carried by name, nothing to decode: every entry is a node.
182
+ return { mask, entered: entered ?? (aside === undefined ? queued : nodesOf(queued, aside, queued)) };
183
+ }
184
+ /**
185
+ * The walk while every entry carries the whole file: an entered node takes
186
+ * nothing more, so the mask is the whole record of what was entered. Returns
187
+ * where a hand first answered with names, or `undefined` when the walk ended
188
+ * whole.
189
+ */
190
+ function wholeFrom(edges, queued, starts, step, mask, via, allowed, avoided) {
191
+ const { offset, target, kind } = edges;
192
+ const asks = step.hand !== undefined;
193
+ for (let head = 0; head < queued.length; head += 1) {
194
+ const node = queued[head];
195
+ if (asks && head >= starts) {
196
+ const carry = step.hand(node, WHOLE);
197
+ if (carry !== undefined && carry !== WHOLE) {
198
+ if (carry.size === 0)
199
+ continue;
200
+ return { head, carry };
201
+ }
202
+ }
203
+ const end = offset[node + 1];
204
+ for (let edge = offset[node]; edge < end; edge += 1) {
205
+ if (allowed[kind[edge]] !== 1)
206
+ continue;
207
+ const next = target[edge];
208
+ if (mask[next] === 1 || avoided?.[next] === 1)
209
+ continue;
210
+ mask[next] = 1;
211
+ if (via !== undefined)
212
+ via[next] = node;
213
+ queued.push(next);
214
+ }
215
+ }
216
+ return undefined;
217
+ }
218
+ /** The worklist entry for `node` carrying the names in `carry`. */
219
+ function named(aside, node, carry) {
220
+ aside.carries.push(carry);
221
+ return ~(aside.nodes.push(node) - 1);
222
+ }
223
+ /** The nodes of `entries`, written into `into`, which may be `entries` itself. */
224
+ function nodesOf(entries, aside, into) {
225
+ for (let at = 0; at < entries.length; at += 1) {
226
+ const entry = entries[at];
227
+ into[at] = entry >= 0 ? entry : aside.nodes[~entry];
228
+ }
229
+ return into;
230
+ }
231
+ /** What `carry` adds to `holds`, which takes it in. */
232
+ function addedTo(holds, carry) {
233
+ const added = new Map();
234
+ for (const [name, payload] of carry) {
235
+ if (holds.has(name))
236
+ continue;
237
+ holds.add(name);
238
+ added.set(name, payload);
239
+ }
240
+ return added;
241
+ }
242
+ /**
243
+ * The names a carry holds, as a set the walk grows. Added one by one: V8 builds
244
+ * a `Set` from a map's key iterator several times slower than this loop.
245
+ */
246
+ function namesOf(carry) {
247
+ const names = new Set();
248
+ for (const name of carry.keys())
249
+ names.add(name);
250
+ return names;
251
+ }
252
+ /**
253
+ * The marked nodes in id order. The walk's own order depends on seed order;
254
+ * this one does not, so a report built from it is byte-stable whatever order
255
+ * the caller listed its changed files in.
256
+ */
257
+ export function inIdOrder(mask) {
258
+ const visited = [];
259
+ for (let id = 0; id < mask.length; id += 1)
260
+ if (mask[id] === 1)
261
+ visited.push(id);
262
+ return visited;
263
+ }
264
+ /** The default filter, built once: a walk runs once per changed file. */
265
+ const EVERY = allowedKinds(undefined);
266
+ /**
267
+ * A kind filter as a byte lookup, so the inner loop tests a byte; `fallback`
268
+ * when no kinds are named.
269
+ */
270
+ export function allowedKinds(through, fallback = EDGE_KINDS) {
271
+ const allowed = new Uint8Array(EDGE_KINDS.length);
272
+ for (const name of through ?? fallback) {
273
+ const at = EDGE_KINDS.indexOf(name);
274
+ if (at !== -1)
275
+ allowed[at] = 1;
276
+ }
277
+ return allowed;
278
+ }
279
+ //# sourceMappingURL=carried.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"carried.js","sourceRoot":"","sources":["../../src/relate/carried.ts"],"names":[],"mappings":"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","sourcesContent":["// compass: variance-authority.reach.relations\n/**\n * The one walk against the arrows: what a change carries from the files it\n * started in to every file that loads one of them, and on.\n *\n * Every question about what a change reached is this walk with a different\n * step. A plain closure carries the whole file everywhere. A narrowed one\n * carries the exports that moved, and an importer that binds none of them is\n * not entered. Selection carries names to a reader and stops behind the\n * importer the record answers. The walk is the same each time — a worklist of\n * facts `(file, name)`, each fact entered once — so it is written once, here,\n * and each caller says only what one importer does with what reached it.\n * Handed the forward adjacency instead, the same walk runs along the arrows,\n * which is how `dependenciesOf` closes over what a file loads. One plain\n * closure is written again: `Graph::search` in sense's native journey graph,\n * because Rust cannot call this.\n *\n * ## What is carried\n *\n * A {@link Carry} is either {@link WHOLE} — the file moved as it loads, or\n * nobody can say which of its names did — or a map from the names that moved\n * to whatever the caller carries with each. An empty map is nothing, and\n * nothing arrives nowhere: the importer is not entered.\n *\n * ## The kernel owns\n *\n * - **the worklist** — first in, first out, so a node is first entered from a\n * node on a shortest path and the trail through `via` is a shortest one;\n * - **what was entered** — the names each node holds only grow, a name is\n * handed to a node once, and a node that holds the whole file takes nothing\n * more. A name is held as a string, whichever file it arrived from: a caller\n * that needs two files' `default` apart names them apart. The walk ends,\n * whatever the steps return, after at most one entry per node and name, and\n * one more when a node turns whole;\n * - **cycles** — a cycle, a self-import included, is a revisit like any other;\n * - **the step that cannot answer** — `undefined` from a step is\n * {@link WHOLE}. A narrower walk has to be earned by an answer, so an\n * unknown can only cost a wider one.\n */\n\nimport { EDGE_KINDS, type Adjacency, type EdgeKind, type NodeId } from './graph.js';\n\n/** The whole file: every name it exposes, and what it does as it loads. */\nexport const WHOLE: unique symbol = Symbol('whole');\nexport type Whole = typeof WHOLE;\n\n/** What reaches a node: the whole file, or the names that moved, each with the caller's payload. */\nexport type Carry<T> = ReadonlyMap<string, T> | Whole;\n\n/** Nothing: the importer is not entered, and nothing is handed on from it. */\nexport const NOTHING: Carry<never> = new Map<string, never>();\n\n/** What a node holds so far: the whole file, or the names handed to it. Live — read it, never keep it. */\nexport type Held = ReadonlySet<string> | Whole;\n\n/**\n * What one importer does with what reached it. A step left out passes what it\n * was given on unchanged.\n */\nexport interface CarriedStep<T> {\n /**\n * What crosses one edge: `carried` left `from`, and `importer` loads `from`\n * through an edge of `kind` (an index into `EDGE_KINDS`). `held` is\n * everything `from` holds when it is expanded, which `carried` is part of:\n * the whole file when `carried` is, and a seed's starting names even when\n * `seedsHold` is `false`.\n * {@link NOTHING} keeps the edge from entering `importer`; `undefined` is\n * the whole file. Not asked of an edge into a node that already holds the\n * whole file, since nothing it returns could add to it.\n */\n arrive?(importer: NodeId, from: NodeId, kind: number, carried: Carry<T>, held: Held): Carry<T> | undefined;\n /**\n * What `importer` hands on, given what arrived that it did not already hold\n * — never empty. Asked once per new arrival, as the walk expands it, in the\n * order the walk reached them, and never of a seed as it starts. Every\n * arrival is asked, so a step that answers {@link NOTHING} for one importer\n * still sees each arrival that reached it. {@link NOTHING} stops the walk\n * behind it; `undefined` hands on the whole file.\n */\n hand?(importer: NodeId, arrived: Carry<T>): Carry<T> | undefined;\n}\n\nexport interface CarriedOptions {\n /** Edge kinds to walk. Every kind when absent; `RUNTIME_EDGES` for what a run loads. */\n readonly through?: Iterable<EdgeKind>;\n /** Nodes the walk never enters, seeds included. */\n readonly avoid?: Iterable<NodeId>;\n /**\n * Marks to write into instead of a fresh array; `1` where a node was entered.\n * A node already marked when the walk starts counts as holding the whole\n * file, so it is neither entered nor handed anything.\n */\n readonly mask?: Uint8Array;\n /**\n * Where to record the node each one was first entered from. Not recorded\n * when absent. A seed's entry is left as it was, `-1` by convention.\n */\n readonly via?: Int32Array;\n /**\n * Whether a seed holds what it starts with. When `false` it holds nothing,\n * so what a cycle carries back to it is new, and handed to it: a file can\n * read its own names back through an importer.\n */\n readonly seedsHold?: boolean;\n}\n\nexport interface Reached {\n /** `1` where a node was entered, including the seeds. */\n readonly mask: Uint8Array;\n /** The entered nodes, in the order they were first entered. */\n readonly entered: readonly NodeId[];\n}\n\n/**\n * Walk `edges` from `seeds`, each with what its change carries, and hand each\n * node it enters what reaches it through `step`. `edges` is the reverse\n * adjacency for what a change reaches, the forward one for what a file loads.\n * A seed listed more than once starts with everything its listings carry.\n */\nexport function carried<T>(\n edges: Adjacency,\n seeds: Iterable<readonly [NodeId, Carry<T>]>,\n step: CarriedStep<T> = {},\n options: CarriedOptions = {},\n): Reached {\n const { offset, target, kind } = edges;\n const nodes = offset.length - 1;\n const mask = options.mask ?? new Uint8Array(nodes);\n const { via } = options;\n const allowed = options.through === undefined ? EVERY : allowedKinds(options.through);\n let avoided: Uint8Array | undefined;\n if (options.avoid !== undefined) {\n // A typed array ignores a write out of its range, so an id the graph does\n // not hold avoids nothing.\n for (const id of options.avoid) {\n avoided ??= new Uint8Array(nodes);\n avoided[id] = 1;\n }\n }\n\n // An entered node absent here holds the whole file.\n let partial: Map<NodeId, Set<string>> | undefined;\n // The worklist, one number an entry: the node itself when it carries the\n // whole file, `~k` when it carries names, held at `k` aside. Each entry is\n // what arrived, and is handed on as it is expanded: the same entries in the\n // same order as asking on arrival, with the edge loop left free of the step.\n // While every entry is a node's first, the worklist is the list of entered\n // nodes too, so a walk pushes one number a node and nothing else. The first\n // entry that is not a node's first sets `entered` apart, and from then on it\n // is kept on its own.\n const queued: number[] = [];\n let aside: Aside<T> | undefined;\n let entered: NodeId[] | undefined;\n const { arrive, hand } = step;\n\n const holdsNothing = options.seedsHold === false;\n for (const [seed, carry] of seeds) {\n if (seed < 0 || seed >= nodes || avoided?.[seed] === 1) continue;\n let start: Carry<T> = carry;\n if (mask[seed] !== 1) {\n mask[seed] = 1;\n entered?.push(seed);\n if (holdsNothing) (partial ??= new Map()).set(seed, new Set());\n else if (carry !== WHOLE) (partial ??= new Map()).set(seed, namesOf(carry));\n } else {\n // Marked before the walk, which holds the whole file, or listed again.\n const holds = partial?.get(seed);\n if (holds === undefined) continue;\n // A seed that holds nothing of what it starts with starts every listing.\n if (!holdsNothing) {\n if (carry === WHOLE) partial!.delete(seed);\n else start = addedTo(holds, carry);\n }\n if (start !== WHOLE && start.size === 0) continue;\n entered ??= nodesOf(queued, aside, []);\n }\n queued.push(start === WHOLE ? seed : named((aside ??= { nodes: [], carries: [] }), seed, start));\n }\n const starts = queued.length;\n\n // With no step on the edge and every seed whole, nothing is held by name\n // until a hand answers with names, and the walk runs in a loop of its own\n // until then: a closure and a cut walk are this loop, unslowed by the walks\n // that narrow.\n let from = 0;\n let handed: ReadonlyMap<string, T> | undefined;\n if (arrive === undefined && partial === undefined && aside === undefined) {\n const stop = wholeFrom(edges, queued, starts, step, mask, via, allowed, avoided);\n if (stop === undefined) return { mask, entered: queued };\n ({ head: from, carry: handed } = stop);\n }\n\n for (let head = from; head < queued.length; head += 1) {\n const entry = queued[head]!;\n const node = entry >= 0 ? entry : aside!.nodes[~entry]!;\n let carry: Carry<T> = entry >= 0 ? WHOLE : aside!.carries[~entry]!;\n if (handed !== undefined && head === from) carry = handed;\n else if (hand !== undefined && head >= starts) carry = step.hand!(node, carry) ?? WHOLE;\n if (carry !== WHOLE && carry.size === 0) continue;\n // What it holds, which what it carries is part of: a seed that holds\n // nothing of what it starts with still starts with it.\n const holds = carry === WHOLE ? undefined : partial?.get(node);\n let held: Held = holds ?? WHOLE;\n if (holdsNothing && head < starts && holds !== undefined && carry !== WHOLE) {\n const both = namesOf(carry);\n for (const name of holds) both.add(name);\n held = both;\n }\n const end = offset[node + 1]!;\n\n for (let edge = offset[node]!; edge < end; edge += 1) {\n const edgeKind = kind[edge]!;\n if (allowed[edgeKind] !== 1) continue;\n const next = target[edge]!;\n if (avoided?.[next] === 1) continue;\n // Entered and absent from `partial`: it holds the whole file already.\n const seen = mask[next] === 1;\n if (seen && (partial === undefined || !partial.has(next))) continue;\n\n const out = arrive === undefined ? carry : (step.arrive!(next, node, edgeKind, carry, held) ?? WHOLE);\n if (out !== WHOLE && out.size === 0) continue;\n let arrived = out;\n if (!seen) {\n mask[next] = 1;\n if (via !== undefined) via[next] = node;\n entered?.push(next);\n if (out !== WHOLE) (partial ??= new Map()).set(next, namesOf(out));\n } else {\n if (out === WHOLE) partial!.delete(next);\n else {\n arrived = addedTo(partial!.get(next)!, out);\n if (arrived.size === 0) continue;\n }\n entered ??= nodesOf(queued, aside, []);\n }\n queued.push(arrived === WHOLE ? next : named((aside ??= { nodes: [], carries: [] }), next, arrived));\n }\n }\n\n // Nothing carried by name, nothing to decode: every entry is a node.\n return { mask, entered: entered ?? (aside === undefined ? queued : nodesOf(queued, aside, queued)) };\n}\n\n/** Where a whole walk met a hand that answered with names, and the names. */\ninterface Handed<T> {\n readonly head: number;\n readonly carry: ReadonlyMap<string, T>;\n}\n\n/**\n * The walk while every entry carries the whole file: an entered node takes\n * nothing more, so the mask is the whole record of what was entered. Returns\n * where a hand first answered with names, or `undefined` when the walk ended\n * whole.\n */\nfunction wholeFrom<T>(\n edges: Adjacency,\n queued: NodeId[],\n starts: number,\n step: CarriedStep<T>,\n mask: Uint8Array,\n via: Int32Array | undefined,\n allowed: Uint8Array,\n avoided: Uint8Array | undefined,\n): Handed<T> | undefined {\n const { offset, target, kind } = edges;\n const asks = step.hand !== undefined;\n for (let head = 0; head < queued.length; head += 1) {\n const node = queued[head]!;\n if (asks && head >= starts) {\n const carry = step.hand!(node, WHOLE);\n if (carry !== undefined && carry !== WHOLE) {\n if (carry.size === 0) continue;\n return { head, carry };\n }\n }\n const end = offset[node + 1]!;\n for (let edge = offset[node]!; edge < end; edge += 1) {\n if (allowed[kind[edge]!] !== 1) continue;\n const next = target[edge]!;\n if (mask[next] === 1 || avoided?.[next] === 1) continue;\n mask[next] = 1;\n if (via !== undefined) via[next] = node;\n queued.push(next);\n }\n }\n return undefined;\n}\n\n/** What the worklist carries by name, out of line so a whole entry is one number. */\ninterface Aside<T> {\n readonly nodes: NodeId[];\n readonly carries: Array<ReadonlyMap<string, T>>;\n}\n\n/** The worklist entry for `node` carrying the names in `carry`. */\nfunction named<T>(aside: Aside<T>, node: NodeId, carry: ReadonlyMap<string, T>): number {\n aside.carries.push(carry);\n return ~(aside.nodes.push(node) - 1);\n}\n\n/** The nodes of `entries`, written into `into`, which may be `entries` itself. */\nfunction nodesOf<T>(entries: readonly number[], aside: Aside<T> | undefined, into: NodeId[]): NodeId[] {\n for (let at = 0; at < entries.length; at += 1) {\n const entry = entries[at]!;\n into[at] = entry >= 0 ? entry : aside!.nodes[~entry]!;\n }\n return into;\n}\n\n/** What `carry` adds to `holds`, which takes it in. */\nfunction addedTo<T>(holds: Set<string>, carry: ReadonlyMap<string, T>): ReadonlyMap<string, T> {\n const added = new Map<string, T>();\n for (const [name, payload] of carry) {\n if (holds.has(name)) continue;\n holds.add(name);\n added.set(name, payload);\n }\n return added;\n}\n\n/**\n * The names a carry holds, as a set the walk grows. Added one by one: V8 builds\n * a `Set` from a map's key iterator several times slower than this loop.\n */\nfunction namesOf<T>(carry: ReadonlyMap<string, T>): Set<string> {\n const names = new Set<string>();\n for (const name of carry.keys()) names.add(name);\n return names;\n}\n\n/**\n * The marked nodes in id order. The walk's own order depends on seed order;\n * this one does not, so a report built from it is byte-stable whatever order\n * the caller listed its changed files in.\n */\nexport function inIdOrder(mask: Uint8Array): NodeId[] {\n const visited: NodeId[] = [];\n for (let id = 0; id < mask.length; id += 1) if (mask[id] === 1) visited.push(id);\n return visited;\n}\n\n/** The default filter, built once: a walk runs once per changed file. */\nconst EVERY = allowedKinds(undefined);\n\n/**\n * A kind filter as a byte lookup, so the inner loop tests a byte; `fallback`\n * when no kinds are named.\n */\nexport function allowedKinds(\n through: Iterable<EdgeKind> | undefined,\n fallback: readonly EdgeKind[] = EDGE_KINDS,\n): Uint8Array {\n const allowed = new Uint8Array(EDGE_KINDS.length);\n for (const name of through ?? fallback) {\n const at = EDGE_KINDS.indexOf(name);\n if (at !== -1) allowed[at] = 1;\n }\n return allowed;\n}\n"]}
@@ -47,7 +47,7 @@
47
47
  * for each name an install resolved. That is deliberate rather than incidental. A
48
48
  * component relation — *`TodoFooter` renders `Chip`* — is another edge kind
49
49
  * between nodes of another kind in this same structure, and
50
- * [`composition.md`](../../../../docs/composition.md) already computes exactly
50
+ * [`composition.md`](https://variance-authority.dev/docs/composition) already computes exactly
51
51
  * that relation from what a run rendered. One graph means the static answer and
52
52
  * the rendered answer are joinable rather than adjacent.
53
53
  *
@@ -56,7 +56,7 @@
56
56
  * tests, and leaves it again at the packages — so a bumped dependency is a node
57
57
  * like any other, and *which of our files a new `jsdom` can affect* is the
58
58
  * one traversal this file already performs, seeded on the other side
59
- * ([`docs/selecting.md`](../../../../docs/selecting.md)).
59
+ * ([`docs/selecting.md`](https://variance-authority.dev/docs/selecting)).
60
60
  *
61
61
  * ## What it is not
62
62
  *
@@ -76,11 +76,11 @@ export type NodeKind = (typeof NODE_KINDS)[number];
76
76
  * Edge kinds, in id order.
77
77
  *
78
78
  * The distinctions are kept because they explain a finding. One of them also
79
- * decides a walk: `type` is erased by every compiler, so nothing behind it runs
80
- * and nothing behind it renders, and the default traversal leaves it out
81
- * (`RUNTIME_EDGES`). A caller whose question is about source rather than about a
82
- * runtime — a docgen that reads prop types, a type-check gate — passes
83
- * `EDGE_KINDS` and walks it.
79
+ * decides a runtime walk: `type` is erased by every compiler, so nothing behind
80
+ * it runs and nothing behind it renders. A traversal walks every kind unless its
81
+ * caller names others, because a type-only import is still a dependency; a
82
+ * caller whose question is what a run loads — test selection — passes
83
+ * `RUNTIME_EDGES` and leaves it out.
84
84
  */
85
85
  export declare const EDGE_KINDS: readonly [
86
86
  /** `import x from './y'` — a value import. */
@@ -101,10 +101,11 @@ export declare const EDGE_KINDS: readonly [
101
101
  'depends'];
102
102
  export type EdgeKind = (typeof EDGE_KINDS)[number];
103
103
  /**
104
- * The edge kinds a runtime loads through: every kind but `type`. The
105
- * default for a traversal, and the list a caller widens from. A closure folds a
106
- * shorter list (`CLOSURE_EDGES`), because a digest is a claim about bytes and
107
- * one of these kinds leads nowhere any bytes are.
104
+ * The edge kinds a runtime loads through: every kind but `type`. What a caller
105
+ * asking a runtime question, such as test selection, passes as `through`; a
106
+ * traversal walks every kind when it is not told. A closure folds a shorter
107
+ * list (`CLOSURE_EDGES`), because a digest is a claim about bytes and one of
108
+ * these kinds leads nowhere any bytes are.
108
109
  */
109
110
  export declare const RUNTIME_EDGES: readonly EdgeKind[];
110
111
  export interface Node {
@@ -114,10 +115,11 @@ export interface Node {
114
115
  * package the name source code imports it by — `@mui/material`, never a
115
116
  * version and never a resolution. Which copy a resolver handed any one
116
117
  * importer is unanswerable without running that resolver, and the question
117
- * this graph is asked never needs it ([`sense/lock`](../../../sense/src/lock/index.ts)).
118
+ * this graph is asked never needs it ([`sense/lock`](https://github.com/Variance-Authority/variance-authority/blob/main/packages/sense/src/lock/index.ts)).
118
119
  */
119
120
  readonly name: string;
120
121
  }
122
+ /** One edge as a reader of a file states it: `from` reaches `to` through an edge of `kind`. */
121
123
  export interface Relation {
122
124
  readonly from: Node;
123
125
  readonly to: Node;
@@ -47,7 +47,7 @@
47
47
  * for each name an install resolved. That is deliberate rather than incidental. A
48
48
  * component relation — *`TodoFooter` renders `Chip`* — is another edge kind
49
49
  * between nodes of another kind in this same structure, and
50
- * [`composition.md`](../../../../docs/composition.md) already computes exactly
50
+ * [`composition.md`](https://variance-authority.dev/docs/composition) already computes exactly
51
51
  * that relation from what a run rendered. One graph means the static answer and
52
52
  * the rendered answer are joinable rather than adjacent.
53
53
  *
@@ -56,7 +56,7 @@
56
56
  * tests, and leaves it again at the packages — so a bumped dependency is a node
57
57
  * like any other, and *which of our files a new `jsdom` can affect* is the
58
58
  * one traversal this file already performs, seeded on the other side
59
- * ([`docs/selecting.md`](../../../../docs/selecting.md)).
59
+ * ([`docs/selecting.md`](https://variance-authority.dev/docs/selecting)).
60
60
  *
61
61
  * ## What it is not
62
62
  *
@@ -74,11 +74,11 @@ export const NODE_KINDS = ['file', 'component', 'package'];
74
74
  * Edge kinds, in id order.
75
75
  *
76
76
  * The distinctions are kept because they explain a finding. One of them also
77
- * decides a walk: `type` is erased by every compiler, so nothing behind it runs
78
- * and nothing behind it renders, and the default traversal leaves it out
79
- * (`RUNTIME_EDGES`). A caller whose question is about source rather than about a
80
- * runtime — a docgen that reads prop types, a type-check gate — passes
81
- * `EDGE_KINDS` and walks it.
77
+ * decides a runtime walk: `type` is erased by every compiler, so nothing behind
78
+ * it runs and nothing behind it renders. A traversal walks every kind unless its
79
+ * caller names others, because a type-only import is still a dependency; a
80
+ * caller whose question is what a run loads — test selection — passes
81
+ * `RUNTIME_EDGES` and leaves it out.
82
82
  */
83
83
  export const EDGE_KINDS = [
84
84
  /** `import x from './y'` — a value import. */
@@ -99,10 +99,11 @@ export const EDGE_KINDS = [
99
99
  'depends',
100
100
  ];
101
101
  /**
102
- * The edge kinds a runtime loads through: every kind but `type`. The
103
- * default for a traversal, and the list a caller widens from. A closure folds a
104
- * shorter list (`CLOSURE_EDGES`), because a digest is a claim about bytes and
105
- * one of these kinds leads nowhere any bytes are.
102
+ * The edge kinds a runtime loads through: every kind but `type`. What a caller
103
+ * asking a runtime question, such as test selection, passes as `through`; a
104
+ * traversal walks every kind when it is not told. A closure folds a shorter
105
+ * list (`CLOSURE_EDGES`), because a digest is a claim about bytes and one of
106
+ * these kinds leads nowhere any bytes are.
106
107
  */
107
108
  export const RUNTIME_EDGES = EDGE_KINDS.filter((kind) => kind !== 'type');
108
109
  /**