@ghostry/fabricator 0.0.1 → 0.0.3

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 (139) hide show
  1. package/README.md +18 -12
  2. package/dist/esm/Adapter/Core.js +3 -3
  3. package/dist/esm/Enumeration/Enumerate.js +16 -13
  4. package/dist/esm/Error/index.js +16 -8
  5. package/dist/esm/Fabricator/Constructor.js +12 -14
  6. package/dist/esm/Harnessing/Core.js +30 -0
  7. package/dist/esm/Harnessing/Salt.js +12 -0
  8. package/dist/esm/Harnessing/Types.js +1 -0
  9. package/dist/esm/Instance/Core.js +25 -41
  10. package/dist/esm/Instance/Stack/Async.js +10 -0
  11. package/dist/esm/Instance/Stack/Sync.js +16 -0
  12. package/dist/esm/Primitive/bigint/Registry.js +12 -12
  13. package/dist/esm/Primitive/boolean/Registry.js +2 -1
  14. package/dist/esm/Primitive/date/Registry.js +15 -14
  15. package/dist/esm/Primitive/null/Registry.js +2 -1
  16. package/dist/esm/Primitive/number/Registry.js +18 -17
  17. package/dist/esm/Primitive/recursive/Fabricator.js +1 -1
  18. package/dist/esm/Primitive/symbol/Registry.js +2 -1
  19. package/dist/esm/Primitive/undefined/Registry.js +2 -1
  20. package/dist/esm/Random/index.js +24 -79
  21. package/dist/esm/Utility/Core.js +6 -1
  22. package/dist/esm/adapting.js +2 -0
  23. package/dist/esm/harnessing.js +1 -0
  24. package/dist/esm/index.js +5 -4
  25. package/dist/esm/internal.js +2 -2
  26. package/dist/types/Adapter/Core.d.ts +30 -33
  27. package/dist/types/Adapter/Types.d.ts +78 -88
  28. package/dist/types/Bound.d.ts +15 -15
  29. package/dist/types/Distribution/index.d.ts +54 -61
  30. package/dist/types/Enumeration/Enumerate.d.ts +24 -24
  31. package/dist/types/Enumeration/Plan.d.ts +22 -26
  32. package/dist/types/Enumeration/Types.d.ts +38 -43
  33. package/dist/types/Error/index.d.ts +103 -89
  34. package/dist/types/Fabricator/Constructor.d.ts +24 -26
  35. package/dist/types/Fabricator/Types.d.ts +73 -81
  36. package/dist/types/Harnessing/Core.d.ts +43 -0
  37. package/dist/types/Harnessing/Salt.d.ts +31 -0
  38. package/dist/types/Harnessing/Types.d.ts +79 -0
  39. package/dist/types/Instance/Core.d.ts +38 -74
  40. package/dist/types/Instance/Stack/Async.d.ts +14 -0
  41. package/dist/types/Instance/Stack/Sync.d.ts +14 -0
  42. package/dist/types/Instance/Types.d.ts +98 -102
  43. package/dist/types/Primitive/always/Schema.d.ts +8 -8
  44. package/dist/types/Primitive/always/Types.d.ts +7 -7
  45. package/dist/types/Primitive/array/Registry.d.ts +10 -8
  46. package/dist/types/Primitive/array/Schema.d.ts +4 -5
  47. package/dist/types/Primitive/array/Types.d.ts +6 -6
  48. package/dist/types/Primitive/bigint/Registry.d.ts +6 -6
  49. package/dist/types/Primitive/bigint/Schema.d.ts +8 -8
  50. package/dist/types/Primitive/bigint/Types.d.ts +5 -5
  51. package/dist/types/Primitive/boolean/Outcomes.d.ts +8 -8
  52. package/dist/types/Primitive/boolean/Registry.d.ts +2 -12
  53. package/dist/types/Primitive/boolean/Schema.d.ts +8 -8
  54. package/dist/types/Primitive/boolean/Types.d.ts +3 -3
  55. package/dist/types/Primitive/choice/Fabricator.d.ts +6 -7
  56. package/dist/types/Primitive/choice/Registry.d.ts +13 -13
  57. package/dist/types/Primitive/choice/Schema.d.ts +6 -6
  58. package/dist/types/Primitive/choice/Types.d.ts +11 -11
  59. package/dist/types/Primitive/date/Registry.d.ts +25 -48
  60. package/dist/types/Primitive/date/Schema.d.ts +9 -10
  61. package/dist/types/Primitive/date/Types.d.ts +4 -4
  62. package/dist/types/Primitive/enum/Registry.d.ts +13 -13
  63. package/dist/types/Primitive/enum/Schema.d.ts +5 -5
  64. package/dist/types/Primitive/enum/Types.d.ts +17 -19
  65. package/dist/types/Primitive/namespace.d.ts +10 -10
  66. package/dist/types/Primitive/null/Registry.d.ts +2 -2
  67. package/dist/types/Primitive/null/Schema.d.ts +2 -2
  68. package/dist/types/Primitive/null/Types.d.ts +3 -3
  69. package/dist/types/Primitive/nullable/Fabricator.d.ts +7 -7
  70. package/dist/types/Primitive/nullable/Schema.d.ts +13 -13
  71. package/dist/types/Primitive/nullable/Types.d.ts +9 -10
  72. package/dist/types/Primitive/nullish/Fabricator.d.ts +12 -13
  73. package/dist/types/Primitive/nullish/Schema.d.ts +8 -8
  74. package/dist/types/Primitive/nullish/Types.d.ts +12 -13
  75. package/dist/types/Primitive/number/Registry.d.ts +20 -38
  76. package/dist/types/Primitive/number/Schema.d.ts +11 -12
  77. package/dist/types/Primitive/number/Types.d.ts +13 -13
  78. package/dist/types/Primitive/number/defaults.d.ts +3 -3
  79. package/dist/types/Primitive/object/Fabricator.d.ts +15 -15
  80. package/dist/types/Primitive/object/Registry.d.ts +8 -8
  81. package/dist/types/Primitive/object/Schema.d.ts +10 -10
  82. package/dist/types/Primitive/object/Types.d.ts +20 -22
  83. package/dist/types/Primitive/object/compute/Fabricator.d.ts +4 -5
  84. package/dist/types/Primitive/object/compute/Schema.d.ts +4 -4
  85. package/dist/types/Primitive/object/compute/Types.d.ts +19 -20
  86. package/dist/types/Primitive/object/omittable/Fabricator.d.ts +10 -10
  87. package/dist/types/Primitive/object/omittable/Outcomes.d.ts +2 -2
  88. package/dist/types/Primitive/object/omittable/Schema.d.ts +11 -11
  89. package/dist/types/Primitive/object/omittable/Types.d.ts +14 -15
  90. package/dist/types/Primitive/object/optional/Fabricator.d.ts +16 -18
  91. package/dist/types/Primitive/object/optional/Outcomes.d.ts +2 -2
  92. package/dist/types/Primitive/object/optional/Schema.d.ts +4 -4
  93. package/dist/types/Primitive/object/optional/Types.d.ts +17 -17
  94. package/dist/types/Primitive/opaque/Registry.d.ts +3 -3
  95. package/dist/types/Primitive/opaque/Schema.d.ts +8 -9
  96. package/dist/types/Primitive/record/Registry.d.ts +8 -6
  97. package/dist/types/Primitive/record/Schema.d.ts +9 -11
  98. package/dist/types/Primitive/record/Types.d.ts +25 -25
  99. package/dist/types/Primitive/recursive/Fabricator.d.ts +20 -21
  100. package/dist/types/Primitive/recursive/Registry.d.ts +6 -7
  101. package/dist/types/Primitive/recursive/Schema.d.ts +8 -8
  102. package/dist/types/Primitive/recursive/Terminate.d.ts +13 -14
  103. package/dist/types/Primitive/recursive/Types.d.ts +31 -31
  104. package/dist/types/Primitive/recursive/self/Fabricator.d.ts +11 -12
  105. package/dist/types/Primitive/recursive/self/Schema.d.ts +10 -10
  106. package/dist/types/Primitive/recursive/self/Types.d.ts +7 -8
  107. package/dist/types/Primitive/string/Constants.d.ts +12 -13
  108. package/dist/types/Primitive/string/Fabricator.d.ts +2 -2
  109. package/dist/types/Primitive/string/Registry.d.ts +10 -16
  110. package/dist/types/Primitive/string/Schema.d.ts +5 -5
  111. package/dist/types/Primitive/string/Types.d.ts +17 -17
  112. package/dist/types/Primitive/symbol/Fabricator.d.ts +2 -2
  113. package/dist/types/Primitive/symbol/Registry.d.ts +4 -11
  114. package/dist/types/Primitive/symbol/Schema.d.ts +6 -6
  115. package/dist/types/Primitive/symbol/Types.d.ts +2 -2
  116. package/dist/types/Primitive/tuple/Fabricator.d.ts +7 -8
  117. package/dist/types/Primitive/tuple/Schema.d.ts +5 -5
  118. package/dist/types/Primitive/tuple/Types.d.ts +24 -25
  119. package/dist/types/Primitive/undefinable/Fabricator.d.ts +7 -7
  120. package/dist/types/Primitive/undefinable/Schema.d.ts +13 -13
  121. package/dist/types/Primitive/undefinable/Types.d.ts +10 -10
  122. package/dist/types/Primitive/undefined/Registry.d.ts +2 -2
  123. package/dist/types/Primitive/undefined/Schema.d.ts +4 -4
  124. package/dist/types/Primitive/undefined/Types.d.ts +3 -3
  125. package/dist/types/Random/Generator/sfc32.d.ts +4 -4
  126. package/dist/types/Random/Types.d.ts +151 -293
  127. package/dist/types/Random/index.d.ts +56 -81
  128. package/dist/types/Schema/Core.d.ts +19 -21
  129. package/dist/types/Schema/Registry.d.ts +3 -3
  130. package/dist/types/Schema/Types.d.ts +41 -48
  131. package/dist/types/Types.d.ts +39 -45
  132. package/dist/types/Utility/Core.d.ts +18 -9
  133. package/dist/types/adapting.d.ts +32 -0
  134. package/dist/types/harnessing.d.ts +30 -0
  135. package/dist/types/index.d.ts +95 -128
  136. package/dist/types/internal.d.ts +53 -40
  137. package/package.json +39 -7
  138. package/dist/esm/Random/CallSite.js +0 -56
  139. package/dist/types/Random/CallSite.d.ts +0 -59
