@oh-my-pi/omptype 17.2.6 → 17.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,346 @@
1
+ import { OmpTypeError } from "./errors.js";
2
+ import { type } from "./type.js";
3
+ const OPTIONAL_INNER = Symbol("omptype.typebox.optionalInner");
4
+ const OBJECT_INFO = Symbol("omptype.typebox.objectInfo");
5
+ function validationFailure(message) {
6
+ return { message };
7
+ }
8
+ function withLegacyCompat(schema) {
9
+ const compatSchema = schema;
10
+ if (!Object.hasOwn(compatSchema, "__validator")) {
11
+ Object.defineProperty(compatSchema, "__validator", {
12
+ value: (data) => {
13
+ const result = schema(data);
14
+ return result instanceof type.errors ? validationFailure(result.summary) : result;
15
+ },
16
+ configurable: true,
17
+ });
18
+ }
19
+ if (!Object.hasOwn(compatSchema, "safeParse")) {
20
+ Object.defineProperty(compatSchema, "safeParse", {
21
+ value: (input) => {
22
+ const result = schema(input);
23
+ return result instanceof type.errors
24
+ ? { success: false, error: validationFailure(result.summary) }
25
+ : { success: true, data: result };
26
+ },
27
+ configurable: true,
28
+ });
29
+ }
30
+ return compatSchema;
31
+ }
32
+ function applyMeta(schema, opts) {
33
+ let result = schema;
34
+ const description = opts?.description ?? opts?.title;
35
+ if (description !== undefined)
36
+ result = result.describe(description);
37
+ if (opts && Object.hasOwn(opts, "default"))
38
+ result = result.default(opts.default);
39
+ return withLegacyCompat(result);
40
+ }
41
+ function withJsonSchemaKeywords(schema, keywords) {
42
+ const emitBase = schema.toJsonSchema.bind(schema);
43
+ schema.toJsonSchema = options => ({ ...emitBase(options), ...keywords });
44
+ return schema;
45
+ }
46
+ function checkFiniteOption(name, value) {
47
+ if (value !== undefined && !Number.isFinite(value))
48
+ throw new OmpTypeError(`${name} must be finite`);
49
+ }
50
+ function tString(opts) {
51
+ checkFiniteOption("minLength", opts?.minLength);
52
+ checkFiniteOption("maxLength", opts?.maxLength);
53
+ let schema = type.raw(opts?.format === "url" || opts?.format === "uri" ? "string.url" : "string");
54
+ if (opts?.minLength !== undefined)
55
+ schema = schema.atLeastLength(opts.minLength);
56
+ if (opts?.maxLength !== undefined)
57
+ schema = schema.atMostLength(opts.maxLength);
58
+ if (opts?.pattern !== undefined) {
59
+ let regex;
60
+ try {
61
+ regex = new RegExp(opts.pattern);
62
+ }
63
+ catch {
64
+ throw new OmpTypeError(`invalid regular expression pattern ${JSON.stringify(opts.pattern)}`);
65
+ }
66
+ schema = schema.narrow((value, ctx) => regex.test(value) || ctx.mustBe(`a string matching ${opts.pattern}`));
67
+ }
68
+ if (opts?.format !== undefined && opts.format !== "url" && opts.format !== "uri") {
69
+ const format = opts.format;
70
+ const valid = formatPredicate(format);
71
+ schema = schema.narrow((value, ctx) => valid(value) || ctx.mustBe(`a string in ${format} format`));
72
+ }
73
+ return applyMeta(schema, opts);
74
+ }
75
+ function formatPredicate(format) {
76
+ switch (format) {
77
+ case "url":
78
+ case "uri":
79
+ return value => {
80
+ try {
81
+ new URL(value);
82
+ return true;
83
+ }
84
+ catch {
85
+ return false;
86
+ }
87
+ };
88
+ case "email":
89
+ return value => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
90
+ case "uuid":
91
+ return value => /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
92
+ case "date-time":
93
+ return value => /^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(?:\.\d+)?(?:Z|[+-]\d\d:\d\d)$/.test(value) &&
94
+ !Number.isNaN(Date.parse(value));
95
+ case "date":
96
+ return value => /^\d{4}-\d\d-\d\d$/.test(value) && !Number.isNaN(Date.parse(`${value}T00:00:00Z`));
97
+ default:
98
+ return () => true;
99
+ }
100
+ }
101
+ function tNumber(opts, integer = false) {
102
+ for (const key of ["minimum", "maximum", "exclusiveMinimum", "exclusiveMaximum", "multipleOf"]) {
103
+ checkFiniteOption(key, opts?.[key]);
104
+ }
105
+ if (opts?.multipleOf !== undefined && opts.multipleOf <= 0)
106
+ throw new OmpTypeError("multipleOf must be greater than zero");
107
+ let lower;
108
+ if (opts?.minimum !== undefined)
109
+ lower = { value: opts.minimum, exclusive: false };
110
+ if (opts?.exclusiveMinimum !== undefined && (!lower || opts.exclusiveMinimum >= lower.value)) {
111
+ lower = { value: opts.exclusiveMinimum, exclusive: true };
112
+ }
113
+ let upper;
114
+ if (opts?.maximum !== undefined)
115
+ upper = { value: opts.maximum, exclusive: false };
116
+ if (opts?.exclusiveMaximum !== undefined && (!upper || opts.exclusiveMaximum <= upper.value)) {
117
+ upper = { value: opts.exclusiveMaximum, exclusive: true };
118
+ }
119
+ const keyword = integer ? "number.integer" : "number";
120
+ const lowerDsl = lower ? `${lower.value} ${lower.exclusive ? "<" : "<="} ` : "";
121
+ const upperDsl = upper ? ` ${upper.exclusive ? "<" : "<="} ${upper.value}` : "";
122
+ let schema = type.raw(`${lowerDsl}${keyword}${upperDsl}`);
123
+ if (opts?.multipleOf !== undefined) {
124
+ const divisor = opts.multipleOf;
125
+ schema = schema.narrow((value, ctx) => {
126
+ const quotient = value / divisor;
127
+ return (Math.abs(quotient - Math.round(quotient)) <= Number.EPSILON * Math.max(1, Math.abs(quotient)) ||
128
+ ctx.mustBe(`a multiple of ${divisor}`));
129
+ });
130
+ }
131
+ return applyMeta(schema, opts);
132
+ }
133
+ function tLiteral(value, opts) {
134
+ return applyMeta(type.enumerated(value), opts);
135
+ }
136
+ function tNever(opts) {
137
+ return applyMeta(type.raw("unknown").narrow((_value, ctx) => ctx.mustBe("never")), opts);
138
+ }
139
+ function tUnion(schemas, opts) {
140
+ if (schemas.length === 0)
141
+ return tNever(opts);
142
+ let result = schemas[0];
143
+ for (let i = 1; i < schemas.length; i++)
144
+ result = result.or(schemas[i]);
145
+ return applyMeta(result, opts);
146
+ }
147
+ function tIntersect(schemas, opts) {
148
+ if (schemas.length === 0)
149
+ return applyMeta(type.raw("unknown"), opts);
150
+ const validateAll = () => {
151
+ const base = type.raw("unknown");
152
+ return base.narrow((value, ctx) => {
153
+ for (const schema of schemas) {
154
+ if (schema(value) instanceof type.errors)
155
+ return ctx.mustBe("a value satisfying every intersection member");
156
+ }
157
+ return true;
158
+ });
159
+ };
160
+ if (schemas.some(schema => schema.hasSteps))
161
+ return applyMeta(validateAll(), opts);
162
+ let result = schemas[0];
163
+ try {
164
+ for (let i = 1; i < schemas.length; i++)
165
+ result = result.and(schemas[i]);
166
+ }
167
+ catch (error) {
168
+ if (error instanceof OmpTypeError)
169
+ return applyMeta(validateAll(), opts);
170
+ throw error;
171
+ }
172
+ return applyMeta(result, opts);
173
+ }
174
+ function enumValues(values) {
175
+ if (Array.isArray(values))
176
+ return [...values];
177
+ const result = [];
178
+ const record = values;
179
+ for (const key in record) {
180
+ const value = record[key];
181
+ if (!(/^\d+$/.test(key) && typeof value === "string") && !result.includes(value))
182
+ result.push(value);
183
+ }
184
+ return result;
185
+ }
186
+ function tEnum(values, opts) {
187
+ return applyMeta(type.enumerated(...enumValues(values)), opts);
188
+ }
189
+ function tArray(item, opts) {
190
+ checkFiniteOption("minItems", opts?.minItems);
191
+ checkFiniteOption("maxItems", opts?.maxItems);
192
+ let schema = item.array();
193
+ if (opts?.minItems !== undefined)
194
+ schema = schema.atLeastLength(opts.minItems);
195
+ if (opts?.maxItems !== undefined)
196
+ schema = schema.atMostLength(opts.maxItems);
197
+ if (opts?.uniqueItems) {
198
+ schema = schema.narrow((values, ctx) => {
199
+ for (let i = 0; i < values.length; i++) {
200
+ for (let j = i + 1; j < values.length; j++) {
201
+ if (jsonEqual(values[i], values[j]))
202
+ return ctx.mustBe("an array with unique items");
203
+ }
204
+ }
205
+ return true;
206
+ });
207
+ }
208
+ const result = applyMeta(schema, opts);
209
+ return opts?.uniqueItems ? withJsonSchemaKeywords(result, { uniqueItems: true }) : result;
210
+ }
211
+ function jsonEqual(left, right) {
212
+ if (Object.is(left, right))
213
+ return true;
214
+ if (typeof left !== "object" || left === null || typeof right !== "object" || right === null)
215
+ return false;
216
+ try {
217
+ return JSON.stringify(left) === JSON.stringify(right);
218
+ }
219
+ catch {
220
+ return false;
221
+ }
222
+ }
223
+ function tTuple(items, opts) {
224
+ const schema = type.raw("unknown").narrow((value, ctx) => {
225
+ if (!Array.isArray(value) || value.length !== items.length)
226
+ return ctx.mustBe(`a tuple of length ${items.length}`);
227
+ for (let i = 0; i < items.length; i++)
228
+ if (items[i](value[i]) instanceof type.errors)
229
+ return ctx.mustBe(`a valid item at index ${i}`);
230
+ return true;
231
+ });
232
+ return applyMeta(schema, opts);
233
+ }
234
+ function tObject(properties, opts) {
235
+ const def = {};
236
+ const props = {};
237
+ for (const key in properties) {
238
+ const schema = properties[key];
239
+ const inner = schema[OPTIONAL_INNER];
240
+ def[inner ? `${key}?` : key] = (inner ?? schema);
241
+ props[key] = schema;
242
+ }
243
+ if (opts?.additionalProperties === false)
244
+ def["+"] = "reject";
245
+ else if (opts?.additionalProperties && opts.additionalProperties !== true)
246
+ def["[string]"] = opts.additionalProperties;
247
+ const schema = applyMeta(type.raw(def), opts);
248
+ schema[OBJECT_INFO] = { props, additionalProperties: opts?.additionalProperties };
249
+ return schema;
250
+ }
251
+ function tRecord(key, value, opts) {
252
+ const base = type.raw({ "[string]": value }).narrow((record, ctx) => {
253
+ for (const name in record)
254
+ if (key(name) instanceof type.errors)
255
+ return ctx.mustBe("an object with valid record keys");
256
+ return true;
257
+ });
258
+ return applyMeta(base, opts);
259
+ }
260
+ function tOptional(schema, opts) {
261
+ const marker = applyMeta(schema.or(type.raw("undefined")), opts);
262
+ marker[OPTIONAL_INNER] = schema;
263
+ return marker;
264
+ }
265
+ function tNullable(schema, opts) {
266
+ return applyMeta(schema.or(type.raw("null")), opts);
267
+ }
268
+ function requireObject(schema, operation) {
269
+ const info = schema[OBJECT_INFO];
270
+ if (!info)
271
+ throw new OmpTypeError(`Type.${operation} requires a schema created by Type.Object`);
272
+ return info;
273
+ }
274
+ function tPartial(schema) {
275
+ const info = requireObject(schema, "Partial");
276
+ const props = {};
277
+ for (const key in info.props)
278
+ props[key] = info.props[key][OPTIONAL_INNER]
279
+ ? info.props[key]
280
+ : tOptional(info.props[key]);
281
+ return tObject(props, { additionalProperties: info.additionalProperties });
282
+ }
283
+ function tRequired(schema) {
284
+ const info = requireObject(schema, "Required");
285
+ const props = {};
286
+ for (const key in info.props) {
287
+ props[key] = info.props[key][OPTIONAL_INNER] ?? info.props[key];
288
+ }
289
+ return tObject(props, { additionalProperties: info.additionalProperties });
290
+ }
291
+ function tPick(schema, keys) {
292
+ const info = requireObject(schema, "Pick");
293
+ const props = {};
294
+ for (const key of keys)
295
+ if (typeof key === "string" && info.props[key])
296
+ props[key] = info.props[key];
297
+ return tObject(props, { additionalProperties: info.additionalProperties });
298
+ }
299
+ function tOmit(schema, keys) {
300
+ const info = requireObject(schema, "Omit");
301
+ const omitted = new Set(keys);
302
+ const props = {};
303
+ for (const key in info.props)
304
+ if (!omitted.has(key))
305
+ props[key] = info.props[key];
306
+ return tObject(props, { additionalProperties: info.additionalProperties });
307
+ }
308
+ function tComposite(schemas, opts) {
309
+ const props = {};
310
+ for (const schema of schemas)
311
+ Object.assign(props, requireObject(schema, "Composite").props);
312
+ return tObject(props, opts);
313
+ }
314
+ function tUnsafe(_jsonSchema = {}) {
315
+ // Raw JSON Schema is accepted for source compatibility but is not retained or validated:
316
+ // omptype cannot honestly implement that contract without importing a second validator.
317
+ return withLegacyCompat(type.unknown);
318
+ }
319
+ export const Type = {
320
+ String: tString,
321
+ Number: (opts) => tNumber(opts),
322
+ Integer: (opts) => tNumber(opts, true),
323
+ Boolean: (opts) => applyMeta(type.raw("boolean"), opts),
324
+ Null: (opts) => applyMeta(type.raw("null"), opts),
325
+ Any: (opts) => applyMeta(type.raw("unknown"), opts),
326
+ Unknown: (opts) => applyMeta(type.raw("unknown"), opts),
327
+ Never: tNever,
328
+ Literal: tLiteral,
329
+ Union: tUnion,
330
+ Intersect: tIntersect,
331
+ Enum: tEnum,
332
+ Array: tArray,
333
+ Tuple: tTuple,
334
+ Object: tObject,
335
+ Record: tRecord,
336
+ Optional: tOptional,
337
+ Nullable: tNullable,
338
+ Readonly: (schema) => withLegacyCompat(schema),
339
+ Partial: tPartial,
340
+ Required: tRequired,
341
+ Pick: tPick,
342
+ Omit: tOmit,
343
+ Composite: tComposite,
344
+ Unsafe: tUnsafe,
345
+ };
346
+ export default { Type };
package/dist/js/zod.js ADDED
@@ -0,0 +1,269 @@
1
+ import { OmpTypeError } from "./errors.js";
2
+ import { embed, IR_BRAND } from "./ir.js";
3
+ import { type } from "./type.js";
4
+ function schemaFromIR(ir) {
5
+ const embedded = {
6
+ [IR_BRAND]: true,
7
+ ir,
8
+ hasSteps: false,
9
+ hasDefault: false,
10
+ run: value => value,
11
+ };
12
+ return type.raw(embedded);
13
+ }
14
+ function restrictBase(source, ir) {
15
+ let next = source.hasSteps
16
+ ? schemaFromIR({ k: "morph", input: ir, fn: value => source(value) })
17
+ : schemaFromIR(ir);
18
+ if (source.description !== undefined)
19
+ next = next.describe(source.description);
20
+ if (source.hasDefault)
21
+ next = next.default(source.defaultValue);
22
+ return next;
23
+ }
24
+ function lengthBound(kind, schema, bound) {
25
+ if (schema.ir.k !== "string" && schema.ir.k !== "array")
26
+ return;
27
+ if (!Number.isSafeInteger(bound) || bound < 0) {
28
+ throw new OmpTypeError(`${kind} length must be a nonnegative safe integer`);
29
+ }
30
+ }
31
+ function refinementMessage(messageOrOptions) {
32
+ if (typeof messageOrOptions === "string")
33
+ return messageOrOptions;
34
+ return messageOrOptions?.message ?? messageOrOptions?.error ?? "valid (refinement failed)";
35
+ }
36
+ function isStringKeyIR(ir) {
37
+ switch (ir.k) {
38
+ case "string":
39
+ return true;
40
+ case "lit":
41
+ return typeof ir.v === "string";
42
+ case "union":
43
+ return ir.members.length > 0 && ir.members.every(isStringKeyIR);
44
+ case "sub":
45
+ return isStringKeyIR(ir.schema.ir);
46
+ default:
47
+ return false;
48
+ }
49
+ }
50
+ function decorate(schema, optional = false) {
51
+ const next = (inner, nextOptional = optional) => decorate(inner, nextOptional);
52
+ const withObjectExtras = (extras) => {
53
+ if (schema.ir.k !== "object")
54
+ throw new OmpTypeError("object mode requires an object schema");
55
+ return next(restrictBase(schema, { ...schema.ir, extras }));
56
+ };
57
+ Object.defineProperty(schema, "isOptional", { value: optional, enumerable: false });
58
+ return Object.assign(schema, {
59
+ parse(value) {
60
+ const result = schema(value);
61
+ if (result instanceof type.errors)
62
+ throw new Error(result.summary);
63
+ return result;
64
+ },
65
+ safeParse(value) {
66
+ const result = schema(value);
67
+ if (!(result instanceof type.errors))
68
+ return { success: true, data: result };
69
+ return {
70
+ success: false,
71
+ error: {
72
+ message: result.summary,
73
+ issues: result.map(issue => ({ path: [...issue.path], message: issue.problem })),
74
+ },
75
+ };
76
+ },
77
+ min(bound) {
78
+ const ir = schema.ir;
79
+ if (ir.k === "string" || ir.k === "array") {
80
+ lengthBound("min", schema, bound);
81
+ const min = ir.min === undefined ? bound : Math.max(ir.min, bound);
82
+ return next(restrictBase(schema, { ...ir, min }));
83
+ }
84
+ if (ir.k === "number") {
85
+ if (Number.isNaN(bound))
86
+ throw new OmpTypeError("number min must not be NaN");
87
+ if (ir.min !== undefined && ir.min >= bound)
88
+ return next(restrictBase(schema, ir));
89
+ return next(restrictBase(schema, { ...ir, min: bound, xmin: false }));
90
+ }
91
+ throw new OmpTypeError(`cannot apply min to ${ir.k}`);
92
+ },
93
+ max(bound) {
94
+ const ir = schema.ir;
95
+ if (ir.k === "string" || ir.k === "array") {
96
+ lengthBound("max", schema, bound);
97
+ const max = ir.max === undefined ? bound : Math.min(ir.max, bound);
98
+ return next(restrictBase(schema, { ...ir, max }));
99
+ }
100
+ if (ir.k === "number") {
101
+ if (Number.isNaN(bound))
102
+ throw new OmpTypeError("number max must not be NaN");
103
+ if (ir.max !== undefined && ir.max <= bound)
104
+ return next(restrictBase(schema, ir));
105
+ return next(restrictBase(schema, { ...ir, max: bound, xmax: false }));
106
+ }
107
+ throw new OmpTypeError(`cannot apply max to ${ir.k}`);
108
+ },
109
+ int() {
110
+ if (schema.ir.k !== "number")
111
+ throw new OmpTypeError(`cannot apply int to ${schema.ir.k}`);
112
+ return next(restrictBase(schema, { ...schema.ir, int: true }));
113
+ },
114
+ positive() {
115
+ if (schema.ir.k !== "number")
116
+ throw new OmpTypeError(`cannot apply positive to ${schema.ir.k}`);
117
+ const ir = schema.ir;
118
+ if (ir.min !== undefined && ir.min > 0)
119
+ return next(restrictBase(schema, ir));
120
+ return next(restrictBase(schema, { ...ir, min: 0, xmin: true }));
121
+ },
122
+ nonnegative() {
123
+ if (schema.ir.k !== "number")
124
+ throw new OmpTypeError(`cannot apply nonnegative to ${schema.ir.k}`);
125
+ return this.min(0);
126
+ },
127
+ regex(expression, message) {
128
+ if (schema.ir.k !== "string")
129
+ throw new OmpTypeError(`cannot apply regex to ${schema.ir.k}`);
130
+ const expectation = message ?? `matching ${expression}`;
131
+ const narrowed = schema.narrow((value, ctx) => {
132
+ expression.lastIndex = 0;
133
+ const matches = expression.test(value);
134
+ expression.lastIndex = 0;
135
+ return matches || ctx.mustBe(expectation);
136
+ });
137
+ return next(narrowed);
138
+ },
139
+ url() {
140
+ if (schema.ir.k !== "string")
141
+ throw new OmpTypeError(`cannot apply url to ${schema.ir.k}`);
142
+ return next(restrictBase(schema, { ...schema.ir, url: true }));
143
+ },
144
+ optional() {
145
+ const widened = schema.or(type.raw("undefined"));
146
+ return decorate(widened, true);
147
+ },
148
+ nullable() {
149
+ return decorate(schema.or(type.raw("null")), optional);
150
+ },
151
+ default(value) {
152
+ const widened = schema.or(type.raw("undefined"));
153
+ const piped = widened.pipe(output => {
154
+ if (output !== undefined)
155
+ return output;
156
+ return typeof value === "function" ? value() : value;
157
+ });
158
+ return decorate(piped.default(value));
159
+ },
160
+ describe(description) {
161
+ return next(restrictBase(schema, { ...schema.ir, desc: description }).describe(description));
162
+ },
163
+ refine(predicate, messageOrOptions) {
164
+ const expectation = refinementMessage(messageOrOptions);
165
+ return next(schema.narrow((value, ctx) => Boolean(predicate(value)) || ctx.mustBe(expectation)));
166
+ },
167
+ transform(transformer) {
168
+ return decorate(schema.pipe(value => transformer(value)), optional);
169
+ },
170
+ catch(fallback) {
171
+ const caught = type.unknown.pipe(input => {
172
+ try {
173
+ const result = schema(input);
174
+ if (!(result instanceof type.errors))
175
+ return result;
176
+ }
177
+ catch {
178
+ // A caught schema is deliberately total, including user refinement/transform exceptions.
179
+ }
180
+ return typeof fallback === "function" ? fallback() : fallback;
181
+ });
182
+ return decorate(caught, optional);
183
+ },
184
+ strict() {
185
+ return withObjectExtras("reject");
186
+ },
187
+ passthrough() {
188
+ return withObjectExtras("keep");
189
+ },
190
+ strip() {
191
+ return withObjectExtras("delete");
192
+ },
193
+ partial() {
194
+ if (schema.ir.k !== "object")
195
+ throw new OmpTypeError(`cannot apply partial to ${schema.ir.k}`);
196
+ const props = schema.ir.props.map(prop => ({ ...prop, opt: true }));
197
+ return next(restrictBase(schema, { ...schema.ir, props }));
198
+ },
199
+ });
200
+ }
201
+ function decorateUnknown(schema) {
202
+ return decorate(schema);
203
+ }
204
+ function objectSchema(shape) {
205
+ const props = [];
206
+ for (const key in shape) {
207
+ const member = shape[key];
208
+ const prop = { key, opt: member.isOptional, val: embed(member) };
209
+ if (member.hasDefault) {
210
+ prop.hasDefault = true;
211
+ prop.def = member.defaultValue;
212
+ prop.defFactory = typeof member.defaultValue === "function";
213
+ }
214
+ props.push(prop);
215
+ }
216
+ return decorateUnknown(schemaFromIR({ k: "object", props, extras: "delete" }));
217
+ }
218
+ export const string = () => decorate(schemaFromIR(type.string.ir));
219
+ export const number = () => decorate(schemaFromIR(type.number.ir));
220
+ export const boolean = () => decorate(schemaFromIR(type.boolean.ir));
221
+ export const literal = (value) => decorate(schemaFromIR(type.enumerated(value).ir));
222
+ const enumSchema = (values) => {
223
+ if (values.length === 0)
224
+ throw new OmpTypeError("enum requires at least one value");
225
+ return decorate(schemaFromIR(type.enumerated(...values).ir));
226
+ };
227
+ export { enumSchema as enum };
228
+ export const union = (schemas) => decorate(schemaFromIR({ k: "union", members: schemas.map(schema => embed(schema)) }));
229
+ export const array = (element) => decorate(schemaFromIR({ k: "array", el: embed(element) }));
230
+ export const object = (shape) => objectSchema(shape);
231
+ export const record = (keySchema, valueSchema) => {
232
+ if (!isStringKeyIR(keySchema.ir))
233
+ throw new OmpTypeError("record keys must use a string schema");
234
+ const base = schemaFromIR({
235
+ k: "object",
236
+ props: [],
237
+ index: embed(valueSchema),
238
+ extras: "keep",
239
+ });
240
+ const checked = base.narrow((value, ctx) => {
241
+ for (const key in value) {
242
+ if (keySchema(key) instanceof type.errors)
243
+ return ctx.mustBe("a record with valid string keys");
244
+ }
245
+ return true;
246
+ });
247
+ return decorate(checked);
248
+ };
249
+ export const unknown = () => decorate(schemaFromIR(type.unknown.ir));
250
+ export const any = () => decorate(schemaFromIR(type.unknown.ir));
251
+ const nullSchema = () => decorate(type.raw("null"));
252
+ const undefinedSchema = () => decorate(type.raw("undefined"));
253
+ export { nullSchema as null, undefinedSchema as undefined };
254
+ /** Runtime `z.*` facade, merged with the `z.infer` type namespace below. */
255
+ export const z = {
256
+ string,
257
+ number,
258
+ boolean,
259
+ literal,
260
+ enum: enumSchema,
261
+ union,
262
+ array,
263
+ object,
264
+ record,
265
+ unknown,
266
+ any,
267
+ null: nullSchema,
268
+ undefined: undefinedSchema,
269
+ };
@@ -6,21 +6,13 @@
6
6
  * `from "@oh-my-pi/omptype/ark"` and nothing else changes. New code should
