@ghostry/fabricator 0.0.6 → 0.0.7
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.
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
function
|
|
2
|
-
|
|
3
|
-
for(let index = 0; index <
|
|
1
|
+
function governs(receiver, reader) {
|
|
2
|
+
if (reader.length > receiver.length) return false;
|
|
3
|
+
for(let index = 0; index < reader.length; index++)if (reader[index] !== receiver[index]) return false;
|
|
4
4
|
return true;
|
|
5
5
|
}
|
|
6
6
|
function toVisible(frames, ancestry) {
|
|
7
|
-
return frames.filter((frame)=>
|
|
7
|
+
return frames.filter((frame)=>governs(frame.ancestry, ancestry));
|
|
8
8
|
}
|
|
9
9
|
function toInnermostFrame(stack, ancestry) {
|
|
10
10
|
const frames = stack.visible(ancestry);
|
|
@@ -34,12 +34,15 @@ import type { FabricatorTestContext, Integration } from "./Types";
|
|
|
34
34
|
* `scope` is a function so that capturing it captures the lookup, where a
|
|
35
35
|
* captured result would pin one frame.
|
|
36
36
|
*
|
|
37
|
-
* The
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
37
|
+
* The per-test wrap is entered on `context.scope()`, so it governs that
|
|
38
|
+
* instance and its ancestors: the integrated instance when nothing encloses
|
|
39
|
+
* it, and that instance as an ancestor of the enclosing scope when something
|
|
40
|
+
* does. It does not govern forks of the integrated instance. Per-test data
|
|
41
|
+
* therefore comes from the instance handed to `integration(...)`, from
|
|
42
|
+
* `context.fabricator`, or from a fork of that scope — a module-level fork of
|
|
43
|
+
* the integrated instance draws the same data in every test, and because its
|
|
44
|
+
* construction counter runs across tests, which values a test gets depends on
|
|
45
|
+
* which tests ran before it.
|
|
43
46
|
*
|
|
44
47
|
* `provides.fabricator` is then that scope — the instance `wrap` gave its
|
|
45
48
|
* block, not the base instance — so `context.fabricator.salt` is the per-test
|
|
@@ -3,8 +3,8 @@ import type { PlainObject } from "../Utility/Types";
|
|
|
3
3
|
/**
|
|
4
4
|
* What identifies one registered test or suite — the material a salt is derived
|
|
5
5
|
* from. Named to match how this codebase already talks about the concept:
|
|
6
|
-
* fabricator's own reproducibility guide reaches for `layer(...)` for "a
|
|
7
|
-
*
|
|
6
|
+
* fabricator's own reproducibility guide reaches for `layer(...)` for "a test's
|
|
7
|
+
* own name" — this is that identity, structured.
|
|
8
8
|
*
|
|
9
9
|
* Declared here rather than imported from `@ghostry/harness`, so neither
|
|
10
10
|
* package depends on the other — the same arrangement `Adapter`/`walk` already
|
|
@@ -5,12 +5,16 @@ import type { Ancestry, Frame, Stack } from "../Types";
|
|
|
5
5
|
* delegate to so neither can drift from the other. A carrier's own job is
|
|
6
6
|
* reduced to holding the chain in whatever way its runtime allows.
|
|
7
7
|
*
|
|
8
|
+
* A wrap governs the instance it was called on and that instance's ancestors,
|
|
9
|
+
* never its descendants: `governs` is a prefix test in that one direction.
|
|
8
10
|
* Order is preserved rather than reduced to the innermost match, because the
|
|
9
11
|
* count is `context.depth` and the innermost is just the last element.
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
12
|
+
*
|
|
13
|
+
* It filters the whole chain rather than walking in from the innermost frame
|
|
14
|
+
* and stopping at the first that does not govern the reader, because a
|
|
15
|
+
* governing frame can sit beneath one that does not: with `B`'s wrap open and
|
|
16
|
+
* `C`'s nested inside it, `B` must pass over `C`'s frame and still resolve
|
|
17
|
+
* against its own.
|
|
14
18
|
*/
|
|
15
19
|
export declare function toVisible(frames: ReadonlyArray<Frame>, ancestry: Ancestry): ReadonlyArray<Frame>;
|
|
16
20
|
/**
|
|
@@ -69,19 +69,19 @@ export type Token = symbol & {
|
|
|
69
69
|
* over that instance's `config`. One rule, so an instance's position and its
|
|
70
70
|
* configuration always agree about who its parent is.
|
|
71
71
|
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* resolve against neither's.
|
|
77
|
-
* of identity — two roots hold two separate carriers, so a `wrap` on one
|
|
78
|
-
* where the other's reads never look.
|
|
72
|
+
* {@link Stack.visible} tests whether the reader is the wrap's receiver or one
|
|
73
|
+
* of that receiver's ancestors — the reader's chain a prefix of the frame's. A
|
|
74
|
+
* parent's constructions resolve against a wrap entered on a child; a child's
|
|
75
|
+
* constructions do not resolve against a wrap entered on a parent. Two siblings
|
|
76
|
+
* resolve against neither's. The relation never crosses lineages, and not for
|
|
77
|
+
* want of identity — two roots hold two separate carriers, so a `wrap` on one
|
|
78
|
+
* pushes where the other's reads never look.
|
|
79
79
|
*/
|
|
80
80
|
export type Ancestry = readonly [Token, ...ReadonlyArray<Token>];
|
|
81
81
|
/**
|
|
82
82
|
* One active `wrap` — its resolved config plus the single `RandomSource` every
|
|
83
|
-
* build reached inside that `wrap` shares, whether reached implicitly (
|
|
84
|
-
*
|
|
83
|
+
* build reached inside that `wrap` shares, whether reached implicitly (the
|
|
84
|
+
* receiver and its ancestors consulting the frame) or explicitly
|
|
85
85
|
* (`scope.Fabricator`, the `Instance` passed to the block). Storing the scope's
|
|
86
86
|
* own already-built `source` here, rather than each consumer re-deriving one
|
|
87
87
|
* from `config`, keeps the two routes resolving against the _same_ source —
|
|
@@ -93,11 +93,12 @@ export type Ancestry = readonly [Token, ...ReadonlyArray<Token>];
|
|
|
93
93
|
* separate `salt`/`algorithm`/`clock` fields.
|
|
94
94
|
*
|
|
95
95
|
* `ancestry` is the **origin's** — the instance `wrap` was called on — not the
|
|
96
|
-
* scope's
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
96
|
+
* scope's, and {@link Stack.visible} governs that origin and its ancestors. Not
|
|
97
|
+
* load-bearing for who is governed: keyed on the scope, the frame would govern
|
|
98
|
+
* the same instances plus the scope itself, which resolves against this very
|
|
99
|
+
* `source` either way. What it decides is the scope's own `context.depth` — 0,
|
|
100
|
+
* since the scope is a descendant of the origin and not among those the frame
|
|
101
|
+
* governs.
|
|
101
102
|
*/
|
|
102
103
|
export type Frame = {
|
|
103
104
|
readonly config: Config<PlainObject>;
|
|
@@ -132,23 +133,21 @@ export type Stack = {
|
|
|
132
133
|
readonly asynchronous: boolean;
|
|
133
134
|
/**
|
|
134
135
|
* Every open frame `ancestry` may resolve against, outermost first: those
|
|
135
|
-
* whose
|
|
136
|
-
* The innermost visible frame — what a build or a `context`
|
|
137
|
-
* resolves against — is the last element, and the count is
|
|
136
|
+
* whose receiver this instance is, or is an ancestor of — this chain a prefix
|
|
137
|
+
* of the frame's. The innermost visible frame — what a build or a `context`
|
|
138
|
+
* read actually resolves against — is the last element, and the count is
|
|
139
|
+
* `context.depth`.
|
|
138
140
|
*
|
|
139
|
-
*
|
|
140
|
-
* the
|
|
141
|
-
*
|
|
142
|
-
* the outer one. Callers never filter themselves — `toVisible`
|
|
143
|
-
* (`Instance/Stack/Visible.ts`) is the single definition both carriers
|
|
144
|
-
* delegate to, so the rule cannot drift between them.
|
|
141
|
+
* Callers never filter themselves — `toVisible` (`Instance/Stack/Visible.ts`)
|
|
142
|
+
* is the single definition both carriers delegate to, so the rule cannot
|
|
143
|
+
* drift between them.
|
|
145
144
|
*/
|
|
146
145
|
visible(ancestry: Ancestry): ReadonlyArray<Frame>;
|
|
147
146
|
/**
|
|
148
147
|
* Append `frame`, run `block`, remove it in a `finally`, so a frame unwinds
|
|
149
|
-
* correctly even if `block` throws. Appends rather than replaces:
|
|
150
|
-
*
|
|
151
|
-
*
|
|
148
|
+
* correctly even if `block` throws. Appends rather than replaces: nested
|
|
149
|
+
* wraps are a chain, and {@link visible} reports every frame this reader is
|
|
150
|
+
* governed by, not only the innermost.
|
|
152
151
|
*/
|
|
153
152
|
enter<$Return>(frame: Frame, block: () => $Return): $Return;
|
|
154
153
|
};
|
|
@@ -188,11 +187,13 @@ export type Context = {
|
|
|
188
187
|
*/
|
|
189
188
|
scope(): Instance<PlainObject>;
|
|
190
189
|
/**
|
|
191
|
-
* How many frames
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
190
|
+
* How many frames currently govern this instance — 0 outside any. Genuine
|
|
191
|
+
* dynamic nesting depth, counted off the carrier rather than inferred from
|
|
192
|
+
* {@link Ancestry}: a wrap entered on a descendant is counted (this instance
|
|
193
|
+
* is an ancestor of that receiver), a wrap entered on a sibling or an
|
|
194
|
+
* ancestor is not, and entering two `wrap`s on one instance reads as 2 even
|
|
195
|
+
* though neither deepened anyone's ancestry. A wrap's own `scope` is a
|
|
196
|
+
* descendant of the receiver, so its depth inside that wrap is 0.
|
|
196
197
|
*/
|
|
197
198
|
readonly depth: number;
|
|
198
199
|
};
|
|
@@ -280,7 +281,7 @@ export interface Instance<$Registry extends PlainObject> extends Pick<RandomSour
|
|
|
280
281
|
/**
|
|
281
282
|
* `fork(overlay)`, made ambient for the synchronous extent of `block`: every
|
|
282
283
|
* `new Fabricator(...)`, `combinatorial(...)`, and `coverage(...)` reached
|
|
283
|
-
* inside — on this instance
|
|
284
|
+
* inside — on this instance, and on this instance's ancestors — resolves
|
|
284
285
|
* against the fork instead, with nothing threaded through. The fork is also
|
|
285
286
|
* passed to `block`: use it explicitly where that reads better, and
|
|
286
287
|
* _necessarily_ for any async work, which the ambient frame does not survive
|
|
@@ -294,11 +295,11 @@ export interface Instance<$Registry extends PlainObject> extends Pick<RandomSour
|
|
|
294
295
|
* bound outside, as a destructured `wrap` is. To compose onto whatever is
|
|
295
296
|
* active regardless of receiver, go through `context.scope().wrap(...)`.
|
|
296
297
|
*
|
|
297
|
-
* While the block runs, calls
|
|
298
|
-
* against the scope
|
|
299
|
-
*
|
|
300
|
-
*
|
|
301
|
-
*
|
|
298
|
+
* While the block runs, calls on this instance and its ancestors resolve
|
|
299
|
+
* against the scope. Calls on a descendant — a fork of this instance, or the
|
|
300
|
+
* wrap's own scope — draw that instance's own configuration; so does a
|
|
301
|
+
* sibling. The scope still shares one `RandomSource` with this instance
|
|
302
|
+
* inside the wrap, so ambient and explicit construction agree. See
|
|
302
303
|
* {@link Ancestry}.
|
|
303
304
|
*/
|
|
304
305
|
wrap<$Return, const $WrapRegistry extends PlainObject = $Registry>(overlay: Overlay<$WrapRegistry>, block: (scope: Instance<$WrapRegistry>) => $Return): $Return;
|