@@ -0,0 +1,43 @@
1
+ import type { Instance } from "../Instance/Types";
2
+ import type { PlainObject } from "../Utility/Types";
3
+ import type { FabricatorTestContext, Integration } from "./Types";
4
+ /**
5
+ * Decorate an existing `Instance` as a `@ghostry/harness` integration.
6
+ * `around(identity, body)` is `instance.wrap({ salt: layer(saltFor(identity))
7
+ * })` — one line of real work. Construction ordinals therefore restart per test
8
+ * (each `wrap` re-instantiates), which is what makes `.only`, filters, shards,
9
+ * and `.concurrent` unable to shift a neighbor's data. That per-test
10
+ * partitioning is also why the salt needs no file in it; see `saltFor`
11
+ * (`Harnessing/Salt.ts`).
12
+ *
13
+ * `around`, not `setup`: the ambient frame has to enclose the body, and only
14
+ * `around` does. Its `finally` running at the call boundary rather than at test
15
+ * settlement costs nothing here — there is no teardown, and the
16
+ * `AsyncLocalStorage` carrier keeps the frame alive across the body's `await`s
17
+ * regardless of when `wrap` returns. On the synchronous carrier an async body
18
+ * still raises `SynchronousStackError` from `wrap`. Declaring no `setup` also
19
+ * keeps `@ghostry/harness` on its uninstrumented path, where a synchronous
20
+ * assertion failure is reported at the user's own line.
21
+ *
22
+ * `provides.fabricator` hands back the scope `wrap` gave its block, not the
23
+ * base instance, so `context.fabricator.salt` is the per-test salt and
24
+ * `.fork()` forks from the test's configuration. The two calls meet through
25
+ * `scope`: set just before `body()`, read by the provider, restored in a
26
+ * `finally`. That is safe under `.concurrent` because `@ghostry/harness` runs a
27
+ * provider synchronously inside its own integration's `around` — no other test
28
+ * can enter between the write and the read, and the context object already
29
+ * holds the scope by the body's first `await`. Restoring rather than clearing
30
+ * keeps a nested `around` from dropping its parent's scope. A provider reached
31
+ * with no scope is a composer breaking that contract, and raises
32
+ * `HarnessingProviderError` rather than quietly providing the base instance.
33
+ *
34
+ * Nothing here reads `instance.context`. The integration is a pure function of
35
+ * the `Identity` it is handed and the instance it decorates, and never sets
36
+ * `clock`. A pinned `Date` (the recommended setup) and the wall-clock default
37
+ * are already concrete numbers by the time `overlay()` sees them, so they
38
+ * inherit through every `wrap` unchanged: salt varies per test, "now" does not.
39
+ * `clock: "derived"` is left alone on purpose — that policy's documented
40
+ * meaning is that the salt _is_ the reproducibility unit, so per-test clocks
41
+ * are the request honored, not a bug to override.
42
+ */
43
+ export declare function integration<$Registry extends PlainObject>(instance: Instance<$Registry>): Integration<FabricatorTestContext<$Registry>>;
@@ -0,0 +1,31 @@
1
+ import type { Identity } from "./Types";
2
+ /**
3
+ * The salt `integration` layers onto the instance for one `Identity`.
4
+ *
5
+ * [ <kind>, ...<describe names>, <name>, <row?> ]
6
+ *
7
+ * **No file, deliberately.** Every test body runs inside its own
8
+ * `instance.wrap`, which builds a fresh `RandomSource` with a fresh
9
+ * construction counter, so constructions are already partitioned per test.
10
+ * Identity comes from a path, never from an execution counter or a location
11
+ * that moves when a file does.
12
+ *
13
+ * The accepted cost: two tests with the same `kind`, describe path, and name in
14
+ * _different files_ share a salt and therefore draw the same data. Each is
15
+ * still deterministic. That is the same trade already made in dropping
16
+ * duplicate-path detection, and the fix is the ordinary one — give them
17
+ * distinguishable names.
18
+ *
19
+ * `kind` leads. Without it, an empty-named test collides with its enclosing
20
+ * suite scope: `path` never carries a leaf's own name, only its describes, and
21
+ * `name` is `""` for both a `"suite"` identity (by design — see `Identity`) and
22
+ * any test a user happens to name `""`, so at the same `path` the two arrays
23
+ * would otherwise be identical. `kind` does not disambiguate two suite
24
+ * identities that share a `path` (a `beforeAll` and an `afterAll` in one
25
+ * `describe`, say) — that collision is intentional, a suite's setup and
26
+ * teardown sharing one deterministic scope, and a caller who wants otherwise
27
+ * already has `instance.wrap(...)` inside the hook body.
28
+ *
29
+ * The row is appended only for `.each`.
30
+ */
31
+ export declare function saltFor(identity: Identity): ReadonlyArray<string>;
@@ -0,0 +1,79 @@
1
+ import type { Instance } from "../Instance/Types";
2
+ import type { PlainObject } from "../Utility/Types";
3
+ /**
4
+ * What identifies one registered test or suite — the material a salt is derived
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.
8
+ *
9
+ * Declared here rather than imported from `@ghostry/harness`, so neither
10
+ * package depends on the other — the same arrangement `Adapter`/`walk` already
11
+ * uses for schema adapters. Satisfied structurally.
12
+ *
13
+ * **Carries no file, deliberately.** Nothing here identifies where the test was
14
+ * registered, which is what lets `@ghostry/harness` skip stack walking entirely
15
+ * — see `saltFor` (`Harnessing/Salt.ts`) for why the file turned out to be
16
+ * redundant against per-test `wrap` partitioning. The consequence for the
17
+ * contract: an integration that genuinely needs the registering file cannot get
18
+ * it from here, and adding it back means solving the frame-skip problem for
19
+ * every wrapper between the user's `it(...)` and the integration. Worth
20
+ * revisiting only against a real requirement, not speculatively.
21
+ */
22
+ export type Identity = {
23
+ /**
24
+ * Disambiguates an empty-named test from its enclosing suite scope — `name`
25
+ * is `""` for both, and `path` never carries a leaf's own name. Two suite
26
+ * identities that share a `path` (`beforeAll` and `afterAll` in one
27
+ * `describe`) are not disambiguated by this: that collision is intentional
28
+ * (see `saltFor`, `Harnessing/Salt.ts`).
29
+ */
30
+ readonly kind: "test" | "suite";
31
+ /** Enclosing describe names, outer → inner. */
32
+ readonly path: ReadonlyArray<string>;
33
+ /** The test name; empty for a suite-scoped callback. */
34
+ readonly name: string;
35
+ /** `.each` row index (0-based), `undefined` when the test is not from `.each`. */
36
+ readonly row: number | undefined;
37
+ };
38
+ /**
39
+ * One context key's value, as a function of the test's `Identity` rather than a
40
+ * fixed value.
41
+ */
42
+ export type Provider<$Value> = (identity: Identity) => $Value;
43
+ /**
44
+ * The keys an integration contributes, and how each is produced. Homomorphic
45
+ * over `$Context`, so the context an integration contributes is read back out
46
+ * of this object's shape with no separate key declaration to keep in sync.
47
+ */
48
+ export type Provides<$Context extends object> = {
49
+ readonly [$Key in keyof $Context]: Provider<$Context[$Key]>;
50
+ };
51
+ /**
52
+ * What `integration(instance)` is, as `@ghostry/harness`'s `initialize` sees
53
+ * it. The subset of that package's contract this integration actually uses, not
54
+ * a copy of all of it: `@ghostry/harness` also accepts an optional `setup`,
55
+ * which fabricator has no teardown to put in, and an object lacking an optional
56
+ * member still satisfies the contract structurally. `around` is required here,
57
+ * though optional there, because this integration always declares it.
58
+ *
59
+ * `provides` is the _only_ source of context keys; `initialize` rejects a
60
+ * collision across integrations by reading `Object.keys(provides)`. Each
61
+ * provider runs inside its integration's `around`. `around` is generic in its
62
+ * return and must return the body's value unchanged: that is what makes async
63
+ * work and what lets frames nest.
64
+ */
65
+ export type Integration<$Context extends object> = {
66
+ readonly name: string;
67
+ readonly provides: Provides<$Context>;
68
+ around<$Return>(identity: Identity, body: () => $Return): $Return;
69
+ };
70
+ /**
71
+ * The slice of the test context `integration(instance)` contributes — one key,
72
+ * `fabricator`, holding the per-test scoped `Instance`. The same instance is
73
+ * also ambient for the body's duration (`instance.wrap`), so a body that
74
+ * ignores this and uses the caller's own `instance` still sees the per-test
75
+ * salt.
76
+ */
77
+ export type FabricatorTestContext<$Registry extends PlainObject = PlainObject> = {
78
+ readonly fabricator: Instance<$Registry>;
79
+ };
@@ -2,95 +2,59 @@ import type { RandomSource } from "../Random/Types";
2
2
  import type { PlainObject } from "../Utility/Types";
