@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.
- package/CHANGELOG.md +878 -0
- package/README.md +38 -17
- package/dist/attribute/component-hash.d.ts +14 -5
- package/dist/attribute/component-hash.js +14 -5
- package/dist/attribute/component-hash.js.map +1 -1
- package/dist/attribute/composition.d.ts +16 -0
- package/dist/attribute/composition.js +4 -6
- package/dist/attribute/composition.js.map +1 -1
- package/dist/attribute/index.d.ts +3 -1
- package/dist/attribute/index.js +2 -1
- package/dist/attribute/index.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 +91 -22
- package/dist/attribute/region.js.map +1 -1
- package/dist/attribute/source.d.ts +10 -24
- package/dist/attribute/source.js +4 -38
- package/dist/attribute/source.js.map +1 -1
- package/dist/attribute/subject-pieces.d.ts +37 -0
- package/dist/attribute/subject-pieces.js +122 -0
- package/dist/attribute/subject-pieces.js.map +1 -0
- 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/capture.d.ts +25 -0
- package/dist/format/capture.js +6 -0
- package/dist/format/capture.js.map +1 -1
- package/dist/format/document.d.ts +28 -5
- package/dist/format/document.js +8 -2
- package/dist/format/document.js.map +1 -1
- package/dist/format/drive.d.ts +191 -0
- package/dist/format/drive.js +343 -0
- package/dist/format/drive.js.map +1 -0
- package/dist/format/environment.d.ts +20 -2
- package/dist/format/environment.js +7 -0
- package/dist/format/environment.js.map +1 -1
- package/dist/format/index.d.ts +13 -3
- package/dist/format/index.js +8 -2
- package/dist/format/index.js.map +1 -1
- package/dist/format/intervention.d.ts +79 -0
- package/dist/format/intervention.js.map +1 -1
- package/dist/format/origin.d.ts +32 -0
- package/dist/format/origin.js +54 -0
- package/dist/format/origin.js.map +1 -0
- 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/snapshot.d.ts +2 -0
- package/dist/format/snapshot.js.map +1 -1
- package/dist/format/stabilize.d.ts +35 -6
- package/dist/format/stabilize.js +58 -103
- 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/waits.d.ts +12 -0
- package/dist/format/waits.js +156 -0
- package/dist/format/waits.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/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- 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/nearest.d.ts +46 -0
- package/dist/nearest.js +102 -0
- package/dist/nearest.js.map +1 -0
- package/dist/relate/before.d.ts +19 -24
- package/dist/relate/before.js +37 -39
- package/dist/relate/before.js.map +1 -1
- package/dist/relate/beyond.d.ts +59 -0
- package/dist/relate/beyond.js +98 -0
- package/dist/relate/beyond.js.map +1 -0
- package/dist/relate/carried.d.ts +122 -0
- package/dist/relate/carried.js +279 -0
- package/dist/relate/carried.js.map +1 -0
- 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 +3 -1
- package/dist/relate/index.js +3 -1
- package/dist/relate/index.js.map +1 -1
- package/dist/relate/merkle.js +2 -11
- package/dist/relate/merkle.js.map +1 -1
- package/dist/relate/narrow.d.ts +2 -2
- package/dist/relate/narrow.js +26 -73
- package/dist/relate/narrow.js.map +1 -1
- package/dist/relate/reach.d.ts +6 -6
- package/dist/relate/reach.js +10 -53
- package/dist/relate/reach.js.map +1 -1
- package/dist/relate/records.d.ts +6 -5
- package/dist/relate/records.js +3 -2
- package/dist/relate/records.js.map +1 -1
- package/dist/rules/index.d.ts +3 -3
- package/dist/rules/index.js +3 -3
- package/dist/rules/index.js.map +1 -1
- package/dist/rules/normalize/cascade.d.ts +12 -0
- package/dist/rules/normalize/cascade.js +34 -16
- package/dist/rules/normalize/cascade.js.map +1 -1
- package/dist/rules/normalize/fixture.d.ts +3 -0
- package/dist/rules/normalize/fixture.js +3 -1
- package/dist/rules/normalize/fixture.js.map +1 -1
- package/dist/rules/normalize/index.d.ts +2 -2
- package/dist/rules/normalize/index.js +9 -2
- package/dist/rules/normalize/index.js.map +1 -1
- package/dist/rules/normalize/value.d.ts +13 -2
- package/dist/rules/normalize/value.js +42 -8
- package/dist/rules/normalize/value.js.map +1 -1
- package/dist/rules/normalize/wrapper.js +5 -0
- package/dist/rules/normalize/wrapper.js.map +1 -1
- package/dist/rules/ruleset.d.ts +24 -4
- package/dist/rules/ruleset.js +24 -4
- package/dist/rules/ruleset.js.map +1 -1
- package/dist/segment/index.d.ts +20 -4
- package/dist/segment/index.js +28 -7
- package/dist/segment/index.js.map +1 -1
- package/dist/shard/index.d.ts +11 -0
- package/dist/shard/index.js +11 -0
- package/dist/shard/index.js.map +1 -0
- package/dist/shard/placement.d.ts +119 -0
- package/dist/shard/placement.js +156 -0
- package/dist/shard/placement.js.map +1 -0
- 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 +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"]}
|
package/dist/relate/graph.d.ts
CHANGED
|
@@ -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`](
|
|
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`](
|
|
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
|
|
80
|
-
* and nothing behind it renders
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
* `
|
|
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`.
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
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`](
|
|
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;
|
package/dist/relate/graph.js
CHANGED
|
@@ -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`](
|
|
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`](
|
|
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
|
|
78
|
-
* and nothing behind it renders
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* `
|
|
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`.
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
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
|
/**
|