7
7
  * import `@oh-my-pi/omptype` directly.
8
8
  *
9
- * Compatibility affordances beyond the plain re-export:
10
- * - `ArkError` / `ArkErrors` alias `OmpError` / `OmpErrors`.
11
- * - `scope()` (alias-free form only) returns `{ type }`; the `jitless` flag is
12
- * obsolete — omptype always starts interpreted and JIT-compiles lazily.
9
+ * Compatibility affordance: `ArkError` / `ArkErrors` alias `OmpError` /
10
+ * `OmpErrors`. All schema builders, including recursive `scope()`, are
11
+ * re-exported unchanged.
13
12
  */
14
13
  import { OmpError, OmpErrors } from "./errors.js";
15
- import { type } from "./type.js";
16
14
  export * from "./index.js";
17
15
  export declare const ArkError: typeof OmpError;
18
16
  export type ArkError = OmpError;
19
17
  export declare const ArkErrors: typeof OmpErrors;
20
18
  export type ArkErrors = OmpErrors;
21
- /** ArkType `scope()` shim: only the alias-free `scope({}, config?)` form is supported. */
22
- export declare function scope(aliases: Record<string, never>, _config?: {
23
- jitless?: boolean;
24
- }): {
25
- type: typeof type;
26
- };
@@ -1,5 +1,7 @@
1
1
  import { type IR } from "./ir.js";
2
2
  /** Compile `ir` into a specialized validator. */
3
3
  export declare function compile(ir: IR): (value: unknown) => unknown;
4
+ /** Compile `ir` into an allocation-free boolean validator. */
5
+ export declare function compileAllows(ir: IR): (value: unknown) => boolean;
4
6
  /** Generated source for inspection/debugging. */
5
7
  export declare function compileToSource(ir: IR): string;