3
3
  import type { Config, Instance, Overlay, Stack } from "./Types";
4
4
  /**
5
- * `combinatorial`'s default limit — `2**10`, so it admits ten
6
- * independent binary axes before requiring the caller to raise it
7
- * explicitly. Each enumerated instance costs a full build and
8
- * fabricate, so this is as much a wall-clock guard as a combinatorial
9
- * one.
5
+ * `combinatorial`'s default limit — `2**10`, so it admits ten independent
6
+ * binary axes before requiring the caller to raise it explicitly. Each
7
+ * enumerated instance costs a full build and fabricate, so this is as much a
8
+ * wall-clock guard as a combinatorial one.
10
9
  */
11
10
  export declare const DEFAULT_COMBINATORIAL_LIMIT = 1024;
12
11
  /**
13
- * The single place a `Config` inherits from a base — `initialize` lays
14
- * its own config over an empty `{}` base (nothing to inherit, so every
15
- * field falls through to a hardcoded default: an empty seed, wall-clock
16
- * `clock`, the built-in algorithm, `resolveAttribution(undefined)`'s
17
- * `"call site"` resolution, the default registry, the default
18
- * combinatorial limit), and `fork` lays its overlay over the instance
19
- * it was called on (a full, already-resolved `Config`, so every field
20
- * has a real value to fall back to). `base` is typed
21
- * `Partial<Config<PlainObject>>` rather than `Config` specifically so
22
- * both calls go through the same function.
12
+ * The single place a `Config` inherits from a base — `initialize` lays its own
13
+ * config over an empty `{}` base (nothing to inherit, so every field falls
14
+ * through to a hardcoded default: an empty salt, wall-clock `clock`, the
15
+ * built-in algorithm, the default registry, the default combinatorial limit),
16
+ * and `fork` lays its overlay over the instance it was called on (a full,
17
+ * already-resolved `Config`, so every field has a real value to fall back to).
18
+ * `base` is typed `Partial<Config<PlainObject>>` rather than `Config`
19
+ * specifically so both calls go through the same function.
23
20
  *
24
- * `seed` composes onto the base rather than replacing it only when
25
- * tagged with `layer(...)` (`{@link isLayered}`) — a bare `seed` (the
26
- * ordinary meaning everywhere else in this library) replaces the
27
- * base's outright, and an omitted `seed` inherits the base's unchanged
28
- * (or, at the root, an empty mixer via `normalizeSeed(undefined)`,
29
- * unless an env var supplies one). Wall-clock `clock` is the default
30
- * entropy; `seed` is an optional mixer.
31
- *
32
- * `attribution` resolves through `resolveAttribution` at most once per
33
- * call, and only when it's actually needed:
34
- * - an explicit `over.attribution` always wins (resolved fresh, so
35
- * `fork({ attribution: { kind: "call site" } })` roots at *that*
36
- * call);
37
- * - otherwise an already-resolved `base.attribution` is reused as-is
38
- * — never re-resolved, which keeps a fork from silently re-rooting
39
- * `"call site"` at wherever `fork()` itself happens to be called
40
- * (`resolveCallerFile()` skips this library's own frames, so calling
41
- * it from here still lands on the user's call site either way);
42
- * - only when neither is available (the root case, `base.attribution`
43
- * absent) does this fall back to resolving the `"call site"`
44
- * default.
45
- * That also keeps `initialize({ attribution: { kind: "none" } })` — or
46
- * any other explicit override — from paying for a stack walk whose
47
- * result would be immediately discarded.
21
+ * `salt` composes onto the base rather than replacing it only when tagged with
22
+ * `layer(...)` (`{@link isLayered}`) — a bare `salt` (the ordinary meaning
23
+ * everywhere else in this library) replaces the base's outright, and an omitted
24
+ * `salt` inherits the base's unchanged (or, at the root, an empty mixer via
25
+ * `normalizeSalt(undefined)`, unless an env var supplies one). Wall-clock
26
+ * `clock` is the default entropy; `salt` is an optional mixer.
48
27
  *
49
28
  * `algorithm`/`types`: wholesale replacement when given, matching how
50
29
  * `initialize({ types })` already behaves — no deep merge;
51
30
  * `registry.extend(...)` is the existing tool for that. `limits` is
52
31
  * re-validated through `resolveCombinatorialLimit` whenever given (or
53
- * inherited, or defaulted), so a bad limit fails at
54
- * `fork()`/`initialize()` time rather than at first use. `clock`
55
- * follows the given → inherited → default shape `algorithm` does, but
56
- * stays *unresolved* only for the explicit `"seeded"` sentinel: an
57
- * explicit `Date` and the unconfigured wall-clock default are stored
58
- * as epoch milliseconds (a stated instant, inherited as-is from then
59
- * on), while `"seeded"` is left as the sentinel rather than collapsed
60
- * to a number, so `resolveClock` can re-derive it from whichever
61
- * `seed` is actually in effect at read time. An omitted `clock` on a
62
- * `fork`/`wrap` whose seed changed therefore keeps the parent's
63
- * instant unless that parent was itself `"seeded"`.
32
+ * inherited, or defaulted), so a bad limit fails at `fork()`/`initialize()`
33
+ * time rather than at first use. `clock` follows the given → inherited →
34
+ * default shape `algorithm` does, but stays _unresolved_ only for the explicit
35
+ * `"derived"` sentinel: an explicit `Date` and the unconfigured wall-clock
36
+ * default are stored as epoch milliseconds (a stated instant, inherited as-is
37
+ * from then on), while `"derived"` is left as the sentinel rather than
38
+ * collapsed to a number, so `resolveClock` can re-derive it from whichever
39
+ * `salt` is actually in effect at read time. An omitted `clock` on a
40
+ * `fork`/`wrap` whose salt changed therefore keeps the parent's instant unless
41
+ * that parent was itself `"derived"`.
64
42
  */
