@orkestrel/contract 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Orkestrel
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,46 @@
1
+ # @orkestrel/contract
2
+
3
+ The zero-dependency contract toolkit — runtime type guards, guard combinators, coerce-and-extract
4
+ parsers, and a shape DSL that compiles once into a guard, parser, JSON Schema, and generator that
5
+ can never drift. The foundation package of the `@orkestrel` line.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ npm install @orkestrel/contract
11
+ ```
12
+
13
+ ## Requirements
14
+
15
+ - Node.js >= 24
16
+ - TypeScript-first (ships its own `.d.ts` types)
17
+
18
+ ## Usage
19
+
20
+ ```ts
21
+ import { createContract, integerShape, objectShape, stringShape } from '@orkestrel/contract'
22
+
23
+ const user = createContract(
24
+ objectShape({
25
+ name: stringShape({ min: 1 }),
26
+ age: integerShape({ min: 0, max: 120 }),
27
+ }),
28
+ )
29
+
30
+ user.is({ name: 'Ada', age: 36 }) // true
31
+ user.parse({ name: 'Ada', age: '36' }) // { name: 'Ada', age: 36 } — coerces, or undefined
32
+ user.schema // the compiled JSON Schema
33
+ ```
34
+
35
+ ## Guide
36
+
37
+ For the full surface — guards, combinators, parsers, the JSON boundary, and the shape DSL — see
38
+ [`guides/src/contract.md`](guides/src/contract.md).
39
+
40
+ ## Package
41
+
42
+ Published as a single typed entry point per the `exports` field in `package.json`.
43
+
44
+ ## License
45
+
46
+ MIT © [Orkestrel](https://github.com/orkestrel) — see [LICENSE](./LICENSE).
@@ -0,0 +1,384 @@
1
+ import type { AnyConstructor, FromGuards, Guard, GuardsShape, GuardType, IntersectionFromGuards, OptionalFromGuards, TupleFromGuards } from './types.js';
2
+ /**
3
+ * Build a guard that accepts arrays whose every element satisfies `elementGuard`.
4
+ *
5
+ * @example
6
+ * ```ts
7
+ * const isStringArray = arrayOf(isString)
8
+ * isStringArray(['a', 'b']) // true
9
+ * isStringArray(['a', 1]) // false
10
+ * ```
11
+ */
12
+ export declare function arrayOf<T>(elementGuard: Guard<T>): Guard<readonly T[]>;
13
+ export declare function arrayOf(elementGuard: (value: unknown) => boolean): Guard<readonly unknown[]>;
14
+ /**
15
+ * Build a guard that accepts fixed-arity tuples, testing each index with the
16
+ * corresponding guard.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * const isPair = tupleOf(isString, isNumber)
21
+ * isPair(['hello', 42]) // true
22
+ * isPair(['hello']) // false — wrong arity
23
+ * ```
24
+ */
25
+ export declare function tupleOf<const Gs extends ReadonlyArray<Guard<unknown>>>(...guards: Gs): Guard<TupleFromGuards<Gs>>;
26
+ export declare function tupleOf(...predicates: ReadonlyArray<(value: unknown) => boolean>): Guard<readonly unknown[]>;
27
+ /**
28
+ * Build a guard that accepts values identical (via `Object.is`) to one of the
29
+ * provided literal primitives.
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * const isRole = literalOf('admin', 'member', 'guest')
34
+ * isRole('admin') // true
35
+ * isRole('owner') // false
36
+ * ```
37
+ */
38
+ export declare function literalOf<const Literals extends ReadonlyArray<string | number | boolean>>(...literals: Literals): Guard<Literals[number]>;
39
+ /**
40
+ * Build a guard that accepts instances of the provided constructor.
41
+ *
42
+ * @remarks
43
+ * Verifies that `ctor` is a real constructor (via {@link isConstructor}) first,
44
+ * so passing an arrow function does not silently produce a broken guard.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * const isDateValue = instanceOf(Date)
49
+ * isDateValue(new Date()) // true
50
+ * isDateValue({}) // false
51
+ * ```
52
+ */
53
+ export declare function instanceOf<C>(ctor: C): Guard<InstanceType<C & AnyConstructor<object>>>;
54
+ /**
55
+ * Build a guard from a native `enum` or any object whose values are strings or
56
+ * numbers.
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * enum Direction { Up = 'up', Down = 'down' }
61
+ * const isDirection = enumOf(Direction)
62
+ * isDirection('up') // true
63
+ * isDirection('left') // false
64
+ * ```
65
+ */
66
+ export declare function enumOf<E extends Record<string, string | number>>(enumeration: E): Guard<E[keyof E]>;
67
+ /**
68
+ * Build a guard that accepts `Set` instances whose every element satisfies
69
+ * `elementGuard`.
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * const isStringSet = setOf(isString)
74
+ * isStringSet(new Set(['a', 'b'])) // true
75
+ * isStringSet(new Set(['a', 1])) // false
76
+ * ```
77
+ */
78
+ export declare function setOf<T>(elementGuard: Guard<T>): Guard<ReadonlySet<T>>;
79
+ export declare function setOf(elementGuard: (value: unknown) => boolean): Guard<ReadonlySet<unknown>>;
80
+ /**
81
+ * Build a guard that accepts `Map` instances where every key satisfies
82
+ * `keyGuard` and every value satisfies `valueGuard`.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * const isStringNumberMap = mapOf(isString, isNumber)
87
+ * isStringNumberMap(new Map([['a', 1]])) // true
88
+ * isStringNumberMap(new Map([[1, 'a']])) // false
89
+ * ```
90
+ */
91
+ export declare function mapOf<K, V>(keyGuard: Guard<K>, valueGuard: Guard<V>): Guard<ReadonlyMap<K, V>>;
92
+ export declare function mapOf(keyPredicate: (value: unknown) => boolean, valuePredicate: (value: unknown) => boolean): Guard<ReadonlyMap<unknown, unknown>>;
93
+ export declare function recordOf<S extends GuardsShape>(shape: S): Guard<FromGuards<S>>;
94
+ export declare function recordOf<S extends GuardsShape, K extends ReadonlyArray<keyof S & string>>(shape: S, optional: K): Guard<OptionalFromGuards<S, K>>;
95
+ export declare function recordOf<S extends GuardsShape>(shape: S, optional: true): Guard<Readonly<{
96
+ [P in keyof S]: FromGuards<S>[P] | undefined;
97
+ }>>;
98
+ /**
99
+ * Build a guard that accepts any iterable whose every element satisfies
100
+ * `elementGuard`.
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * const isNumberIterable = iterableOf(isNumber)
105
+ * isNumberIterable([1, 2, 3]) // true
106
+ * isNumberIterable(new Set([1, 2])) // true
107
+ * isNumberIterable([1, 'two']) // false
108
+ * ```
109
+ */
110
+ export declare function iterableOf<T>(elementGuard: Guard<T>): Guard<Iterable<T>>;
111
+ export declare function iterableOf(elementGuard: (value: unknown) => boolean): Guard<Iterable<unknown>>;
112
+ /**
113
+ * Build a guard that accepts values that are own keys of the provided object.
114
+ *
115
+ * @remarks
116
+ * Membership is tested with `Object.hasOwn`, so inherited prototype-chain keys
117
+ * (`toString`, `constructor`, …) are rejected. An own property that shadows a
118
+ * prototype name is accepted.
119
+ *
120
+ * @example
121
+ * ```ts
122
+ * const COLORS = { red: '#f00', green: '#0f0', blue: '#00f' } as const
123
+ * const isColorKey = keyOf(COLORS)
124
+ * isColorKey('red') // true
125
+ * isColorKey('purple') // false
126
+ * isColorKey('toString') // false — inherited, not an own key
127
+ * ```
128
+ */
129
+ export declare function keyOf<const O extends Readonly<Record<PropertyKey, unknown>>>(value: O): Guard<keyof O>;
130
+ /**
131
+ * Build a new guard shape by keeping only the listed keys — the structural
132
+ * equivalent of `Pick<T, K>`. Produces a shape for {@link recordOf}, not a guard.
133
+ *
134
+ * @example
135
+ * ```ts
136
+ * const full = { name: isString, age: isNumber, role: isString }
137
+ * const isName = recordOf(pickOf(full, ['name']))
138
+ * isName({ name: 'Ada' }) // true
139
+ * ```
140
+ */
141
+ export declare function pickOf<S extends GuardsShape, K extends ReadonlyArray<keyof S & string>>(shape: S, keys: K): Pick<S, K[number]>;
142
+ /**
143
+ * Build a new guard shape by removing the listed keys — the structural
144
+ * equivalent of `Omit<T, K>`. Produces a shape for {@link recordOf}, not a guard.
145
+ *
146
+ * @example
147
+ * ```ts
148
+ * const full = { name: isString, age: isNumber, role: isString }
149
+ * const isPublic = recordOf(omitOf(full, ['role']))
150
+ * isPublic({ name: 'Ada', age: 36 }) // true
151
+ * ```
152
+ */
153
+ export declare function omitOf<S extends GuardsShape, K extends ReadonlyArray<keyof S & string>>(shape: S, keys: K): Omit<S, K[number]>;
154
+ /**
155
+ * Combine two guards with logical AND — passes only when both pass.
156
+ *
157
+ * @remarks
158
+ * Use {@link whereOf} when the right side refines an already-narrowed type; use
159
+ * `andOf` to combine two independent guards.
160
+ *
161
+ * @example
162
+ * ```ts
163
+ * const isShortString = andOf(isString, isNonEmptyString)
164
+ * ```
165
+ */
166
+ export declare function andOf<A, B>(left: Guard<A>, right: Guard<B>): Guard<A & B>;
167
+ export declare function andOf<T, U extends T>(left: Guard<T>, right: (value: T) => value is U): Guard<U>;
168
+ export declare function andOf<T>(left: Guard<T>, right: (value: T) => boolean): Guard<T>;
169
+ export declare function andOf(left: (value: unknown) => boolean, right: (value: unknown) => boolean): Guard<unknown>;
170
+ /**
171
+ * Combine two guards with logical OR — passes when at least one passes. For more
172
+ * than two variants prefer {@link unionOf}.
173
+ *
174
+ * @example
175
+ * ```ts
176
+ * const isStringOrNumber = orOf(isString, isNumber)
177
+ * ```
178
+ */
179
+ export declare function orOf<A, B>(left: Guard<A>, right: Guard<B>): Guard<A | B>;
180
+ export declare function orOf(left: (value: unknown) => boolean, right: (value: unknown) => boolean): Guard<unknown>;
181
+ /**
182
+ * Negate a guard or predicate — passes when `guard` returns `false`.
183
+ *
184
+ * @remarks
185
+ * Typed as `Guard<unknown>` because `Exclude<unknown, T>` is not useful; use
186
+ * {@link complementOf} when you need the narrowed `Exclude<TBase, TExcluded>`.
187
+ *
188
+ * @example
189
+ * ```ts
190
+ * const isNotNull = notOf(isNull)
191
+ * ```
192
+ */
193
+ export declare function notOf(guard: (value: unknown) => boolean): Guard<unknown>;
194
+ /**
195
+ * Build a guard for `Exclude<TBase, TExcluded>` — accepts values that pass
196
+ * `base` but not `excluded`.
197
+ *
198
+ * @example
199
+ * ```ts
200
+ * const isNonEmpty = complementOf(isString, isEmptyString)
201
+ * isNonEmpty('hi') // true
202
+ * isNonEmpty('') // false
203
+ * ```
204
+ */
205
+ export declare function complementOf<TBase, TExcluded extends TBase>(base: Guard<TBase>, excluded: Guard<TExcluded> | ((value: TBase) => value is TExcluded)): Guard<Exclude<TBase, TExcluded>>;
206
+ /**
207
+ * Build a guard that accepts values matching at least one of the provided
208
+ * guards — the variadic form of {@link orOf}.
209
+ *
210
+ * @example
211
+ * ```ts
212
+ * const isStringOrBoolean = unionOf(isString, isBoolean)
213
+ * ```
214
+ */
215
+ export declare function unionOf<const Gs extends ReadonlyArray<Guard<unknown>>>(...guards: Gs): Guard<GuardType<Gs[number]>>;
216
+ export declare function unionOf(...predicates: ReadonlyArray<(value: unknown) => boolean>): Guard<unknown>;
217
+ /**
218
+ * Build a guard that accepts values matching ALL of the provided guards — the
219
+ * variadic form of {@link andOf}.
220
+ *
221
+ * @example
222
+ * ```ts
223
+ * const isNonEmpty = intersectionOf(isString, isNonEmptyString)
224
+ * ```
225
+ */
226
+ export declare function intersectionOf<const Gs extends ReadonlyArray<Guard<unknown>>>(...guards: Gs): Guard<IntersectionFromGuards<Gs>>;
227
+ export declare function intersectionOf(...predicates: ReadonlyArray<(value: unknown) => boolean>): Guard<unknown>;
228
+ /**
229
+ * Refine a base guard with an additional predicate that runs only when the base
230
+ * passes.
231
+ *
232
+ * @remarks
233
+ * The predicate receives a value already narrowed to `T`. When the predicate is
234
+ * itself a type guard (`value is U`), the result narrows to `Guard<U>` — it
235
+ * passes only when the value is genuinely a `U`, so the narrowing is sound. Per
236
+ * §14 the returned guard never throws: if `predicate` throws, the throw is
237
+ * contained and the guard reports a non-match.
238
+ *
239
+ * @example
240
+ * ```ts
241
+ * const isPositive = whereOf(isNumber, (n) => n > 0)
242
+ * isPositive(5) // true
243
+ * isPositive(-1) // false
244
+ *
245
+ * // A narrowing predicate refines the result type to Guard<5>
246
+ * const isFive = whereOf(isNumber, (n): n is 5 => n === 5)
247
+ * ```
248
+ */
249
+ export declare function whereOf<T, U extends T>(base: Guard<T>, predicate: (value: T) => value is U): Guard<U>;
250
+ export declare function whereOf<T>(base: Guard<T>, predicate: (value: T) => boolean): Guard<T>;
251
+ /**
252
+ * Defer guard creation until first use by calling `thunk()` on every
253
+ * invocation.
254
+ *
255
+ * @remarks
256
+ * `thunk` is called on every guard call, not cached — this lets it close over a
257
+ * binding assigned *after* `lazyOf` is called, the primary use case for
258
+ * self-referential recursive guards. Per §14 a throw from `thunk` (or the guard
259
+ * it resolves to) is contained and reported as a non-match.
260
+ *
261
+ * A recursive guard built this way has no cycle/depth detection: a cyclic or
262
+ * pathologically deep input is stack-bounded — the overflow is contained and the
263
+ * guard returns `false` rather than throwing, but it is not validated correctly
264
+ * past that bound.
265
+ *
266
+ * @example
267
+ * ```ts
268
+ * type Tree = { value: number; children: Tree[] }
269
+ * let isTree: Guard<Tree>
270
+ * isTree = recordOf({ value: isNumber, children: arrayOf(lazyOf(() => isTree)) })
271
+ * ```
272
+ */
273
+ export declare function lazyOf<T>(thunk: () => Guard<T>): Guard<T>;
274
+ /**
275
+ * Build a guard that passes when the base passes AND the projection of the value
276
+ * satisfies the target guard. Still narrows to `T` (the base type) — the target
277
+ * check is a validity constraint on a derived view, not a type transformation.
278
+ *
279
+ * @remarks
280
+ * `project` is a plain `(value: T) => U`. Per §14 the returned guard never
281
+ * throws: a throw from `project` is contained and reported as a non-match.
282
+ * `target` is itself a Guard (already §14-bound), so it stays outside the
283
+ * contained region. (Unlike the reference implementation, there is no
284
+ * "curried projector" branch — a projection that legitimately returns a function
285
+ * would be double-invoked under that scheme. Compose explicitly if you need it.)
286
+ *
287
+ * @example
288
+ * ```ts
289
+ * const isBounded = transformOf(
290
+ * isString,
291
+ * (s) => s.trim().length,
292
+ * whereOf(isNumber, (n) => n >= 1 && n <= 50),
293
+ * )
294
+ * isBounded('hello') // true
295
+ * isBounded('') // false
296
+ * ```
297
+ */
298
+ export declare function transformOf<T, U>(base: Guard<T>, project: (value: T) => U, target: Guard<U>): Guard<T>;
299
+ export declare function transformOf<T>(base: Guard<T>, project: (value: T) => unknown, target: (value: unknown) => boolean): Guard<T>;
300
+ /**
301
+ * Build a guard that accepts finite numbers within an inclusive `[min, max]`
302
+ * range.
303
+ *
304
+ * @remarks
305
+ * Refines {@link isFiniteNumber} with the bound comparison, so `NaN` /
306
+ * `±Infinity` are rejected before any comparison runs. An absent bound never
307
+ * constrains that side. Reused for a number's own value AND, applied to a
308
+ * `.length`, for string and array length refinements — the single source of the
309
+ * bound logic shared by the compiled guard and parser (compilers.ts).
310
+ *
311
+ * @example
312
+ * ```ts
313
+ * const inRange = boundsOf(1, 5)
314
+ * inRange(3) // true
315
+ * inRange(0) // false — below min
316
+ * inRange(6) // false — above max
317
+ *
318
+ * const atLeastTwo = boundsOf(2)
319
+ * atLeastTwo(2) // true — unbounded above
320
+ * ```
321
+ */
322
+ export declare function boundsOf(min?: number, max?: number): Guard<number>;
323
+ /**
324
+ * Build a guard that accepts strings matching a regular expression.
325
+ *
326
+ * @example
327
+ * ```ts
328
+ * const isHex = matchOf(/^[0-9a-f]+$/)
329
+ * isHex('1a2f') // true
330
+ * isHex('xyz') // false
331
+ * ```
332
+ */
333
+ export declare function matchOf(pattern: RegExp): Guard<string>;
334
+ /**
335
+ * Build a guard that accepts strings satisfying optional length and pattern
336
+ * refinements — `min` / `max` length and a `pattern`.
337
+ *
338
+ * @remarks
339
+ * Composes {@link isString} with {@link boundsOf} on the string's `.length` and
340
+ * an inline `pattern.test` (the same refinement {@link matchOf} performs). When all three options are absent it returns
341
+ * the bare {@link isString} guard (the unconstrained fast path), so an
342
+ * unrefined string leaf pays no wrapping cost. The single source of the string
343
+ * refinement shared by the compiled guard and parser (compilers.ts).
344
+ *
345
+ * @example
346
+ * ```ts
347
+ * const isSlug = stringOf({ min: 1, max: 32, pattern: /^[a-z-]+$/ })
348
+ * isSlug('hello-world') // true
349
+ * isSlug('') // false — below min
350
+ * isSlug('Hello') // false — pattern miss
351
+ *
352
+ * stringOf() // identical to isString
353
+ * ```
354
+ */
355
+ export declare function stringOf(options?: {
356
+ min?: number;
357
+ max?: number;
358
+ pattern?: RegExp;
359
+ }): Guard<string>;
360
+ /**
361
+ * Extend a guard to also allow `null`.
362
+ *
363
+ * @example
364
+ * ```ts
365
+ * const isNullableString = nullableOf(isString)
366
+ * isNullableString('hi') // true
367
+ * isNullableString(null) // true
368
+ * isNullableString(42) // false
369
+ * ```
370
+ */
371
+ export declare function nullableOf<T>(guard: Guard<T>): Guard<T | null>;
372
+ /**
373
+ * Extend a guard to also allow `undefined` — the optional counterpart of
374
+ * {@link nullableOf}.
375
+ *
376
+ * @example
377
+ * ```ts
378
+ * const isOptionalString = optionalOf(isString)
379
+ * isOptionalString('hi') // true
380
+ * isOptionalString(undefined) // true
381
+ * isOptionalString(null) // false
382
+ * ```
383
+ */
384
+ export declare function optionalOf<T>(guard: Guard<T>): Guard<T | undefined>;
@@ -0,0 +1,119 @@
1
+ import type { ContractInterface, ContractShape, Guard, Infer, JSONSchema, Parser, RandomFunction } from './types.js';
2
+ /**
3
+ * Validate that a {@link ContractShape} tree is well-formed — a pure recursive
4
+ * prepass run before compilation.
5
+ *
6
+ * @remarks
7
+ * Fail-fast, per AGENTS §12: a malformed shape is a programmer error, so this
8
+ * throws a plain `Error` immediately rather than surfacing as a silently-wrong
9
+ * guard, parser, schema, or generator later. Checks, recursively:
10
+ *
11
+ * - An {@link OptionalShape} is only legal as a direct object-property value —
12
+ * `optionalShape` wrapping an array item, a union variant, another
13
+ * optional/nullable's inner shape, `additionalProperties`, or the top-level
14
+ * shape all throw. An object property IS the one legal placement: its value
15
+ * is unwrapped to `.inner` before recursing, so `.inner` itself is validated
16
+ * as a normal (non-optional-wrapping) shape.
17
+ * - A {@link UnionShape} needs at least one variant; a {@link LiteralShape}
18
+ * needs at least one value and rejects non-finite (`NaN` / `Infinity` /
19
+ * `-Infinity`) number values.
20
+ * - A bounded {@link StringShape} / {@link NumberShape} / {@link ArrayShape}
21
+ * needs `min <= max` when both are set.
22
+ * - An integer {@link NumberShape} (`integer: true`) needs a non-empty integer
23
+ * range: `Math.ceil(min ?? -Infinity) <= Math.floor(max ?? Infinity)`.
24
+ * - `null` / `json` / `raw` / `boolean` are always-valid leaves. Recursion
25
+ * continues into array items, object properties (and `additionalProperties`
26
+ * when it is a shape), union variants, and optional/nullable inner shapes.
27
+ *
28
+ * @param shape - The shape to validate
29
+ * @throws {Error} When the shape is malformed
30
+ */
31
+ export declare function validateShape(shape: ContractShape): void;
32
+ /**
33
+ * Compile a {@link ContractShape} into a JSON Schema document.
34
+ *
35
+ * @remarks
36
+ * Object shapes emit `additionalProperties: false` (unless opened) and list only
37
+ * required keys in `required`; nullable shapes emit an `anyOf` with `{ type:
38
+ * 'null' }`. Emission only — it never inspects a runtime value.
39
+ *
40
+ * @param shape - The shape to compile
41
+ * @returns The emitted JSON Schema
42
+ */
43
+ export declare function compileSchema(shape: ContractShape): JSONSchema;
44
+ /**
45
+ * Compile a {@link ContractShape} into a runtime type guard.
46
+ *
47
+ * @remarks
48
+ * Reuses the combinators: `literalOf` for literals, `arrayOf` for arrays,
49
+ * `recordOf` for closed objects, `unionOf` for unions, `nullableOf` for nullable,
50
+ * and `whereOf` for constraint refinement. Like every guard it is total — it
51
+ * never throws (AGENTS §14).
52
+ *
53
+ * @param shape - The shape to compile
54
+ * @returns A guard narrowing to the shape's inferred type
55
+ */
56
+ export declare function compileGuard(shape: ContractShape): Guard<unknown>;
57
+ /**
58
+ * Compile a {@link ContractShape} into an input parser.
59
+ *
60
+ * @remarks
61
+ * Reuses the leaf parsers (`parseString` / `parseInteger` / `parseNumber` /
62
+ * `parseBoolean` / `parseRecord`) and coerces structurally. An object fails as a
63
+ * whole on any required-field failure; a union returns a guard-valid value
64
+ * unchanged, otherwise the first variant that both parses and guards wins.
65
+ *
66
+ * After coercing a leaf, it re-applies that leaf's REFINEMENTS through the same
67
+ * combinators `compileGuard` uses — `stringOf` for a string's length/pattern and
68
+ * `boundsOf` for a number's value and an array's length — so a value that coerces
69
+ * but violates a bound parses to `undefined`. The result is full parse↔guard
70
+ * soundness (AGENTS §14): a non-`undefined` parse always satisfies the contract's
71
+ * `is`, refinements included.
72
+ *
73
+ * @param shape - The shape to compile
74
+ * @returns A parser yielding the shape's inferred type or `undefined`
75
+ */
76
+ export declare function compileParser(shape: ContractShape): Parser<unknown>;
77
+ /**
78
+ * Compile a {@link ContractShape} into a deterministic seed value.
79
+ *
80
+ * @remarks
81
+ * The same shape and the same `random` source always produce the same value, so
82
+ * seed data is reproducible. Defaults to a {@link seededRandom} source seeded
83
+ * from the wall clock when none is supplied. Throws on a degenerate empty
84
+ * `literalShape` / `unionShape`, on a pattern-constrained `stringShape` whose
85
+ * generated sample cannot satisfy the pattern, or on a `rawShape` (its embedded
86
+ * schema is arbitrary and cannot be auto-generated) — a programmer error that
87
+ * cannot generate a value (AGENTS §12). `createContract` runs
88
+ * {@link validateShape} first, so a degenerate `literalShape` / `unionShape` /
89
+ * bounded shape is normally caught there; these throws remain here as defense
90
+ * for standalone `compileGenerator` use.
91
+ *
92
+ * @param shape - The shape to generate from
93
+ * @param random - A seeded random source (defaults to `seededRandom(Date.now())`)
94
+ * @returns A value matching the shape
95
+ */
96
+ export declare function compileGenerator(shape: ContractShape, random?: RandomFunction): unknown;
97
+ /**
98
+ * Compile a {@link ContractShape} into a {@link ContractInterface} — the four
99
+ * lockstep outputs from one declaration.
100
+ *
101
+ * @remarks
102
+ * Runs {@link validateShape} first — a malformed shape throws immediately
103
+ * rather than compiling into a silently-wrong contract (AGENTS §12). Then
104
+ * precompiles the schema, guard, and parser once; `generate` walks the shape
105
+ * per call with the supplied random source.
106
+ *
107
+ * @param shape - The shape to compile
108
+ * @returns A contract bundling `schema` / `is` / `parse` / `generate`
109
+ *
110
+ * @example
111
+ * ```ts
112
+ * const user = createContract(objectShape({ name: stringShape(), age: integerShape() }))
113
+ * user.is({ name: 'Ada', age: 36 }) // true
114
+ * user.parse({ name: 'Ada', age: '36' }) // { name: 'Ada', age: 36 }
115
+ * user.schema // { type: 'object', properties: { … }, … }
116
+ * ```
117
+ */
118
+ export declare function createContract<S extends ContractShape>(shape: S): ContractInterface<Infer<S>>;
119
+ export declare function createContract(shape: ContractShape): ContractInterface<unknown>;
@@ -0,0 +1,20 @@
1
+ import type { JSONSchemaType } from './types.js';
2
+ /**
3
+ * The seven standard JSON Schema `type` names, frozen.
4
+ *
5
+ * @remarks
6
+ * The runtime source of truth for the {@link JSONSchemaType} vocabulary. Compose
7
+ * it with the shipped primitives instead of reaching for a bespoke guard:
8
+ * `literalOf(...JSON_SCHEMA_TYPES)` is the guard, and
9
+ * `parseEnum(value, JSON_SCHEMA_TYPES)` / `parseEnumField(record, path, JSON_SCHEMA_TYPES)`
10
+ * is the parser.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import { JSON_SCHEMA_TYPES, literalOf, parseEnumField } from '@src/core'
15
+ *
16
+ * const isSchemaType = literalOf(...JSON_SCHEMA_TYPES) // Guard<JSONSchemaType>
17
+ * parseEnumField(schema, 'type', JSON_SCHEMA_TYPES) // JSONSchemaType | undefined
18
+ * ```
19
+ */
20
+ export declare const JSON_SCHEMA_TYPES: readonly JSONSchemaType[];