@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 onDirectLine(a, b) {
2
- const shared = Math.min(a.length, b.length);
3
- for(let index = 0; index < shared; index++)if (a[index] !== b[index]) return false;
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)=>onDirectLine(frame.ancestry, ancestry));
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 frame that `wrap` pushes is keyed on the receiver's ancestry, so under
38
- * composition the per-test frame belongs to the enclosing scope's line: a
39
- * collateral `fork()` taken inside a test resolves against the outermost frame
40
- * on its own line instead. That is the ordinary ancestry rule — siblings never
41
- * see each other's frames, and the outward walk supplies the outer ones — not a
42
- * special case here.
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 tenant
7
- * id, a test's own name" — this is that identity, structured.
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
- * Skipping, rather than stopping at, the first invisible frame is the outward
11
- * walk: with a parent's `wrap` open and a child's nested inside it, that
12
- * child's sibling must pass over the inner frame and still resolve against the
13
- * outer one.
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
- * Two chains describe instances on the same ancestral line when either is a
73
- * prefix of the other, which is what {@link Stack.visible} tests. That relation
74
- * decides whose calls resolve against whose frames: a parent's calls resolve
75
- * against a child's frame and a child's against a parent's, while two siblings
76
- * resolve against neither's. Note this never crosses lineages, and not for want
77
- * of identity — two roots hold two separate carriers, so a `wrap` on one pushes
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 (any
84
- * instance on the origin's ancestral line consulting the frame) or explicitly
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. The scope is a fresh child of the origin, so keying on it would make
97
- * every `fork` taken off that origin a _sibling_ of the scope, and calls on
98
- * those forks would stop resolving against the frame. Keying on the origin
99
- * keeps everything on the origin's own line resolving against it, which is the
100
- * whole point of entering one.
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 own `ancestry` is a prefix of this one or has this one as a prefix.
136
- * The innermost visible frame — what a build or a `context` read actually
137
- * resolves against — is the last element, and the count is `context.depth`.
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
- * Filtering, rather than simply reporting the innermost frame, is what makes
140
- * the outward walk possible: with a parent's `wrap` open and a child's nested
141
- * inside it, the child's _sibling_ must skip the inner frame and still find
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: the chain
150
- * has to stay intact for {@link visible} to walk outward past a frame this
151
- * reader cannot see.
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 are currently visible to this instance — 0 outside any.
192
- * Genuine dynamic nesting depth, counted off the carrier rather than inferred
193
- * from {@link Ancestry}: a frame a sibling cannot see is not counted for that
194
- * sibling, and entering two `wrap`s on one instance reads as 2 even though
195
- * neither deepened anyone's ancestry.
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 or any other in the same lineage — resolves
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 made on this instance's ancestral line resolve
298
- * against the scope its forks, their forks, and its own ancestors up to the
299
- * root. Calls on a _sibling_ do not: a frame entered on one `fork` is not one
300
- * that another `fork` of the same parent can resolve against, which keeps two
301
- * unrelated derivations from drawing each other's data. See
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ghostry/fabricator",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "license": "MIT",
5
5
  "description": "Fabricate typed data from composable schemas.",
6
6
  "keywords": [