65
43
  export declare function overlay<$Registry extends PlainObject>(base: Partial<Config<PlainObject>>, over: Overlay<$Registry>): Config<$Registry>;
66
- /**
67
- * Builds a `Stack`: closes over a private `Frame[]`, pushing on `enter`
68
- * and popping in a `finally` — correct even around a `throw` from
69
- * `block`. One per root `initialize()`, threaded — never re-created —
70
- * through every `fork`/`wrap` descended from it, so it stays
71
- * per-lineage rather than module-level: two unrelated `initialize()`
72
- * calls each get their own stack and can never perturb each other,
73
- * while every instance sharing one stack (a fork included, no matter
74
- * where in the lineage it was created) resolves against the same
75
- * active frame.
76
- */
77
- export declare function toStack(): Stack;
78
44
  /**
79
45
  * The shared body `initialize` and `fork` both reduce to: build a
80
46
  * `RandomSource` from an already-resolved `Config`, then everything an
81
- * `Instance` exposes off of it. Returns the `RandomSource` alongside
82
- * the `Instance` — `initialize`/`fork` discard it, `wrap` keeps it to
83
- * stash on the `Frame` it pushes, so implicit (ambient) and explicit
84
- * (`scope.Fabricator`) construction inside one `wrap` resolve against
85
- * the very same source rather than each independently re-deriving one
86
- * from the same config (and so silently diverging/duplicating
87
- * construction ordinals).
47
+ * `Instance` exposes off of it. Returns the `RandomSource` alongside the
48
+ * `Instance` — `initialize`/`fork` discard it, `wrap` keeps it to stash on the
49
+ * `Frame` it pushes, so implicit (ambient) and explicit (`scope.Fabricator`)
50
+ * construction inside one `wrap` resolve against the very same source rather
51
+ * than each independently re-deriving one from the same config (and so silently
52
+ * diverging/duplicating construction ordinals).
88
53
  *
89
- * `stack` is threaded straight through to `Constructor`/`enumerables`
90
- * — this function never reads or writes it itself, only passes it
91
- * along so every built `Fabricator`/`combinatorial`/`coverage` can
92
- * consult whichever frame is active *at the moment each is called*,
93
- * not at this moment.
54
+ * `stack` is threaded straight through to `Constructor`/`enumerables` — this
55
+ * function never reads or writes it itself, only passes it along so every built
56
+ * `Fabricator`/`combinatorial`/`coverage` can consult whichever frame is active
57
+ * _at the moment each is called_, not at this moment.
94
58
  */
