@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 +21 -0
- package/README.md +46 -0
- package/dist/src/core/combinators.d.ts +384 -0
- package/dist/src/core/compilers.d.ts +119 -0
- package/dist/src/core/constants.d.ts +20 -0
- package/dist/src/core/helpers.d.ts +112 -0
- package/dist/src/core/index.d.ts +8 -0
- package/dist/src/core/index.js +2026 -0
- package/dist/src/core/index.js.map +1 -0
- package/dist/src/core/parsers.d.ts +230 -0
- package/dist/src/core/shapers.d.ts +178 -0
- package/dist/src/core/types.d.ts +372 -0
- package/dist/src/core/validators.d.ts +250 -0
- package/package.json +69 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import type { ArrayShape, ArrayShapeOptions, BooleanShape, BooleanShapeOptions, ContractShape, JSONSchema, JSONShape, JSONShapeOptions, LiteralShape, LiteralShapeOptions, NullableShape, NullShape, NullShapeOptions, NumberShape, NumberShapeOptions, ObjectShape, ObjectShapeOptions, OptionalShape, RawShape, RecordShapeOptions, StringShape, StringShapeOptions, UnionShape } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Build a string {@link StringShape}.
|
|
4
|
+
*
|
|
5
|
+
* @param options - Optional length (`min` / `max`), `pattern`, and `description`
|
|
6
|
+
* @returns A string shape
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const name = stringShape({ min: 1, max: 80, description: 'Display name' })
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
export declare function stringShape(options?: StringShapeOptions): StringShape;
|
|
14
|
+
/**
|
|
15
|
+
* Build a numeric {@link NumberShape}.
|
|
16
|
+
*
|
|
17
|
+
* @param options - Optional bounds (`min` / `max`), `integer`, and `description`
|
|
18
|
+
* @returns A number shape
|
|
19
|
+
*/
|
|
20
|
+
export declare function numberShape(options?: NumberShapeOptions): NumberShape;
|
|
21
|
+
/**
|
|
22
|
+
* Build an integer {@link NumberShape} — forces `integer: true`.
|
|
23
|
+
*
|
|
24
|
+
* @remarks
|
|
25
|
+
* The emitted JSON Schema uses `"type": "integer"` and the guard rejects
|
|
26
|
+
* fractional numbers.
|
|
27
|
+
*
|
|
28
|
+
* @param options - Optional bounds and `description` (no `integer` key)
|
|
29
|
+
* @returns An integer number shape
|
|
30
|
+
*/
|
|
31
|
+
export declare function integerShape(options?: Omit<NumberShapeOptions, 'integer'>): NumberShape;
|
|
32
|
+
/**
|
|
33
|
+
* Build a {@link BooleanShape}.
|
|
34
|
+
*
|
|
35
|
+
* @param options - Optional `description`
|
|
36
|
+
* @returns A boolean shape
|
|
37
|
+
*/
|
|
38
|
+
export declare function booleanShape(options?: BooleanShapeOptions): BooleanShape;
|
|
39
|
+
/**
|
|
40
|
+
* Build a {@link NullShape}.
|
|
41
|
+
*
|
|
42
|
+
* @param options - Optional `description`
|
|
43
|
+
* @returns A null shape
|
|
44
|
+
*/
|
|
45
|
+
export declare function nullShape(options?: NullShapeOptions): NullShape;
|
|
46
|
+
/**
|
|
47
|
+
* Build a literal shape from a fixed set of primitive values.
|
|
48
|
+
*
|
|
49
|
+
* @param values - The permitted literals
|
|
50
|
+
* @param options - Optional `description`
|
|
51
|
+
* @returns A literal shape whose `Infer` is the union of `values`
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* const role = literalShape(['admin', 'member', 'guest'])
|
|
56
|
+
* // Infer<typeof role> = 'admin' | 'member' | 'guest'
|
|
57
|
+
*
|
|
58
|
+
* const via = literalShape(['function', 'tool', 'agent'], { description: 'How to run the step.' })
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare function literalShape<const T extends readonly (string | number | boolean)[]>(values: T, options?: LiteralShapeOptions): LiteralShape<T>;
|
|
62
|
+
/**
|
|
63
|
+
* Build an {@link ArrayShape} from an element shape.
|
|
64
|
+
*
|
|
65
|
+
* @param items - The element shape
|
|
66
|
+
* @param options - Optional length bounds and `description`
|
|
67
|
+
* @returns An array shape
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* const tags = arrayShape(stringShape(), { max: 10 })
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export declare function arrayShape<S extends ContractShape>(items: S, options?: ArrayShapeOptions): ArrayShape<S>;
|
|
75
|
+
/**
|
|
76
|
+
* Build an {@link ObjectShape} from a property map.
|
|
77
|
+
*
|
|
78
|
+
* @remarks
|
|
79
|
+
* Wrap any property in {@link optionalShape} to allow its absence. By default
|
|
80
|
+
* the compiled guard rejects unknown keys; pass `additionalProperties` to open
|
|
81
|
+
* the object.
|
|
82
|
+
*
|
|
83
|
+
* @param properties - Map of property names to child shapes
|
|
84
|
+
* @param options - Optional `additionalProperties` and `description`
|
|
85
|
+
* @returns An object shape
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* const user = objectShape({
|
|
90
|
+
* name: stringShape({ min: 1 }),
|
|
91
|
+
* age: integerShape({ min: 0, max: 120 }),
|
|
92
|
+
* bio: optionalShape(stringShape()),
|
|
93
|
+
* })
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export declare function objectShape<P extends Readonly<Record<string, ContractShape>>>(properties: P, options?: ObjectShapeOptions): ObjectShape<P>;
|
|
97
|
+
/**
|
|
98
|
+
* Build an open {@link ObjectShape} with no fixed properties — a dictionary.
|
|
99
|
+
*
|
|
100
|
+
* @remarks
|
|
101
|
+
* Every value is validated against `values`; keys are unconstrained. Equivalent
|
|
102
|
+
* to `objectShape({}, { additionalProperties: values })`.
|
|
103
|
+
*
|
|
104
|
+
* @param values - The shape every value must match
|
|
105
|
+
* @param options - Optional `description`
|
|
106
|
+
* @returns An open object shape
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* const bindings = recordShape(numberShape()) // ~ Record<string, number>
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
export declare function recordShape<S extends ContractShape>(values: S, options?: RecordShapeOptions): ObjectShape;
|
|
114
|
+
/**
|
|
115
|
+
* Build a {@link UnionShape} from a list of variant shapes (`anyOf` in JSON Schema).
|
|
116
|
+
*
|
|
117
|
+
* @param variants - The candidate shapes; the first match wins at runtime
|
|
118
|
+
* @returns A union shape whose `Infer` is the union of the variants
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* const id = unionShape(stringShape(), integerShape())
|
|
123
|
+
* // Infer<typeof id> = string | number
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
export declare function unionShape<V extends readonly ContractShape[]>(...variants: V): UnionShape<V>;
|
|
127
|
+
/**
|
|
128
|
+
* Build a {@link UnionShape} that emits `oneOf` (exactly one match) in JSON Schema.
|
|
129
|
+
*
|
|
130
|
+
* @remarks
|
|
131
|
+
* Runtime behavior is identical to {@link unionShape} — only the emitted schema
|
|
132
|
+
* keyword differs (`oneOf` vs `anyOf`).
|
|
133
|
+
*
|
|
134
|
+
* @param variants - The candidate shapes
|
|
135
|
+
* @returns A union shape with `mode: 'oneOf'`
|
|
136
|
+
*/
|
|
137
|
+
export declare function oneOfShape<V extends readonly ContractShape[]>(...variants: V): UnionShape<V>;
|
|
138
|
+
/**
|
|
139
|
+
* Wrap a shape so it may be absent (`undefined`).
|
|
140
|
+
*
|
|
141
|
+
* @remarks
|
|
142
|
+
* As an {@link objectShape} property, the field becomes a true optional property
|
|
143
|
+
* in the inferred type.
|
|
144
|
+
*
|
|
145
|
+
* @param inner - The wrapped shape
|
|
146
|
+
* @returns An optional shape
|
|
147
|
+
*/
|
|
148
|
+
export declare function optionalShape<S extends ContractShape>(inner: S): OptionalShape<S>;
|
|
149
|
+
/**
|
|
150
|
+
* Wrap a shape so it may be `null`.
|
|
151
|
+
*
|
|
152
|
+
* @param inner - The wrapped shape
|
|
153
|
+
* @returns A nullable shape
|
|
154
|
+
*/
|
|
155
|
+
export declare function nullableShape<S extends ContractShape>(inner: S): NullableShape<S>;
|
|
156
|
+
/**
|
|
157
|
+
* Build a {@link JSONShape}.
|
|
158
|
+
*
|
|
159
|
+
* @remarks
|
|
160
|
+
* The sound counterpart of {@link rawShape}: `rawShape` embeds an arbitrary
|
|
161
|
+
* schema fragment and accepts anything at runtime, while `jsonShape` validates
|
|
162
|
+
* that a value is real JSON (via {@link isJSONValue}).
|
|
163
|
+
*
|
|
164
|
+
* @param options - Optional `description`
|
|
165
|
+
* @returns A JSON passthrough shape
|
|
166
|
+
*/
|
|
167
|
+
export declare function jsonShape(options?: JSONShapeOptions): JSONShape;
|
|
168
|
+
/**
|
|
169
|
+
* Build a {@link RawShape} from a JSON Schema fragment.
|
|
170
|
+
*
|
|
171
|
+
* @remarks
|
|
172
|
+
* For values the shape DSL can't express. The compiled guard accepts any value;
|
|
173
|
+
* the parser passes it through; the schema is emitted verbatim.
|
|
174
|
+
*
|
|
175
|
+
* @param schema - The JSON Schema fragment to embed
|
|
176
|
+
* @returns A raw shape
|
|
177
|
+
*/
|
|
178
|
+
export declare function rawShape(schema: JSONSchema): RawShape;
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discriminated success branch of a {@link Result}.
|
|
3
|
+
*
|
|
4
|
+
* @remarks
|
|
5
|
+
* Used for operations that can succeed or fail without throwing.
|
|
6
|
+
*/
|
|
7
|
+
export interface Success<T> {
|
|
8
|
+
readonly success: true;
|
|
9
|
+
readonly value: T;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Discriminated failure branch of a {@link Result}.
|
|
13
|
+
*
|
|
14
|
+
* @remarks
|
|
15
|
+
* Carries the error value when an operation does not succeed.
|
|
16
|
+
*/
|
|
17
|
+
export interface Failure<E> {
|
|
18
|
+
readonly success: false;
|
|
19
|
+
readonly error: E;
|
|
20
|
+
}
|
|
21
|
+
/** Discriminated union for operations that can succeed or fail without throwing. */
|
|
22
|
+
export type Result<T, E = Error> = Success<T> | Failure<E>;
|
|
23
|
+
/**
|
|
24
|
+
* A field path into a record: a single key, or an ordered list of keys to
|
|
25
|
+
* descend through nested objects.
|
|
26
|
+
*
|
|
27
|
+
* @remarks
|
|
28
|
+
* A single `string` is ONE key — it is never split on `.`, so keys that contain
|
|
29
|
+
* dots stay safe. Use a `readonly string[]` to descend into nested objects.
|
|
30
|
+
*/
|
|
31
|
+
export type FieldPath = string | readonly string[];
|
|
32
|
+
/** A runtime type guard: returns `true` when `value` satisfies `T` and narrows it. */
|
|
33
|
+
export type Guard<T> = (value: unknown) => value is T;
|
|
34
|
+
/** Extract the guarded type `T` from a `Guard<T>`. */
|
|
35
|
+
export type GuardType<G> = G extends Guard<infer T> ? T : never;
|
|
36
|
+
/**
|
|
37
|
+
* A mapping of string keys to guards.
|
|
38
|
+
*
|
|
39
|
+
* @remarks
|
|
40
|
+
* The shape parameter for the `recordOf`, `pickOf`, and `omitOf` combinators.
|
|
41
|
+
*/
|
|
42
|
+
export type GuardsShape = Readonly<Record<string, Guard<unknown>>>;
|
|
43
|
+
/** Resolve a {@link GuardsShape} to a readonly object type of its guarded property types. */
|
|
44
|
+
export type FromGuards<G extends GuardsShape> = Readonly<{
|
|
45
|
+
[K in keyof G]: GuardType<G[K]>;
|
|
46
|
+
}>;
|
|
47
|
+
/**
|
|
48
|
+
* Like {@link FromGuards}, but every key listed in `K` is made optional.
|
|
49
|
+
*
|
|
50
|
+
* @typeParam S - The full guard shape
|
|
51
|
+
* @typeParam K - Tuple of keys to widen with `| undefined`
|
|
52
|
+
*/
|
|
53
|
+
export type OptionalFromGuards<S extends GuardsShape, K extends ReadonlyArray<keyof S>> = Readonly<{
|
|
54
|
+
[P in keyof S]: P extends K[number] ? FromGuards<S>[P] | undefined : FromGuards<S>[P];
|
|
55
|
+
}>;
|
|
56
|
+
/** Map a tuple of element guards to a readonly tuple of their guarded types. */
|
|
57
|
+
export type TupleFromGuards<Ts extends ReadonlyArray<Guard<unknown>>> = Readonly<{
|
|
58
|
+
[K in keyof Ts]: GuardType<Ts[K]>;
|
|
59
|
+
}>;
|
|
60
|
+
/** Convert a union type to an intersection type. */
|
|
61
|
+
export type UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
|
|
62
|
+
/** Intersection of the types guarded by a tuple of guards — backs `intersectionOf`. */
|
|
63
|
+
export type IntersectionFromGuards<Gs extends ReadonlyArray<Guard<unknown>>> = UnionToIntersection<GuardType<Gs[number]>>;
|
|
64
|
+
/**
|
|
65
|
+
* A parser: coerces an unknown value to `T`, or returns `undefined`.
|
|
66
|
+
*
|
|
67
|
+
* @remarks
|
|
68
|
+
* The runtime parallel of {@link Guard}. A parser pairs soundly with the guard
|
|
69
|
+
* for its output type: a guard-valid input is returned unchanged, and every
|
|
70
|
+
* non-`undefined` output satisfies that guard.
|
|
71
|
+
*/
|
|
72
|
+
export type Parser<T> = (value: unknown) => T | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* Any constructor signature that produces instances of `T`.
|
|
75
|
+
*
|
|
76
|
+
* @remarks
|
|
77
|
+
* Uses `unknown[]` parameters to stay maximally assignable from specific
|
|
78
|
+
* constructors without resorting to `any`.
|
|
79
|
+
*/
|
|
80
|
+
export type AnyConstructor<T = unknown> = new (...args: unknown[]) => T;
|
|
81
|
+
/** A function accepting any arguments and returning `unknown`. */
|
|
82
|
+
export type AnyFunction = (...args: unknown[]) => unknown;
|
|
83
|
+
/** An async function accepting any arguments and returning a `Promise`. */
|
|
84
|
+
export type AnyAsyncFunction = (...args: unknown[]) => Promise<unknown>;
|
|
85
|
+
/** A function accepting zero arguments and returning `unknown`. */
|
|
86
|
+
export type ZeroArgFunction = () => unknown;
|
|
87
|
+
/** An async function accepting zero arguments and returning a `Promise`. */
|
|
88
|
+
export type ZeroArgAsyncFunction = () => Promise<unknown>;
|
|
89
|
+
/**
|
|
90
|
+
* A primitive JSON value — the flat leaf of any JSON document.
|
|
91
|
+
*
|
|
92
|
+
* @remarks
|
|
93
|
+
* The recursive {@link JSONValue} tree type is shipped for consumers that need a
|
|
94
|
+
* reusable JSON metadata contract. Dedicated `JSONObject` / `JSONArray` aliases
|
|
95
|
+
* remain unshipped; compose those narrower shapes with the combinators, or keep
|
|
96
|
+
* an untrusted parse result as `unknown` and narrow it.
|
|
97
|
+
*/
|
|
98
|
+
export type JSONPrimitive = string | number | boolean | null;
|
|
99
|
+
/**
|
|
100
|
+
* A recursive JSON value — primitives, arrays, and object records.
|
|
101
|
+
*
|
|
102
|
+
* @remarks
|
|
103
|
+
* The static type admits any `number` because TypeScript cannot express
|
|
104
|
+
* finiteness. The {@link isJSONValue} guard rejects `NaN` and `±Infinity` since
|
|
105
|
+
* they have no JSON representation.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* const value: JSONValue = { nested: [1, 'x', null] }
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
export type JSONValue = JSONPrimitive | readonly JSONValue[] | {
|
|
113
|
+
readonly [key: string]: JSONValue;
|
|
114
|
+
};
|
|
115
|
+
/** The seven standard JSON Schema `type` names. */
|
|
116
|
+
export type JSONSchemaType = 'null' | 'boolean' | 'object' | 'array' | 'number' | 'integer' | 'string';
|
|
117
|
+
/**
|
|
118
|
+
* A JSON Schema fragment — the subset of keywords the contract compiler emits
|
|
119
|
+
* and {@link RawShape} embeds.
|
|
120
|
+
*
|
|
121
|
+
* @remarks
|
|
122
|
+
* Intentionally lean (not the full ~50-keyword vocabulary): it carries only the
|
|
123
|
+
* keywords {@link Infer}-driven `compileSchema` produces. Recursive via `items` /
|
|
124
|
+
* `properties` / `additionalProperties` / `anyOf` / `oneOf`, but every walk is
|
|
125
|
+
* over a finite, developer-authored shape — there is no cycle/depth risk.
|
|
126
|
+
*/
|
|
127
|
+
export interface JSONSchema {
|
|
128
|
+
readonly type?: JSONSchemaType;
|
|
129
|
+
readonly description?: string;
|
|
130
|
+
readonly enum?: readonly (string | number | boolean)[];
|
|
131
|
+
readonly minLength?: number;
|
|
132
|
+
readonly maxLength?: number;
|
|
133
|
+
readonly pattern?: string;
|
|
134
|
+
readonly minimum?: number;
|
|
135
|
+
readonly maximum?: number;
|
|
136
|
+
readonly minItems?: number;
|
|
137
|
+
readonly maxItems?: number;
|
|
138
|
+
readonly items?: JSONSchema;
|
|
139
|
+
readonly properties?: Readonly<Record<string, JSONSchema>>;
|
|
140
|
+
readonly required?: readonly string[];
|
|
141
|
+
readonly additionalProperties?: boolean | JSONSchema;
|
|
142
|
+
readonly anyOf?: readonly JSONSchema[];
|
|
143
|
+
readonly oneOf?: readonly JSONSchema[];
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* A contract shape — a declarative description of a value, built with the shape
|
|
147
|
+
* builders and compiled into a guard, a parser, a JSON Schema, and a generator.
|
|
148
|
+
*
|
|
149
|
+
* @remarks
|
|
150
|
+
* A discriminated union keyed on `type`. Shapes nest (an `ArrayShape` holds an
|
|
151
|
+
* element shape, an `ObjectShape` a map of them), so a contract is a finite,
|
|
152
|
+
* developer-authored tree — never cyclic.
|
|
153
|
+
*/
|
|
154
|
+
export type ContractShape = StringShape | NumberShape | BooleanShape | NullShape | LiteralShape | ArrayShape | ObjectShape | UnionShape | OptionalShape | NullableShape | JSONShape | RawShape;
|
|
155
|
+
/** A string shape with optional length and pattern constraints. */
|
|
156
|
+
export interface StringShape {
|
|
157
|
+
readonly type: 'string';
|
|
158
|
+
readonly min?: number;
|
|
159
|
+
readonly max?: number;
|
|
160
|
+
readonly pattern?: RegExp;
|
|
161
|
+
readonly description?: string;
|
|
162
|
+
}
|
|
163
|
+
/** A numeric shape with optional bounds; `integer` restricts to whole numbers. */
|
|
164
|
+
export interface NumberShape {
|
|
165
|
+
readonly type: 'number';
|
|
166
|
+
readonly min?: number;
|
|
167
|
+
readonly max?: number;
|
|
168
|
+
readonly integer?: boolean;
|
|
169
|
+
readonly description?: string;
|
|
170
|
+
}
|
|
171
|
+
/** A boolean shape — accepts only `true` or `false`. */
|
|
172
|
+
export interface BooleanShape {
|
|
173
|
+
readonly type: 'boolean';
|
|
174
|
+
readonly description?: string;
|
|
175
|
+
}
|
|
176
|
+
/** A null shape — accepts only `null`. */
|
|
177
|
+
export interface NullShape {
|
|
178
|
+
readonly type: 'null';
|
|
179
|
+
readonly description?: string;
|
|
180
|
+
}
|
|
181
|
+
/** A literal shape — accepts exactly one of a fixed set of primitive values. */
|
|
182
|
+
export interface LiteralShape<T extends readonly (string | number | boolean)[] = readonly (string | number | boolean)[]> {
|
|
183
|
+
readonly type: 'literal';
|
|
184
|
+
readonly values: T;
|
|
185
|
+
readonly description?: string;
|
|
186
|
+
}
|
|
187
|
+
/** An array shape with an element shape and optional length bounds. */
|
|
188
|
+
export interface ArrayShape<S extends ContractShape = ContractShape> {
|
|
189
|
+
readonly type: 'array';
|
|
190
|
+
readonly items: S;
|
|
191
|
+
readonly min?: number;
|
|
192
|
+
readonly max?: number;
|
|
193
|
+
readonly description?: string;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* An object shape — a map of property names to child shapes.
|
|
197
|
+
*
|
|
198
|
+
* @remarks
|
|
199
|
+
* A property whose shape is an {@link OptionalShape} may be absent; all others
|
|
200
|
+
* are required. `additionalProperties` controls unknown keys: `undefined` /
|
|
201
|
+
* `false` rejects them (closed), `true` accepts them as-is, a `ContractShape`
|
|
202
|
+
* validates them.
|
|
203
|
+
*/
|
|
204
|
+
export interface ObjectShape<P extends Readonly<Record<string, ContractShape>> = Readonly<Record<string, ContractShape>>> {
|
|
205
|
+
readonly type: 'object';
|
|
206
|
+
readonly properties: P;
|
|
207
|
+
readonly additionalProperties?: boolean | ContractShape;
|
|
208
|
+
readonly description?: string;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* A union shape — accepts a value matching any one variant (first match wins).
|
|
212
|
+
*
|
|
213
|
+
* @remarks
|
|
214
|
+
* `mode` selects the emitted JSON Schema keyword: `'anyOf'` (default) or
|
|
215
|
+
* `'oneOf'`. Runtime behavior is identical.
|
|
216
|
+
*/
|
|
217
|
+
export interface UnionShape<V extends readonly ContractShape[] = readonly ContractShape[]> {
|
|
218
|
+
readonly type: 'union';
|
|
219
|
+
readonly variants: V;
|
|
220
|
+
readonly mode?: 'anyOf' | 'oneOf';
|
|
221
|
+
readonly description?: string;
|
|
222
|
+
}
|
|
223
|
+
/** An optional wrapper — the inner shape may be absent (`undefined`). */
|
|
224
|
+
export interface OptionalShape<S extends ContractShape = ContractShape> {
|
|
225
|
+
readonly type: 'optional';
|
|
226
|
+
readonly inner: S;
|
|
227
|
+
}
|
|
228
|
+
/** A nullable wrapper — the inner shape may be `null`. */
|
|
229
|
+
export interface NullableShape<S extends ContractShape = ContractShape> {
|
|
230
|
+
readonly type: 'nullable';
|
|
231
|
+
readonly inner: S;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* A JSON passthrough shape — accepts any JSON value.
|
|
235
|
+
*
|
|
236
|
+
* @remarks
|
|
237
|
+
* The compiled guard is a sound {@link isJSONValue} check (rejecting cycles,
|
|
238
|
+
* functions, `NaN`, and `±Infinity`); the parser gates through that guard; the
|
|
239
|
+
* schema is the empty schema `{}` (matches any JSON instance); the generator
|
|
240
|
+
* emits a small deterministic {@link JSONValue}. Unlike {@link RawShape}, whose
|
|
241
|
+
* guard accepts anything, this shape validates that a value is real JSON.
|
|
242
|
+
*/
|
|
243
|
+
export interface JSONShape {
|
|
244
|
+
readonly type: 'json';
|
|
245
|
+
readonly description?: string;
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* A raw JSON Schema passthrough — embeds a schema fragment directly.
|
|
249
|
+
*
|
|
250
|
+
* @remarks
|
|
251
|
+
* For values the shape DSL can't express. The compiled guard accepts any value
|
|
252
|
+
* and the parser passes it through unchanged; the schema is emitted verbatim.
|
|
253
|
+
*/
|
|
254
|
+
export interface RawShape {
|
|
255
|
+
readonly type: 'raw';
|
|
256
|
+
readonly schema: JSONSchema;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Infer the static TypeScript type a {@link ContractShape} describes.
|
|
260
|
+
*
|
|
261
|
+
* @remarks
|
|
262
|
+
* Structural and recursive: optional object fields surface as optional
|
|
263
|
+
* properties, nullable wrappers add `| null`, and a literal tuple becomes a
|
|
264
|
+
* string/number/boolean-literal union.
|
|
265
|
+
*
|
|
266
|
+
* The first, non-distributive branch bails out to `unknown` when `S` is the
|
|
267
|
+
* full widened {@link ContractShape} union. Five members of that union recurse
|
|
268
|
+
* back into the whole union through their defaulted generics, so inferring the
|
|
269
|
+
* full union is a fixed point that can never shrink — the compiler would fan
|
|
270
|
+
* out until it aborts with TS2589. Bailing out lazily short-circuits that
|
|
271
|
+
* fixed point (the untaken branch is never instantiated) while every narrow
|
|
272
|
+
* shape and every partial union still flows through the exact chain below.
|
|
273
|
+
*/
|
|
274
|
+
export type Infer<S extends ContractShape> = [ContractShape] extends [S] ? unknown : S extends StringShape ? string : S extends NumberShape ? number : S extends BooleanShape ? boolean : S extends NullShape ? null : S extends {
|
|
275
|
+
readonly type: 'literal';
|
|
276
|
+
readonly values: infer V;
|
|
277
|
+
} ? V extends readonly (infer L)[] ? L : never : S extends {
|
|
278
|
+
readonly type: 'array';
|
|
279
|
+
readonly items: infer I;
|
|
280
|
+
} ? I extends ContractShape ? readonly Infer<I>[] : never : S extends {
|
|
281
|
+
readonly type: 'object';
|
|
282
|
+
readonly properties: infer P;
|
|
283
|
+
} ? P extends Readonly<Record<string, ContractShape>> ? InferObject<P> : never : S extends {
|
|
284
|
+
readonly type: 'union';
|
|
285
|
+
readonly variants: infer V;
|
|
286
|
+
} ? V extends readonly ContractShape[] ? InferUnion<V> : never : S extends {
|
|
287
|
+
readonly type: 'optional';
|
|
288
|
+
readonly inner: infer I;
|
|
289
|
+
} ? I extends ContractShape ? Infer<I> | undefined : never : S extends {
|
|
290
|
+
readonly type: 'nullable';
|
|
291
|
+
readonly inner: infer I;
|
|
292
|
+
} ? I extends ContractShape ? Infer<I> | null : never : S extends JSONShape ? JSONValue : unknown;
|
|
293
|
+
/**
|
|
294
|
+
* {@link Infer} of an object shape's `properties` — the required keys, plus the
|
|
295
|
+
* `optional`-wrapped keys as optional members.
|
|
296
|
+
*/
|
|
297
|
+
export type InferObject<P extends Readonly<Record<string, ContractShape>>> = Readonly<{
|
|
298
|
+
[K in keyof P as P[K] extends {
|
|
299
|
+
readonly type: 'optional';
|
|
300
|
+
} ? never : K]: Infer<P[K]>;
|
|
301
|
+
} & {
|
|
302
|
+
[K in keyof P as P[K] extends {
|
|
303
|
+
readonly type: 'optional';
|
|
304
|
+
} ? K : never]?: P[K] extends {
|
|
305
|
+
readonly type: 'optional';
|
|
306
|
+
readonly inner: infer I;
|
|
307
|
+
} ? I extends ContractShape ? Infer<I> : never : never;
|
|
308
|
+
}>;
|
|
309
|
+
/** {@link Infer} of a union shape's `variants` — the union of each variant's inferred type. */
|
|
310
|
+
export type InferUnion<V extends readonly ContractShape[]> = V extends readonly (infer U)[] ? U extends ContractShape ? Infer<U> : never : never;
|
|
311
|
+
/** Options for {@link StringShape} (via `stringShape`). */
|
|
312
|
+
export interface StringShapeOptions {
|
|
313
|
+
readonly min?: number;
|
|
314
|
+
readonly max?: number;
|
|
315
|
+
readonly pattern?: RegExp;
|
|
316
|
+
readonly description?: string;
|
|
317
|
+
}
|
|
318
|
+
/** Options for {@link NumberShape} (via `numberShape` / `integerShape`). */
|
|
319
|
+
export interface NumberShapeOptions {
|
|
320
|
+
readonly min?: number;
|
|
321
|
+
readonly max?: number;
|
|
322
|
+
readonly integer?: boolean;
|
|
323
|
+
readonly description?: string;
|
|
324
|
+
}
|
|
325
|
+
/** Options for {@link BooleanShape} (via `booleanShape`). */
|
|
326
|
+
export interface BooleanShapeOptions {
|
|
327
|
+
readonly description?: string;
|
|
328
|
+
}
|
|
329
|
+
/** Options for {@link NullShape} (via `nullShape`). */
|
|
330
|
+
export interface NullShapeOptions {
|
|
331
|
+
readonly description?: string;
|
|
332
|
+
}
|
|
333
|
+
/** Options for {@link JSONShape} (via `jsonShape`). */
|
|
334
|
+
export interface JSONShapeOptions {
|
|
335
|
+
readonly description?: string;
|
|
336
|
+
}
|
|
337
|
+
/** Options for {@link LiteralShape} (via `literalShape`). */
|
|
338
|
+
export interface LiteralShapeOptions {
|
|
339
|
+
readonly description?: string;
|
|
340
|
+
}
|
|
341
|
+
/** Options for {@link ArrayShape} (via `arrayShape`). */
|
|
342
|
+
export interface ArrayShapeOptions {
|
|
343
|
+
readonly min?: number;
|
|
344
|
+
readonly max?: number;
|
|
345
|
+
readonly description?: string;
|
|
346
|
+
}
|
|
347
|
+
/** Options for {@link ObjectShape} (via `objectShape`). */
|
|
348
|
+
export interface ObjectShapeOptions {
|
|
349
|
+
readonly additionalProperties?: boolean | ContractShape;
|
|
350
|
+
readonly description?: string;
|
|
351
|
+
}
|
|
352
|
+
/** Options for record shapes (via `recordShape`). */
|
|
353
|
+
export interface RecordShapeOptions {
|
|
354
|
+
readonly description?: string;
|
|
355
|
+
}
|
|
356
|
+
/** A deterministic random source returning a value in `[0, 1)`. */
|
|
357
|
+
export type RandomFunction = () => number;
|
|
358
|
+
/**
|
|
359
|
+
* A compiled contract — the four lockstep outputs derived from one shape.
|
|
360
|
+
*
|
|
361
|
+
* @remarks
|
|
362
|
+
* Built by `createContract`: `is` narrows, `parse` coerces (returning the typed
|
|
363
|
+
* value or `undefined`), `schema` is the emitted JSON Schema, and `generate`
|
|
364
|
+
* produces deterministic seed data from a {@link RandomFunction} (defaulting to
|
|
365
|
+
* a wall-clock-seeded source when none is supplied).
|
|
366
|
+
*/
|
|
367
|
+
export interface ContractInterface<T> {
|
|
368
|
+
readonly schema: JSONSchema;
|
|
369
|
+
readonly is: Guard<T>;
|
|
370
|
+
parse(value: unknown): T | undefined;
|
|
371
|
+
generate(random?: RandomFunction): T;
|
|
372
|
+
}
|