@ghostry/fabricator 0.0.2 → 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.
- package/README.md +18 -6
- package/dist/esm/Adapter/Core.js +3 -3
- package/dist/esm/Enumeration/Enumerate.js +16 -13
- package/dist/esm/Error/index.js +8 -8
- package/dist/esm/Fabricator/Constructor.js +12 -14
- package/dist/esm/Harnessing/Core.js +30 -0
- package/dist/esm/Harnessing/Salt.js +12 -0
- package/dist/esm/Harnessing/Types.js +1 -0
- package/dist/esm/Instance/Core.js +17 -24
- package/dist/esm/Primitive/recursive/Fabricator.js +1 -1
- package/dist/esm/Random/index.js +24 -79
- package/dist/esm/adapting.js +2 -0
- package/dist/esm/harnessing.js +1 -0
- package/dist/esm/index.js +1 -2
- package/dist/esm/internal.js +1 -2
- package/dist/types/Adapter/Core.d.ts +1 -1
- package/dist/types/Adapter/Types.d.ts +1 -1
- package/dist/types/Enumeration/Enumerate.d.ts +17 -15
- package/dist/types/Error/index.d.ts +15 -19
- package/dist/types/Fabricator/Constructor.d.ts +4 -4
- package/dist/types/Harnessing/Core.d.ts +43 -0
- package/dist/types/Harnessing/Salt.d.ts +31 -0
- package/dist/types/Harnessing/Types.d.ts +79 -0
- package/dist/types/Instance/Core.d.ts +14 -31
- package/dist/types/Instance/Types.d.ts +35 -41
- package/dist/types/Primitive/opaque/Registry.d.ts +1 -1
- package/dist/types/Primitive/recursive/Fabricator.d.ts +8 -8
- package/dist/types/Random/Types.d.ts +97 -217
- package/dist/types/Random/index.d.ts +30 -48
- package/dist/types/Types.d.ts +3 -3
- package/dist/types/adapting.d.ts +32 -0
- package/dist/types/harnessing.d.ts +30 -0
- package/dist/types/index.d.ts +40 -75
- package/dist/types/internal.d.ts +5 -23
- package/package.json +23 -3
- package/dist/esm/Random/CallSite.js +0 -70
- package/dist/types/Random/CallSite.d.ts +0 -78
package/dist/types/index.d.ts
CHANGED
|
@@ -1,46 +1,31 @@
|
|
|
1
1
|
import type { Limits } from "./Enumeration/Types";
|
|
2
2
|
import type { Instance, Stack } from "./Instance/Types";
|
|
3
|
-
import type { Algorithm,
|
|
3
|
+
import type { Algorithm, Salt } from "./Random/Types";
|
|
4
4
|
import { registry } from "./Schema/Registry";
|
|
5
5
|
import type { PlainObject } from "./Utility/Types";
|
|
6
6
|
export declare function initialize<const $Registry extends PlainObject = typeof registry>(config?: Partial<{
|
|
7
7
|
/** The registry of type definers to use — `registry` itself. */
|
|
8
8
|
types: $Registry;
|
|
9
9
|
/**
|
|
10
|
-
* Optional
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* `clock` is the default entropy, so an unconfigured
|
|
16
|
-
* and replays from `context.clock` alone. Pass a
|
|
17
|
-
* should share a clock but draw different
|
|
18
|
-
* "
|
|
10
|
+
* Optional differentiator composed into every stream beside `clock` — it
|
|
11
|
+
* distinguishes runs, it does not generate them. Accepts a single string,
|
|
12
|
+
* or several — several lets a salt be composed out of independent,
|
|
13
|
+
* meaningful parts (a user id, a scenario label) without hand-joining them
|
|
14
|
+
* first. If omitted, the salt is empty (unless `FABRICATOR_SALT` supplies
|
|
15
|
+
* one): wall-clock `clock` is the default entropy, so an unconfigured
|
|
16
|
+
* instance varies by run and replays from `context.clock` alone. Pass a
|
|
17
|
+
* salt when two instances should share a clock but draw different
|
|
18
|
+
* universes, or when `clock: "derived"` should make the salt itself the
|
|
19
|
+
* reproducibility unit.
|
|
19
20
|
*/
|
|
20
|
-
|
|
21
|
+
salt?: Salt;
|
|
21
22
|
/**
|
|
22
23
|
* Bring your own PRNG: a factory that, given a seed, returns a source of
|
|
23
24
|
* randomness — a `() => number` in `[0, 1)`, a drop-in for `Math.random`.
|
|
24
|
-
*
|
|
25
|
+
* The seed is a whole encoded trace, of which `salt` is one slot, not the
|
|
26
|
+
* `salt` itself. Defaults to the built-in `sfc32` generator.
|
|
25
27
|
*/
|
|
26
28
|
algorithm?: Algorithm;
|
|
27
|
-
/**
|
|
28
|
-
* How this instance attributes a construction's randomness to the file it
|
|
29
|
-
* was written in:
|
|
30
|
-
*
|
|
31
|
-
* - `{ kind: "rooted", root }` expresses every file relative to `root` (an
|
|
32
|
-
* absolute path or a `file://` URL), so the same seed reproduces the same
|
|
33
|
-
* data on a checkout at a different absolute path.
|
|
34
|
-
* - `{ kind: "call site" }`, the default, is `"rooted"` at the directory of
|
|
35
|
-
* whichever file called `initialize()`.
|
|
36
|
-
* - `{ kind: "none" }` attributes nothing: every construction of a given kind
|
|
37
|
-
* anywhere in the instance shares one stream, keyed by kind alone.
|
|
38
|
-
*
|
|
39
|
-
* See
|
|
40
|
-
* [Reproducibility](https://docs.ghostry.dev/fabricator/guides/reproducibility)
|
|
41
|
-
* for the trade-offs between the three.
|
|
42
|
-
*/
|
|
43
|
-
attribution?: Attribution;
|
|
44
29
|
/**
|
|
45
30
|
* Instance-wide numeric ceilings. `combinatorial` bounds how many instances
|
|
46
31
|
* `combinatorial(...)` may enumerate — the check is eager, it throws at
|
|
@@ -55,14 +40,14 @@ export declare function initialize<const $Registry extends PlainObject = typeof
|
|
|
55
40
|
* every leaf's trace, the default entropy for the instance. Defaults to the
|
|
56
41
|
* wall-clock instant of this `initialize()` call, so an unconfigured run
|
|
57
42
|
* has realistic dates and varies by process, and replays from
|
|
58
|
-
* `context.clock` (with the same empty or supplied `
|
|
59
|
-
* `Date` to freeze "now" (and the rest of the run, unless `
|
|
60
|
-
* differs). Pass `"
|
|
43
|
+
* `context.clock` (with the same empty or supplied `salt`). Pass a fixed
|
|
44
|
+
* `Date` to freeze "now" (and the rest of the run, unless `salt` also
|
|
45
|
+
* differs). Pass `"derived"` to derive "now" from the instance salt instead
|
|
61
46
|
* — an instant drawn across the whole representable `Date` span, so an
|
|
62
47
|
* implausible date is the expected outcome of that policy, not a bug.
|
|
63
|
-
* `"
|
|
48
|
+
* `"derived"` is what makes `salt` alone the reproducibility unit.
|
|
64
49
|
*/
|
|
65
|
-
clock?: Date | "
|
|
50
|
+
clock?: Date | "derived";
|
|
66
51
|
/**
|
|
67
52
|
* The ambient carrier backing `wrap` for this lineage — override only to
|
|
68
53
|
* force a specific one.
|
|
@@ -79,14 +64,14 @@ export declare function initialize<const $Registry extends PlainObject = typeof
|
|
|
79
64
|
}>): Instance<$Registry>;
|
|
80
65
|
export { Omitted } from "./Types";
|
|
81
66
|
/**
|
|
82
|
-
* Tags a `
|
|
83
|
-
* `Overlay.
|
|
67
|
+
* Tags a `Salt` — for `new Fabricator(schema, { salt })`, or `fork`'s own
|
|
68
|
+
* `Overlay.salt` — as composing onto whatever base is in effect, rather than
|
|
84
69
|
* replacing it outright.
|
|
85
70
|
*/
|
|
86
71
|
export { layer } from "./Random";
|
|
87
72
|
/**
|
|
88
73
|
* `layer(...)`'s return type, so a caller building one programmatically can
|
|
89
|
-
* name it — the same rationale as the existing `
|
|
74
|
+
* name it — the same rationale as the existing `Salt` export.
|
|
90
75
|
*/
|
|
91
76
|
export type { Layered } from "./Random/Types";
|
|
92
77
|
/**
|
|
@@ -95,25 +80,6 @@ export type { Layered } from "./Random/Types";
|
|
|
95
80
|
* subclasses are distinguished by `.name`.
|
|
96
81
|
*/
|
|
97
82
|
export { FabricatorError } from "./Error";
|
|
98
|
-
/**
|
|
99
|
-
* The adapter contract, exported because an adapter is a separate package
|
|
100
|
-
* rather than something registered here: `Adapter`/`Recurse` are what one
|
|
101
|
-
* declares, `drive` is what its conversion entry point calls, and
|
|
102
|
-
* `Adaptation`/`AdaptationsOf` are how it reads what a Schema declared —
|
|
103
|
-
* `[Adaptation]` at runtime, `AdaptationsOf` at the type level, keyed by its
|
|
104
|
-
* own `key` in both cases.
|
|
105
|
-
*
|
|
106
|
-
* This package names no external schema library and depends on none: every
|
|
107
|
-
* mapping, and every dependency it needs, belongs to the adapter.
|
|
108
|
-
*
|
|
109
|
-
* `Adapting` is the odd one out, facing whoever _writes_ an adaptation rather
|
|
110
|
-
* than whoever implements an adapter: it is the parameter type of every kind's
|
|
111
|
-
* `.adapt(adapter, produce)` producer, so a caller writing that producer as a
|
|
112
|
-
* named function can name it — the same reason `Stream` is exported below.
|
|
113
|
-
*/
|
|
114
|
-
export { drive } from "./Adapter/Core";
|
|
115
|
-
export type { Adaptations, AdaptationsOf, Adapter, Adapting, Recurse, } from "./Adapter/Types";
|
|
116
|
-
export { Adaptation } from "./Types";
|
|
117
83
|
/**
|
|
118
84
|
* The default registry of type definers, exported so it can be extended via
|
|
119
85
|
* `registry.extend(({ T }) => ({ ... }))` before being passed to `initialize({
|
|
@@ -142,17 +108,23 @@ export type { Stream } from "./Random/Types";
|
|
|
142
108
|
*/
|
|
143
109
|
export type { ProduceContext } from "./Random/Types";
|
|
144
110
|
/**
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
111
|
+
* What every kind's `.adapt(adapter, produce)` producer is called with — `{
|
|
112
|
+
* schema, meta }` — the same rationale as `Stream`/`ProduceContext` above: a
|
|
113
|
+
* caller writing the producer as a named function can name its parameter.
|
|
114
|
+
* `meta` is the kind's own config, reachable here without importing the `Meta`
|
|
115
|
+
* well-known symbol from `@ghostry/fabricator/internal` — that symbol stays off
|
|
116
|
+
* the path an ordinary caller writing an `.adapt()` call has to walk. The rest
|
|
117
|
+
* of the adapter contract (`walk`, `Adapter`, `Adaptation`, `Adaptations`,
|
|
118
|
+
* `AdaptationsOf`, `Recurse`) is exported from `@ghostry/fabricator/adapting`
|
|
119
|
+
* instead — surface for implementing an adapter, not for calling `.adapt()`.
|
|
148
120
|
*/
|
|
149
|
-
export type {
|
|
121
|
+
export type { Adapting } from "./Adapter/Types";
|
|
150
122
|
/**
|
|
151
|
-
* The shape `initialize({
|
|
152
|
-
*
|
|
153
|
-
* the type.
|
|
123
|
+
* The shape `initialize({ salt })` and `new Fabricator(schema, { salt })` both
|
|
124
|
+
* accept — a single string, or several — so a caller building one
|
|
125
|
+
* programmatically (rather than as an inline literal) can name the type.
|
|
154
126
|
*/
|
|
155
|
-
export type {
|
|
127
|
+
export type { Salt } from "./Random/Types";
|
|
156
128
|
/**
|
|
157
129
|
* Reads the value type a built Fabricator produces straight off its `fabricate`
|
|
158
130
|
* signature — `Fabrication<typeof Product>` instead of `ReturnType<typeof
|
|
@@ -170,19 +142,12 @@ export type { ValueOf } from "./Schema/Types";
|
|
|
170
142
|
* onto one, the same reason `Stream` is exported above.
|
|
171
143
|
*/
|
|
172
144
|
export type { Trace } from "./Random/Types";
|
|
173
|
-
/**
|
|
174
|
-
* How `file` and `ordinal` on a {@link Trace} were resolved — recorded so a
|
|
175
|
-
* captured trace is self-describing, including `"counted"` (replayed for a node
|
|
176
|
-
* taken from inside a `T.recursive` expansion; not a variant you choose when
|
|
177
|
-
* building).
|
|
178
|
-
*/
|
|
179
|
-
export type { RootKind } from "./Random/Types";
|
|
180
145
|
/**
|
|
181
146
|
* `fork`/`wrap`'s own config shapes, so a caller building an overlay
|
|
182
147
|
* programmatically (rather than as an inline literal) can name them — the same
|
|
183
|
-
* rationale as the existing `
|
|
184
|
-
*
|
|
185
|
-
* `
|
|
186
|
-
*
|
|
148
|
+
* rationale as the existing `Salt` export. `Config` is what `initialize`'s own
|
|
149
|
+
* parameter is a `Partial` of; `Overlay` is what `fork`/`wrap` accept;
|
|
150
|
+
* `Context` is `instance.context`'s own type, so a caller writing a helper that
|
|
151
|
+
* reads it can name the parameter.
|
|
187
152
|
*/
|
|
188
153
|
export type { Config, Context, Overlay, Stack } from "./Instance/Types";
|
package/dist/types/internal.d.ts
CHANGED
|
@@ -58,30 +58,12 @@ export type { Constructor } from "./Fabricator/Constructor";
|
|
|
58
58
|
export { plan, resolve } from "./Enumeration/Plan";
|
|
59
59
|
export type { Axis, Enumerable, Pin, Resolvable } from "./Enumeration/Types";
|
|
60
60
|
/**
|
|
61
|
-
* The randomness layer underneath `initialize({
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
* itself exposes.
|
|
61
|
+
* The randomness layer underneath `initialize({ clock, salt, algorithm })` and
|
|
62
|
+
* a Fabricator's `.trace` — needed by tests exercising stream construction
|
|
63
|
+
* directly, beneath the level `initialize()` itself exposes.
|
|
65
64
|
*/
|
|
66
|
-
export { defaultAlgorithm, encode,
|
|
67
|
-
export type { Algorithm, ConstructionTrace, ConstructorOptions,
|
|
68
|
-
/**
|
|
69
|
-
* `Random/CallSite.ts`'s pure string helpers. Exported for this package's own
|
|
70
|
-
* tests: the percent-encoded, `file://`-prefixed, and backslashed spellings
|
|
71
|
-
* they exist to fold together cannot be produced by running the suite from an
|
|
72
|
-
* ordinary POSIX checkout, so they have to be driven with synthetic frame
|
|
73
|
-
* strings instead of real stack frames.
|
|
74
|
-
*/
|
|
75
|
-
export { directoryOf, normalizeLocation, relativize } from "./Random/CallSite";
|
|
76
|
-
/**
|
|
77
|
-
* Resolves the file that triggered the current call. Exported here for a
|
|
78
|
-
* library that wraps fabricator (e.g. `@ghostry/extern`'s testing scope) and
|
|
79
|
-
* wants a construction attributed to _its own_ caller rather than to itself,
|
|
80
|
-
* which is what the `skip` option is for. See `Random/CallSite.ts`'s doc
|
|
81
|
-
* comment for the full contract, including why `skip` is a list of roots that
|
|
82
|
-
* composes onto this library's own root rather than replacing it.
|
|
83
|
-
*/
|
|
84
|
-
export { resolveCallerFile } from "./Random/CallSite";
|
|
65
|
+
export { defaultAlgorithm, encode, randomSalt, toRandomSource, toStream, toStreamFromTrace, } from "./Random";
|
|
66
|
+
export type { Algorithm, ConstructionTrace, ConstructorOptions, RootPins, Salt, Trace, } from "./Random/Types";
|
|
85
67
|
/**
|
|
86
68
|
* The synchronous ambient carrier. `#stack` (`package.json`) selects it only
|
|
87
69
|
* where there is no `node:async_hooks` — in practice a browser bundle — so on
|
package/package.json
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ghostry/fabricator",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Fabricate typed data from composable schemas.",
|
|
6
6
|
"keywords": [
|
|
7
|
-
"factory"
|
|
7
|
+
"factory",
|
|
8
|
+
"reproducible",
|
|
9
|
+
"fixtures",
|
|
10
|
+
"testing",
|
|
11
|
+
"mock",
|
|
12
|
+
"schema",
|
|
13
|
+
"typescript"
|
|
8
14
|
],
|
|
9
15
|
"author": {
|
|
10
16
|
"name": "Patrick Rebsch"
|
|
@@ -14,9 +20,13 @@
|
|
|
14
20
|
"url": "git+https://github.com/ghostry-dev/fabricator",
|
|
15
21
|
"directory": "pkg/fabricator"
|
|
16
22
|
},
|
|
17
|
-
"homepage": "https://
|
|
23
|
+
"homepage": "https://docs.ghostry.dev/fabricator/",
|
|
18
24
|
"bugs": "https://github.com/ghostry-dev/fabricator/issues",
|
|
19
25
|
"type": "module",
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=20.0.0"
|
|
29
|
+
},
|
|
20
30
|
"types": "./dist/types/index.d.ts",
|
|
21
31
|
"module": "./dist/esm/index.js",
|
|
22
32
|
"imports": {
|
|
@@ -38,6 +48,16 @@
|
|
|
38
48
|
"types": "./dist/types/internal.d.ts",
|
|
39
49
|
"import": "./dist/esm/internal.js",
|
|
40
50
|
"default": "./dist/esm/internal.js"
|
|
51
|
+
},
|
|
52
|
+
"./adapting": {
|
|
53
|
+
"types": "./dist/types/adapting.d.ts",
|
|
54
|
+
"import": "./dist/esm/adapting.js",
|
|
55
|
+
"default": "./dist/esm/adapting.js"
|
|
56
|
+
},
|
|
57
|
+
"./harnessing": {
|
|
58
|
+
"types": "./dist/types/harnessing.d.ts",
|
|
59
|
+
"import": "./dist/esm/harnessing.js",
|
|
60
|
+
"default": "./dist/esm/harnessing.js"
|
|
41
61
|
}
|
|
42
62
|
},
|
|
43
63
|
"publishConfig": {
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
const OWN_ROOT = normalizeLocation(new URL("..", import.meta.url).href);
|
|
2
|
-
function stripPosition(text) {
|
|
3
|
-
return text.replace(/:\d+:\d+/g, "");
|
|
4
|
-
}
|
|
5
|
-
function extractLocation(frameLine) {
|
|
6
|
-
const trimmed = frameLine.trim().replace(/^at\s+/, "");
|
|
7
|
-
const parenthesized = trimmed.match(/\(([^()]*)\)$/);
|
|
8
|
-
return parenthesized ? parenthesized[1] : trimmed;
|
|
9
|
-
}
|
|
10
|
-
function decode(text) {
|
|
11
|
-
try {
|
|
12
|
-
return decodeURIComponent(text);
|
|
13
|
-
} catch {
|
|
14
|
-
return text;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
function normalizeLocation(location) {
|
|
18
|
-
const isUrl = location.startsWith("file://");
|
|
19
|
-
const path = isUrl ? decode(location.slice(7)) : location;
|
|
20
|
-
return path.replace(/\\/g, "/").replace(/^\/?([A-Za-z]):\//, (_, letter)=>`/${letter.toUpperCase()}:/`);
|
|
21
|
-
}
|
|
22
|
-
function directoryOf(location) {
|
|
23
|
-
const cut = location.lastIndexOf("/");
|
|
24
|
-
return -1 === cut ? location : location.slice(0, cut + 1);
|
|
25
|
-
}
|
|
26
|
-
function relativize(root, file) {
|
|
27
|
-
if (!file.startsWith("/")) return file;
|
|
28
|
-
const from = root.split("/").filter(Boolean);
|
|
29
|
-
const to = file.split("/").filter(Boolean);
|
|
30
|
-
let shared = 0;
|
|
31
|
-
while(shared < from.length && shared < to.length && from[shared] === to[shared])shared++;
|
|
32
|
-
const traversals = Array(from.length - shared).fill("..");
|
|
33
|
-
return [
|
|
34
|
-
...traversals,
|
|
35
|
-
...to.slice(shared)
|
|
36
|
-
].join("/");
|
|
37
|
-
}
|
|
38
|
-
function isInternalFrame(location, otherInternals = []) {
|
|
39
|
-
if (location.startsWith(OWN_ROOT)) return true;
|
|
40
|
-
return otherInternals.some((skip)=>location.startsWith(skip));
|
|
41
|
-
}
|
|
42
|
-
function firstExternalFrame(stack, otherInternals = []) {
|
|
43
|
-
var _ref, _locations_find;
|
|
44
|
-
const locations = stack.split("\n").filter((line)=>line.trim().startsWith("at ")).map(extractLocation).map(normalizeLocation);
|
|
45
|
-
return null != (_ref = null != (_locations_find = locations.find((location)=>!isInternalFrame(location, otherInternals))) ? _locations_find : locations[locations.length - 1]) ? _ref : stack;
|
|
46
|
-
}
|
|
47
|
-
function resolveCallerFile(options) {
|
|
48
|
-
var _options_skip;
|
|
49
|
-
const skip = null == options ? void 0 : null == (_options_skip = options.skip) ? void 0 : _options_skip.map(normalizeLocation);
|
|
50
|
-
const stack = captureRawStack();
|
|
51
|
-
const location = stripPosition(stack.walkable ? firstExternalFrame(stack.text, skip) : stack.text);
|
|
52
|
-
return (null == options ? void 0 : options.root) === void 0 ? location : relativize(normalizeLocation(options.root), location);
|
|
53
|
-
}
|
|
54
|
-
function captureRawStack() {
|
|
55
|
-
var _captured_stack;
|
|
56
|
-
if ("function" != typeof Error.captureStackTrace) {
|
|
57
|
-
var _stack;
|
|
58
|
-
return {
|
|
59
|
-
text: null != (_stack = new Error().stack) ? _stack : "",
|
|
60
|
-
walkable: false
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
const captured = {};
|
|
64
|
-
Error.captureStackTrace(captured);
|
|
65
|
-
return {
|
|
66
|
-
text: null != (_captured_stack = captured.stack) ? _captured_stack : "",
|
|
67
|
-
walkable: true
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
export { directoryOf, normalizeLocation, relativize, resolveCallerFile };
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* One canonical form for a location, whatever produced it: Node ESM emits
|
|
3
|
-
* `file:///…` URLs, Bun emits bare absolute paths, and this module's own
|
|
4
|
-
* `import.meta.url` is percent-encoded — three spellings of one file that must
|
|
5
|
-
* compare equal, or `isInternalFrame`/`relativize` silently stop matching. A
|
|
6
|
-
* bare path is trusted as-is and never decoded, since it may contain a literal
|
|
7
|
-
* `%20`; only the `file://` form's escaping is guaranteed well-formed. Forward
|
|
8
|
-
* slashes and an uppercased leading `/X:/` drive fold Windows' `C:\a\b` and
|
|
9
|
-
* `file:///c:/a/b` together — the drive is the one component two sources
|
|
10
|
-
* disagree on, so it's the only thing case-folded: doing more would break
|
|
11
|
-
* case-sensitive filesystems and change what ends up hashed.
|
|
12
|
-
*/
|
|
13
|
-
export declare function normalizeLocation(location: string): string;
|
|
14
|
-
/**
|
|
15
|
-
* The directory a location sits in, trailing separator included — without it, a
|
|
16
|
-
* root of `/a/b/` would match the unrelated sibling `/a/bcd/x.ts`, since
|
|
17
|
-
* `startsWith`/prefix-stripping only sees character runs, not path segments.
|
|
18
|
-
*/
|
|
19
|
-
export declare function directoryOf(location: string): string;
|
|
20
|
-
/**
|
|
21
|
-
* `file` expressed relative to `root`, ascending with `..` where `file` sits
|
|
22
|
-
* outside `root` rather than falling back to `file` unchanged. An ascending
|
|
23
|
-
* path stays identical across machines whose checkouts hold both locations at
|
|
24
|
-
* the same relative position, the common case for anything under the same
|
|
25
|
-
* repository — passing an escaping file through as absolute would defeat the
|
|
26
|
-
* default `"call site"` policy for every schema helper that isn't a sibling of
|
|
27
|
-
* wherever `initialize()` was called. A location that isn't an absolute path
|
|
28
|
-
* (`native`, `<anonymous>`, or a value that has already been relativized)
|
|
29
|
-
* doesn't start with `/` and is returned unchanged — applying this twice is a
|
|
30
|
-
* no-op, which lets `T.recursive` thread an already-relativized file back
|
|
31
|
-
* through here uniformly.
|
|
32
|
-
*/
|
|
33
|
-
export declare function relativize(root: string, file: string): string;
|
|
34
|
-
/**
|
|
35
|
-
* Resolve the file that (transitively) triggered the current call, so
|
|
36
|
-
* construction can be attributed to the source file the user wrote it in.
|
|
37
|
-
*
|
|
38
|
-
* Primary path: `Error.captureStackTrace` (V8, and Bun for Node compatibility)
|
|
39
|
-
* captures the full stack, then `firstExternalFrame` skips this library's own
|
|
40
|
-
* frames by path — no need to hardcode how many frames to exclude, so it stays
|
|
41
|
-
* correct as internal call depth changes.
|
|
42
|
-
*
|
|
43
|
-
* Fallback: engines without `captureStackTrace` get the whole raw stack,
|
|
44
|
-
* position-stripped, hashed as-is rather than guessing which frame to isolate.
|
|
45
|
-
* Lower fidelity (sensitive to edits anywhere in the visible call chain, not
|
|
46
|
-
* just the immediate caller), but rarely exercised — Bun, Node, and Chrome all
|
|
47
|
-
* support the primary path. Left unnormalized: a whole multi-line stack has no
|
|
48
|
-
* single location for `normalizeLocation`'s separator/drive rewriting to apply
|
|
49
|
-
* to, so this path never relativizes — it always falls through `relativize`'s
|
|
50
|
-
* non-absolute passthrough instead.
|
|
51
|
-
*
|
|
52
|
-
* Both options exist for a library that wraps fabricator and wants to attribute
|
|
53
|
-
* a construction to _its own_ caller rather than to itself —
|
|
54
|
-
* `@ghostry/extern`'s testing scope is the motivating case: it opens a `wrap`
|
|
55
|
-
* per test and wants the resolved site to be the test file, not `extern`'s own
|
|
56
|
-
* module. This module's own callers (`resolveAttribution`'s `"call site"`
|
|
57
|
-
* branch, `resolveRootFile`) pass neither.
|
|
58
|
-
*
|
|
59
|
-
* `skip`, when given, is a list of _additional_ roots to exclude — layered onto
|
|
60
|
-
* `OWN_ROOT`, never replacing it. With a wrapper between fabricator and the
|
|
61
|
-
* real caller, the stack reads fabricator → wrapper → caller: omitting
|
|
62
|
-
* `OWN_ROOT` from the skip set would make this resolve to fabricator's own file
|
|
63
|
-
* instead of stopping at the wrapper.
|
|
64
|
-
*
|
|
65
|
-
* Always a list, never a bare root: a _chain_ of wrappers needs every link
|
|
66
|
-
* named, and any link left out is where resolution stops. An integration
|
|
67
|
-
* layered on another integration reads fabricator → inner → outer → caller —
|
|
68
|
-
* `@ghostry/extern`'s fabricator extension sits between fabricator and extern
|
|
69
|
-
* exactly this way.
|
|
70
|
-
*
|
|
71
|
-
* `root`, when given, relativizes the result exactly as a `{ kind: "rooted" }`
|
|
72
|
-
* attribution policy does ({@link relativize}) — so a caller needs no separate
|
|
73
|
-
* import to get a checkout-relative path.
|
|
74
|
-
*/
|
|
75
|
-
export declare function resolveCallerFile(options?: {
|
|
76
|
-
readonly skip?: readonly string[];
|
|
77
|
-
readonly root?: string;
|
|
78
|
-
}): string;
|