95
59
  export declare function instantiate<$Registry extends PlainObject>(config: Config<$Registry>, stack: Stack): {
96
60
  instance: Instance<$Registry>;
@@ -0,0 +1,14 @@
1
+ import type { Stack } from "../Types";
2
+ /**
3
+ * The asynchronous carrier, and the **only** module in this package importing
4
+ * anything from `node:`. Nothing imports it directly: `Instance/Core.ts`
5
+ * imports `#stack`, whose `node`/`bun`/`deno` conditions (`package.json`)
6
+ * resolve here while `default` resolves to `./sync.ts`. That is what keeps the
7
+ * package importable on a runtime with no `node:async_hooks` while every
8
+ * runtime that has one gets async-safe `wrap` with nothing to configure.
9
+ *
10
+ * `AsyncLocalStorage.run` returns whatever `block` returns, so this satisfies
11
+ * `enter`'s sync-preserving `<$Return>` signature exactly as the sync carrier
12
+ * does — a synchronous `wrap` is unaffected by which carrier is in play.
13
+ */
14
+ export declare function toStack(): Stack;
@@ -0,0 +1,14 @@
1
+ import type { Stack } from "../Types";
2
+ /**
3
+ * The synchronous carrier: a private `Frame[]`, pushed on `enter` and popped in
4
+ * a `finally` — correct even around a `throw` from `block`.
5
+ *
6
+ * Selected by the `#stack` `default` condition (`package.json`), i.e. on any
7
+ * runtime without `node:async_hooks` — in practice a browser bundle. Its frame
8
+ * cannot survive an `await`: `enter` returns `block()` without awaiting, so an
9
+ * async block's frame unwinds at the block's first suspension point, and a
10
+ * shared LIFO could not represent two overlapping scopes even if it did await.
11
+ * Both are why `asynchronous` is `false` and `wrap` refuses an async block here
12
+ * rather than resolving it against the base instance with no signal.
13
+ */
14
+ export declare function toStack(): Stack;
@@ -1,85 +1,85 @@
1
1
  import type { Enumerable, Limits } from "../Enumeration/Types";
2
2
  import type { Constructor } from "../Fabricator/Constructor";
3
- import type { Algorithm, Attribution, Layered, RandomSource, Seed } from "../Random/Types";
3
+ import type { Algorithm, Layered, RandomSource, Salt } from "../Random/Types";
4
4
  import type { PlainObject } from "../Utility/Types";
5
5
  /**
6
- * A fully resolved instance configuration — every field present, nothing
7
- * left to default. `Overlay` is what `fork` accepts; `overlay()`
6
+ * A fully resolved instance configuration — every field present, nothing left
7
+ * to default. `Overlay` is what `fork` accepts; `overlay()`
8
8
  * (`Instance/Core.ts`) is the only thing producing a complete `Config`.
9
9
  *
10
- * Two fields are declared at their caller-facing type but always hold
11
- * their resolved form once `overlay()` has run: `seed` is `Seed` because
12
- * that is what a caller may supply, but always holds the normalized
13
- * array (`Instance.seed` is the authoritative read); `attribution` is
14
- * `Attribution` for the same reason but always holds a
15
- * `ResolvedAttribution`, a subtype. `clock` is different from both:
16
- * unlike `seed`/`attribution`, it holds *either* a resolved instant
17
- * (epoch milliseconds) or the unresolved `"seeded"` policy — never
18
- * collapsed to a number by `overlay()` when `"seeded"`, because that
19
- * policy must re-derive whenever the seed it composes changes (a
20
- * `fork({ seed: layer(...) })`). The unconfigured default is a wall-
21
- * clock number, inherited as-is like an explicit `Date`. `resolveClock`
22
- * (`Instance/Core.ts`) is the one place that resolves `"seeded"` to a
23
- * number, called fresh wherever the clock actually matters
24
- * (`instantiate`, the `context.clock` getter) rather than once here.
10
+ * `salt` is declared at its caller-facing `Salt` type but always holds the
11
+ * normalized array once `overlay()` has run (`Instance.salt` is the
12
+ * authoritative read). `clock` holds _either_ a resolved instant (epoch
13
+ * milliseconds) or the unresolved `"derived"` policy — never collapsed to a
14
+ * number by `overlay()` when `"derived"`, because that policy must re-derive
15
+ * whenever the salt it composes changes (a `fork({ salt: layer(...) })`). The
16
+ * unconfigured default is a wall- clock number, inherited as-is like an
17
+ * explicit `Date`. `resolveClock` (`Instance/Core.ts`) is the one place that
18
+ * resolves `"derived"` to a number, called fresh wherever the clock actually
19
+ * matters (`instantiate`, the `context.clock` getter) rather than once here.
25
20
  */
26
21
  export type Config<$Registry extends PlainObject> = {
27
- readonly seed: Seed;
22
+ readonly salt: Salt;
28
23
  readonly algorithm: Algorithm;
29
- readonly attribution: Attribution;
30
24
  readonly types: $Registry;
31
25
  readonly limits: Limits;
32
- readonly clock: number | "seeded";
26
+ readonly clock: number | "derived";
33
27
  };
34
28
  /**
35
- * What `fork` accepts — a `Config` to lay over a base, every field
36
- * optional. Identical to `Partial<Config>` but for `seed`, which
37
- * additionally accepts a {@link Layered}: a bare `Seed` replaces the
38
- * base's seed outright (what `seed` means everywhere else in this
39
- * library), `layer(seed)` appends onto it (`[...base.seed, ...seed]`)
40
- * — the shape a wrapping integration wants, and what
41
- * `ConstructorOptions`' layered form is for a single construction.
42
- * Omitting `seed` inherits the base's unchanged. `clock` similarly
43
- * accepts the caller-facing `Date | "seeded"` rather than `Config`'s
44
- * own resolved `number | "seeded"`, so a caller can hand in a literal
45
- * instant without converting it to epoch milliseconds themselves.
46
- * `"seeded"` is the explicit opt-in that derives "now" from the
47
- * instance seed; omitting `clock` at the root captures wall-clock time
48
- * instead.
29
+ * What `fork` accepts — a `Config` to lay over a base, every field optional.
30
+ * Identical to `Partial<Config>` but for `salt`, which additionally accepts a
31
+ * {@link Layered}: a bare `Salt` replaces the base's salt outright (what `salt`
32
+ * means everywhere else in this library), `layer(salt)` appends onto it
33
+ * (`[...base.salt, ...salt]`) — the shape a wrapping integration wants, and
34
+ * what `ConstructorOptions`' layered form is for a single construction.
35
+ * Omitting `salt` inherits the base's unchanged. `clock` similarly accepts the
36
+ * caller-facing `Date | "derived"` rather than `Config`'s own resolved `number
37
+ * | "derived"`, so a caller can hand in a literal instant without converting it
38
+ * to epoch milliseconds themselves. `"derived"` is the explicit opt-in that
39
+ * derives "now" from the instance salt; omitting `clock` at the root captures
40
+ * wall-clock time instead.
49
41
  *
50
- * `initialize`'s own parameter keeps a plain `seed?: Seed`, so passing
51
- * `layer(...)` there is a compile error: there is no base to layer onto
52
- * at the root.
42
+ * `initialize`'s own parameter keeps a plain `salt?: Salt`, so passing
43
+ * `layer(...)` there is a compile error: there is no base to layer onto at the
44
+ * root.
53
45
  */
54
- export type Overlay<$Registry extends PlainObject> = Partial<Omit<Config<$Registry>, "seed" | "clock">> & {
55
- readonly seed?: Seed | Layered;
56
- readonly clock?: Date | "seeded" | undefined;
46
+ export type Overlay<$Registry extends PlainObject> = Partial<Omit<Config<$Registry>, "salt" | "clock">> & {
47
+ readonly salt?: Salt | Layered;
48
+ readonly clock?: Date | "derived" | undefined;
57
49
  };
58
50
  /**
59
- * One active `wrap` — its resolved config plus the single `RandomSource`
60
- * every build reached inside that `wrap` shares, whether reached
61
- * implicitly (any instance in the lineage consulting the active frame)
62
- * or explicitly (`scope.Fabricator`, the `Instance` passed to the
63
- * block). Storing the scope's own already-built `source` here, rather
64
- * than each consumer re-deriving one from `config`, keeps the two
65
- * routes resolving against the *same* source — sharing one set of
66
- * construction-ordinal counters — instead of each silently starting
67
- * its own.
51
+ * One active `wrap` — its resolved config plus the single `RandomSource` every
52
+ * build reached inside that `wrap` shares, whether reached implicitly (any
53
+ * instance in the lineage consulting the active frame) or explicitly
54
+ * (`scope.Fabricator`, the `Instance` passed to the block). Storing the scope's
55
+ * own already-built `source` here, rather than each consumer re-deriving one
56
+ * from `config`, keeps the two routes resolving against the _same_ source —
57
+ * sharing one set of construction-ordinal counters — instead of each silently
58
+ * starting its own.
68
59
  */
69
60
  export type Frame = {
70
61
  readonly config: Config<PlainObject>;
71
62
  readonly source: RandomSource;
72
63
  };
73
64
  /**
74
- * The per-lineage ambient stack. Created once at a root `initialize()`
75
- * and threaded — never re-created — through every `fork`/`wrap`
76
- * descended from it (see `instantiate`, `Instance/Core.ts`). Two
77
- * unrelated `initialize()` calls stay fully isolated; one lineage's
78
- * `wrap` reaches every instance in that lineage — its `Fabricator`,
79
- * `combinatorial`, and `coverage` alike — regardless of where in the
80
- * lineage that instance was itself created.
65
+ * The per-lineage ambient stack. Created once at a root `initialize()` and
66
+ * threaded — never re-created — through every `fork`/`wrap` descended from it
67
+ * (see `instantiate`, `Instance/Core.ts`). Two unrelated `initialize()` calls
68
+ * stay fully isolated; one lineage's `wrap` reaches every instance in that
69
+ * lineage — its `Fabricator`, `combinatorial`, and `coverage` alike —
70
+ * regardless of where in the lineage that instance was itself created.
81
71
  */
82
72
  export type Stack = {
73
+ /**
74
+ * Whether a frame survives an `await` inside the block it was entered for.
75
+ *
76
+ * `false` means the carrier is a plain LIFO whose frame unwinds at the
77
+ * block's first suspension point — correct for synchronous use, and the
78
+ * reason `wrap` (`Instance/Core.ts`) rejects an async block outright rather
79
+ * than letting a build after the `await` silently resolve against the base
80
+ * instance. See `Instance/Stack/Sync.ts` and `Instance/Stack/Async.ts`.
81
+ */
82
+ readonly asynchronous: boolean;
83
83
  current(): Frame | undefined;
84
84
  /**
85
85
  * Push `frame`, run `block`, pop — in a `finally`, so a frame unwinds
@@ -88,80 +88,76 @@ export type Stack = {
88
88
  enter<$Return>(frame: Frame, block: () => $Return): $Return;
89
89
  };
90
90
  /**
91
- * The configuration in effect *right now* — the innermost active `wrap`
92
- * frame, or this instance's own when there is none. Distinct from
93
- * `ConstructionContext` (`Fabricator/Types.ts`), which is one
94
- * construction's internal dispatch plumbing; this is the caller-facing
95
- * "what configuration is in effect."
91
+ * The configuration in effect _right now_ — the innermost active `wrap` frame,
92
+ * or this instance's own when there is none. Distinct from
93
+ * `ConstructionContext` (`Fabricator/Types.ts`), which is one construction's
94
+ * internal dispatch plumbing; this is the caller-facing "what configuration is
95
+ * in effect."
96
96
  */
97
97
  export type Context = {
98
- readonly seed: ReadonlyArray<string>;
98
+ readonly salt: ReadonlyArray<string>;
99
99
  readonly algorithm: Algorithm;
100
- readonly attribution: Attribution;
101
100
  readonly clock: number;
102
101
  };
103
102
  /**
104
- * A single initialized library instance: the registry it was given, and
105
- * a `construct()` bound to its own isolated randomness — its own seed,
106
- * builder, and per-file overrides/streams, held internally and never
107
- * shared with any other `initialize()` call. Independently initialized
108
- * instances (e.g. parallel tests) can never perturb each other.
103
+ * A single initialized library instance: the registry it was given, and a
104
+ * `construct()` bound to its own isolated randomness — its own salt, builder,
105
+ * and construction counter/streams, held internally and never shared with any
106
+ * other `initialize()` call. Independently initialized instances (e.g. parallel
107
+ * tests) can never perturb each other.
109
108
  */
110
- export interface Instance<$Registry extends PlainObject> extends Pick<RandomSource, "seed"> {
109
+ export interface Instance<$Registry extends PlainObject> extends Pick<RandomSource, "salt"> {
111
110
  /** The registry of type definers this instance was initialized with. */
112
111
  readonly T: $Registry;
113
112
  /**
114
113
  * Turn a Schema built from `T` into a live Fabricator, deriving fresh
115
- * randomness from this instance's own seed for whichever leaves
116
- * actually need it.
114
+ * randomness from this instance's own salt for whichever leaves actually need
115
+ * it.
117
116
  */
118
117
  Fabricator: Constructor;
119
118
  /**
120
- * Every combination of every enumerable node in `schema` — every enum
121
- * member, both sides of an optional field, and so on — as a cartesian
122
- * product, lazily. Throws eagerly, before producing anything, if the
123
- * count exceeds `limits.combinatorial` (see `initialize`'s config).
119
+ * Every combination of every enumerable node in `schema` — every enum member,
120
+ * both sides of an optional field, and so on — as a cartesian product,
121
+ * lazily. Throws eagerly, before producing anything, if the count exceeds
122
+ * `limits.combinatorial` (see `initialize`'s config).
124
123
  */
125
124
  combinatorial: Enumerable;
126
125
  /**
127
- * The minimum set of instances such that every option of every
128
- * enumerable node in `schema` appears at least once — count equal to
129
- * the *widest* single axis, not the product, with narrower axes
130
- * cycling to fill it. Unbounded: its count can never exceed the
131
- * schema as written, so unlike `combinatorial` it carries no limit.
126
+ * The minimum set of instances such that every option of every enumerable
127
+ * node in `schema` appears at least once — count equal to the _widest_ single
128
+ * axis, not the product, with narrower axes cycling to fill it. Unbounded:
129
+ * its count can never exceed the schema as written, so unlike `combinatorial`
130
+ * it carries no limit.
132
131
  */
133
132
  coverage: Enumerable;
134
133
  /**
135
134
  * Derive a new instance laid over this one: anything the overlay names
136
- * overrides, anything it omits inherits. A bare `seed` replaces this
137
- * instance's seed; `seed: layer(...)` appends onto it. A peer of an
138
- * `initialize()` return value in every respect, including its own
139
- * `fork`.
135
+ * overrides, anything it omits inherits. A bare `salt` replaces this
136
+ * instance's salt; `salt: layer(...)` appends onto it. A peer of an
137
+ * `initialize()` return value in every respect, including its own `fork`.
140
138
  */
141
139
  fork<const $ForkRegistry extends PlainObject = $Registry>(overlay?: Overlay<$ForkRegistry>): Instance<$ForkRegistry>;
142
140
  /**
143
- * `fork(overlay)`, made ambient for the synchronous extent of `block`:
144
- * every `new Fabricator(...)`, `combinatorial(...)`, and
145
- * `coverage(...)` reached inside — on this instance or any other in
146
- * the same lineage — resolves against the fork instead, with nothing
147
- * threaded through. The fork is also passed to `block`: use it
148
- * explicitly where that reads better, and *necessarily* for any async
149
- * work, which the ambient frame does not survive — a build reached
150
- * after an `await` inside `block` sees this instance's own
141
+ * `fork(overlay)`, made ambient for the synchronous extent of `block`: every
142
+ * `new Fabricator(...)`, `combinatorial(...)`, and `coverage(...)` reached
143
+ * inside — on this instance or any other in the same lineage — resolves
144
+ * against the fork instead, with nothing threaded through. The fork is also
145
+ * passed to `block`: use it explicitly where that reads better, and
146
+ * _necessarily_ for any async work, which the ambient frame does not survive
147
+ * — a build reached after an `await` inside `block` sees this instance's own
151
148
  * configuration again, not the wrap's.
152
149
  *
153
- * A nested `wrap` lays over whichever frame is currently active, not
154
- * over the instance it was called on — so `overlay.seed: layer(...)`
155
- * accumulates with nesting depth while a bare `seed` still replaces
156
- * outright, discarding every enclosing layer.
150
+ * A nested `wrap` lays over whichever frame is currently active, not over the
151
+ * instance it was called on — so `overlay.salt: layer(...)` accumulates with
152
+ * nesting depth while a bare `salt` still replaces outright, discarding every
153
+ * enclosing layer.
157
154
  */
158
155
  wrap<$Return, const $WrapRegistry extends PlainObject = $Registry>(overlay: Overlay<$WrapRegistry>, block: (scope: Instance<$WrapRegistry>) => $Return): $Return;
159
156
  /**
160
- * The configuration in effect right now: the innermost active `wrap`
161
- * frame's, or this instance's own outside any `wrap`. A live view, not
162
- * a snapshot — reflects whichever frame is active at the moment each
163
- * property is read, since one `Instance` outlives any number of
164
- * `wrap`s.
157
+ * The configuration in effect right now: the innermost active `wrap` frame's,
158
+ * or this instance's own outside any `wrap`. A live view, not a snapshot —
159
+ * reflects whichever frame is active at the moment each property is read,
160
+ * since one `Instance` outlives any number of `wrap`s.
165
161
  */
166
162
  readonly context: Context;
167
163
  }
@@ -2,17 +2,17 @@ import { type AdaptationEntry } from "../../Adapter/Core";
2
2
  import type { Adaptations, Adapter, Adapting, WithAdaptations } from "../../Adapter/Types";
3
3
  import type { Core, Value } from "./Types";
4
4
  /**
5
- * A fixed value, so unlike every other kind there is no `.as()` — nothing
6
- * left to override about producing it. `adapt` still applies: what a value
7
- * *means* to an external schema library is a separate question from what it
8
- * fabricates to, and for a value TypeBox cannot pin exactly (a `symbol`, or
9
- * any value's *static* type — see `Adapter/TypeBox`'s `toConst`) it is the
10
- * only way to close the gap.
5
+ * A fixed value, so unlike every other kind there is no `.as()` — nothing left
6
+ * to override about producing it. `adapt` still applies: what a value _means_
7
+ * to an external schema library is a separate question from what it fabricates
8
+ * to, and for a value TypeBox cannot pin exactly (a `symbol`, or any value's
9
+ * _static_ type — see `Adapter/TypeBox`'s `toConst`) it is the only way to
10
+ * close the gap.
11
11
  */
12
12
  export interface Schema<$Value extends Value = Value, $Adaptations extends Adaptations = {}> extends Core<$Value, $Adaptations> {
13
13
  /**
14
- * Override what this schema maps to in one or more external schema
15
- * libraries — see `string/Schema.ts`'s `adapt` for the full contract.
14
+ * Override what this schema maps to in one or more external schema libraries
15
+ * — see `string/Schema.ts`'s `adapt` for the full contract.
16
16
  */
17
17
  adapt: <const $Adapter extends Adapter, $Returnable extends ReturnType<$Adapter["convert"]>>(adapter: $Adapter, produce: (adapting: Adapting<Schema<$Value, $Adaptations>>) => $Returnable) => Schema<$Value, WithAdaptations<$Adaptations, AdaptationEntry<$Adapter, $Returnable>>>;
18
18
  }