@oh-my-pi/omptype 17.2.6 → 17.2.8

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,3062 @@
1
+ /**
2
+ * The public `type()` parser and `Type` schema surface — an ArkType-compatible
3
+ * validator with a lazy JIT:
4
+ *
5
+ * - calls 1-2 run the tree-walking interpreter (near-zero setup cost, so
6
+ * schemas built per-request or validated once stay cheap)
7
+ * - the third call compiles a specialized validator via `new Function` and
8
+ * swaps it in; hot schemas validate in tens of nanoseconds
9
+ *
10
+ * A schema is a callable: `schema(data)` returns the (possibly morphed)
11
+ * output, or an `OmpErrors` on failure (`result instanceof type.errors`).
12
+ */
13
+ import { compile, compileAllows } from "./compile.js";
14
+ import { OmpErrors, OmpTypeError, TraversalError } from "./errors.js";
15
+ import { walk } from "./interp.js";
16
+ import { distributeFilter, embed, expectedOf, hasMorph, IR_BRAND, isSimpleIR, keyOf, markThisOnlyResolver, parseDef, useAssignability, } from "./ir.js";
17
+ import { irToJsonSchema } from "./json-schema.js";
18
+ import { keywordIR, patternIR } from "./keywords.js";
19
+ // `Extract`/`Exclude` in the string DSL need assignability, which is defined here.
20
+ useAssignability(isSubtype);
21
+ /** Runtime constructor-like value used by ArkType-compatible `instanceof Type` checks. */
22
+ export const Type = Object.defineProperty(function Type() { }, Symbol.hasInstance, {
23
+ value: (value) => (typeof value === "function" || (typeof value === "object" && value !== null)) && IR_BRAND in value,
24
+ });
25
+ function descriptionOf(ir, seen = new Set()) {
26
+ if (ir.desc !== undefined)
27
+ return ir.desc;
28
+ if (seen.has(ir))
29
+ return ir.k === "alias" ? ir.name : expectedOf(ir);
30
+ seen.add(ir);
31
+ if (ir.k === "alias")
32
+ return descriptionOf(ir.resolve(), seen);
33
+ if (ir.k === "object") {
34
+ return `{ ${ir.props.map(prop => `${String(prop.key)}${prop.opt ? "?" : ""}: ${descriptionOf(prop.val, seen)}`).join(", ")} }`;
35
+ }
36
+ return expectedOf(ir);
37
+ }
38
+ function errorConfigOf(config) {
39
+ return {
40
+ ...(config.description === undefined || config.expected !== undefined ? {} : { expected: config.description }),
41
+ ...(config.expected === undefined ? {} : { expected: config.expected }),
42
+ ...(config.actual === undefined ? {} : { actual: config.actual }),
43
+ ...(config.problem === undefined ? {} : { problem: config.problem }),
44
+ ...(config.message === undefined ? {} : { message: config.message }),
45
+ };
46
+ }
47
+ function configureNode(ir, config) {
48
+ return {
49
+ ...ir,
50
+ cfg: { ...ir.cfg, ...errorConfigOf(config) },
51
+ ...(config.description === undefined ? {} : { desc: config.description }),
52
+ };
53
+ }
54
+ function configureSelected(ir, config, selector) {
55
+ const domain = ir.k === "string" || ir.k === "number" || ir.k === "boolean" || ir.k === "bigint" || ir.k === "symbol"
56
+ ? ir.k
57
+ : ir.k === "object" || ir.k === "array" || ir.k === "tuple" || ir.k === "instance" || ir.k === "anyobject"
58
+ ? "object"
59
+ : undefined;
60
+ const kind = ir.k === "number" && ir.divisor !== undefined ? "divisor" : "domain";
61
+ if ((selector.kind === undefined || selector.kind === kind) &&
62
+ (selector.where === undefined || selector.where({ kind, domain }))) {
63
+ return configureNode(ir, config);
64
+ }
65
+ switch (ir.k) {
66
+ case "array":
67
+ return { ...ir, el: configureSelected(ir.el, config, selector) };
68
+ case "tuple":
69
+ return {
70
+ ...ir,
71
+ prefix: ir.prefix.map(item => ({ ...item, val: configureSelected(item.val, config, selector) })),
72
+ ...(ir.variadic === undefined ? {} : { variadic: configureSelected(ir.variadic, config, selector) }),
73
+ postfix: ir.postfix.map(item => configureSelected(item, config, selector)),
74
+ };
75
+ case "object":
76
+ return {
77
+ ...ir,
78
+ props: ir.props.map(prop => ({ ...prop, val: configureSelected(prop.val, config, selector) })),
79
+ ...(ir.index === undefined ? {} : { index: configureSelected(ir.index, config, selector) }),
80
+ symbolIndex: ir.symbolIndex === undefined ? undefined : configureSelected(ir.symbolIndex, config, selector),
81
+ patternIndexes: ir.patternIndexes?.map(index => ({
82
+ key: configureSelected(index.key, config, selector),
83
+ val: configureSelected(index.val, config, selector),
84
+ })),
85
+ };
86
+ case "union":
87
+ case "intersection":
88
+ return { ...ir, members: ir.members.map(member => configureSelected(member, config, selector)) };
89
+ case "refine":
90
+ return { ...ir, base: configureSelected(ir.base, config, selector) };
91
+ case "morph":
92
+ return {
93
+ ...ir,
94
+ input: configureSelected(ir.input, config, selector),
95
+ ...(ir.out === undefined ? {} : { out: configureSelected(ir.out, config, selector) }),
96
+ };
97
+ default:
98
+ return ir;
99
+ }
100
+ }
101
+ class Ctx {
102
+ expectation;
103
+ errors;
104
+ path;
105
+ #data;
106
+ constructor(data, path = []) {
107
+ this.#data = data;
108
+ this.path = path.map(key => (typeof key === "symbol" ? String(key) : key));
109
+ }
110
+ error(input) {
111
+ const detail = typeof input === "string" ? { expected: input } : input;
112
+ const error = OmpErrors.single([...(detail.path ?? detail.relativePath ?? [])], detail.expected, this.#data, {
113
+ preserveActual: true,
114
+ ...(Object.hasOwn(detail, "actual") ? { actual: String(detail.actual) } : {}),
115
+ });
116
+ if (this.errors)
117
+ this.errors.append(error);
118
+ else
119
+ this.errors = error;
120
+ return error;
121
+ }
122
+ mustBe(expectation) {
123
+ this.expectation = expectation;
124
+ return false;
125
+ }
126
+ reject(input) {
127
+ if (typeof input === "string") {
128
+ this.expectation = input;
129
+ return false;
130
+ }
131
+ this.error(input);
132
+ return false;
133
+ }
134
+ }
135
+ const kBase = Symbol("omptype.base");
136
+ const kSteps = Symbol("omptype.steps");
137
+ const EMPTY_STEPS = [];
138
+ const EMPTY_META = {};
139
+ const ARK_COMPAT_SCOPE = Object.freeze({ internal: Object.freeze({ name: "ark" }) });
140
+ /** Calls before the JIT compiles a schema (first two run the interpreter). */
141
+ const JIT_THRESHOLD = 3;
142
+ function metaOf(schema) {
143
+ return {
144
+ description: schema.description,
145
+ defaultValue: schema.defaultValue,
146
+ hasDefault: schema.hasDefault,
147
+ defaultOutput: schema.defaultOutput,
148
+ hasDefaultOutput: schema.hasDefaultOutput,
149
+ errorConfig: schema.errorConfig,
150
+ clone: schema.clone,
151
+ };
152
+ }
153
+ function inheritScope(source, target) {
154
+ if (source.resolver === undefined)
155
+ return target;
156
+ target.resolver = source.resolver;
157
+ Reflect.set(target, "$", source.$);
158
+ return target;
159
+ }
160
+ function invalidDefault(label, errors) {
161
+ const error = errors[0];
162
+ let heading = label;
163
+ for (let index = 0; index < error.path.length; index++) {
164
+ const segment = error.path[index];
165
+ if (typeof segment === "number") {
166
+ if (label === "Default" && index === 0)
167
+ heading = "Default value";
168
+ heading += ` at [${segment}]`;
169
+ }
170
+ else if (label === "Default" && index === 0) {
171
+ heading += ` ${String(segment)}`;
172
+ }
173
+ else {
174
+ heading += `.${String(segment)}`;
175
+ }
176
+ }
177
+ throw new OmpTypeError(`ParseError: ${heading} ${error.problem}`);
178
+ }
179
+ function rejectMutableStaticDefault(value) {
180
+ if (value !== null && typeof value === "object" && !(value instanceof Date)) {
181
+ throw new OmpTypeError("ParseError: A mutable default value must be specified as a factory");
182
+ }
183
+ }
184
+ function normalizeDefaults(ir, seen = new WeakSet()) {
185
+ if (seen.has(ir))
186
+ return;
187
+ seen.add(ir);
188
+ switch (ir.k) {
189
+ case "object":
190
+ for (const prop of ir.props) {
191
+ normalizeDefaults(prop.val, seen);
192
+ if (!prop.hasDefault || prop.defValidated)
193
+ continue;
194
+ let candidate;
195
+ let factory = false;
196
+ if (prop.defFactory && typeof prop.def === "function") {
197
+ candidate = prop.def();
198
+ factory = true;
199
+ }
200
+ else {
201
+ rejectMutableStaticDefault(prop.def);
202
+ candidate = prop.def;
203
+ }
204
+ const output = walk(prop.val, candidate);
205
+ if (output instanceof OmpErrors)
206
+ invalidDefault(`Default for ${String(prop.key)}`, output);
207
+ if (!factory)
208
+ prop.def = output;
209
+ prop.defValidated = true;
210
+ }
211
+ if (ir.index)
212
+ normalizeDefaults(ir.index, seen);
213
+ if (ir.symbolIndex)
214
+ normalizeDefaults(ir.symbolIndex, seen);
215
+ if (ir.patternIndexes) {
216
+ for (const index of ir.patternIndexes) {
217
+ normalizeDefaults(index.key, seen);
218
+ normalizeDefaults(index.val, seen);
219
+ }
220
+ }
221
+ return;
222
+ case "tuple":
223
+ for (let index = 0; index < ir.prefix.length; index++) {
224
+ const item = ir.prefix[index];
225
+ normalizeDefaults(item.val, seen);
226
+ if (!item.hasDefault || item.defValidated)
227
+ continue;
228
+ let candidate;
229
+ let factory = false;
230
+ if (item.defFactory && typeof item.def === "function") {
231
+ candidate = item.def();
232
+ factory = true;
233
+ }
234
+ else {
235
+ rejectMutableStaticDefault(item.def);
236
+ candidate = item.def;
237
+ }
238
+ const output = walk(item.val, candidate);
239
+ if (output instanceof OmpErrors)
240
+ invalidDefault(`Default for [${index}]`, output);
241
+ if (!factory)
242
+ item.def = output;
243
+ item.defValidated = true;
244
+ }
245
+ if (ir.variadic)
246
+ normalizeDefaults(ir.variadic, seen);
247
+ for (const item of ir.postfix)
248
+ normalizeDefaults(item, seen);
249
+ return;
250
+ case "array":
251
+ normalizeDefaults(ir.el, seen);
252
+ return;
253
+ case "union":
254
+ case "intersection":
255
+ for (const member of ir.members)
256
+ normalizeDefaults(member, seen);
257
+ return;
258
+ case "refine":
259
+ normalizeDefaults(ir.base, seen);
260
+ return;
261
+ case "morph":
262
+ normalizeDefaults(ir.input, seen);
263
+ if (ir.out)
264
+ normalizeDefaults(ir.out, seen);
265
+ return;
266
+ default:
267
+ return;
268
+ }
269
+ }
270
+ /** Emitted for `io: 'output'` when a bare pipe makes the output unknowable. */
271
+ const OPAQUE_OUTPUT_IR = { k: "unknown" };
272
+ const typeMethods = {
273
+ describe(description) {
274
+ const ir = { ...this.ir, desc: description, cfg: { ...this.ir.cfg, expected: description } };
275
+ return makeType(ir, this[kSteps], { ...metaOf(this), description });
276
+ },
277
+ configure(config, selector = "self") {
278
+ const selected = selector === "self" ? configureNode(this.ir, config) : configureSelected(this.ir, config, selector);
279
+ return makeType(selected, this[kSteps], {
280
+ ...metaOf(this),
281
+ errorConfig: { ...this.errorConfig, ...errorConfigOf(config) },
282
+ ...(config.description === undefined ? {} : { description: config.description }),
283
+ });
284
+ },
285
+ default(value) {
286
+ const factory = typeof value === "function";
287
+ if (!factory)
288
+ rejectMutableStaticDefault(value);
289
+ const candidate = factory ? value() : value;
290
+ const output = this.run(candidate);
291
+ if (output instanceof OmpErrors)
292
+ invalidDefault("Default", output);
293
+ return makeType(this.ir, this[kSteps], {
294
+ ...metaOf(this),
295
+ defaultValue: value,
296
+ hasDefault: true,
297
+ ...(factory ? {} : { defaultOutput: output, hasDefaultOutput: true }),
298
+ });
299
+ },
300
+ optional() {
301
+ return [this, "?"];
302
+ },
303
+ or(def) {
304
+ const other = parseDef(def, this.resolver);
305
+ const a = embed(this);
306
+ const members = [...(a.k === "union" ? a.members : [a]), ...(other.k === "union" ? other.members : [other])];
307
+ return inheritScope(this, makeType({ k: "union", members }, [], {}));
308
+ },
309
+ equals(def) {
310
+ return irEquals(embed(this), parseDef(def, this.resolver));
311
+ },
312
+ ifEquals(def) {
313
+ return irEquals(embed(this), parseDef(def, this.resolver)) ? this : undefined;
314
+ },
315
+ ifExtends(def) {
316
+ return isSubtype(embed(this), parseDef(def, this.resolver)) ? this : undefined;
317
+ },
318
+ extends(def) {
319
+ return isSubtype(embed(this), parseDef(def, this.resolver));
320
+ },
321
+ overlaps(def) {
322
+ try {
323
+ intersect(embed(this), parseDef(def, this.resolver));
324
+ return true;
325
+ }
326
+ catch (error) {
327
+ if (error instanceof OmpTypeError)
328
+ return false;
329
+ throw error;
330
+ }
331
+ },
332
+ distribute(mapper, reducer) {
333
+ const branches = this.ir.k === "union" ? this.ir.members : [embed(this)];
334
+ const mapped = branches.map(branch => mapper(makeType(branch, [], {})));
335
+ if (reducer !== undefined)
336
+ return reducer(mapped);
337
+ const members = mapped.map(branch => embed(branch));
338
+ return makeType(members.length === 1 ? members[0] : { k: "union", members }, [], {});
339
+ },
340
+ select(kind) {
341
+ return selectNodes(this.ir, kind);
342
+ },
343
+ and(def) {
344
+ return inheritScope(this, makeType(intersect(embed(this), parseDef(def, this.resolver)), [], {}));
345
+ },
346
+ array() {
347
+ return inheritScope(this, makeType({ k: "array", el: embed(this) }, [], {}));
348
+ },
349
+ atLeastLength(bound) {
350
+ return makeType(withLengthBound(this.ir, "min", bound), this[kSteps], metaOf(this));
351
+ },
352
+ atMostLength(bound) {
353
+ return makeType(withLengthBound(this.ir, "max", bound), this[kSteps], metaOf(this));
354
+ },
355
+ moreThanLength(bound) {
356
+ return makeType(withLengthBound(this.ir, "min", bound + 1), this[kSteps], metaOf(this));
357
+ },
358
+ lessThanLength(bound) {
359
+ return makeType(withLengthBound(this.ir, "max", bound - 1), this[kSteps], metaOf(this));
360
+ },
361
+ exactlyLength(bound) {
362
+ const bounded = withLengthBound(withLengthBound(this.ir, "min", bound), "max", bound);
363
+ return makeType(bounded, this[kSteps], metaOf(this));
364
+ },
365
+ atLeast(bound) {
366
+ return makeType(withNumericBound(this.ir, "min", bound), this[kSteps], metaOf(this));
367
+ },
368
+ atMost(bound) {
369
+ return makeType(withNumericBound(this.ir, "max", bound), this[kSteps], metaOf(this));
370
+ },
371
+ moreThan(bound) {
372
+ return makeType(withNumericBound(this.ir, "min", bound, true), this[kSteps], metaOf(this));
373
+ },
374
+ lessThan(bound) {
375
+ return makeType(withNumericBound(this.ir, "max", bound, true), this[kSteps], metaOf(this));
376
+ },
377
+ divisibleBy(divisor) {
378
+ if (this.ir.k !== "number")
379
+ throw new OmpTypeError(`cannot apply divisibility to ${this.ir.k}`);
380
+ if (!Number.isFinite(divisor) || divisor === 0)
381
+ throw new OmpTypeError("divisor must be non-zero");
382
+ return makeType({ ...this.ir, divisor }, this[kSteps], metaOf(this));
383
+ },
384
+ positive() {
385
+ return makeType(withNumericBound(this.ir, "min", 0, true), this[kSteps], metaOf(this));
386
+ },
387
+ negative() {
388
+ return makeType(withNumericBound(this.ir, "max", 0, true), this[kSteps], metaOf(this));
389
+ },
390
+ nonNegative() {
391
+ return makeType(withNumericBound(this.ir, "min", 0), this[kSteps], metaOf(this));
392
+ },
393
+ nonPositive() {
394
+ return makeType(withNumericBound(this.ir, "max", 0), this[kSteps], metaOf(this));
395
+ },
396
+ matching(pattern) {
397
+ return makeType(intersect(this.ir, patternIR(pattern)), this[kSteps], metaOf(this));
398
+ },
399
+ atOrAfter(bound) {
400
+ const timestamp = bound instanceof Date ? bound.valueOf() : bound;
401
+ return dateRefinement(this, timestamp, "at or after", value => value >= timestamp);
402
+ },
403
+ atOrBefore(bound) {
404
+ const timestamp = bound instanceof Date ? bound.valueOf() : bound;
405
+ return dateRefinement(this, timestamp, "at or before", value => value <= timestamp);
406
+ },
407
+ laterThan(bound) {
408
+ const timestamp = bound instanceof Date ? bound.valueOf() : bound;
409
+ return dateRefinement(this, timestamp, "later than", value => value > timestamp);
410
+ },
411
+ earlierThan(bound) {
412
+ const timestamp = bound instanceof Date ? bound.valueOf() : bound;
413
+ return dateRefinement(this, timestamp, "earlier than", value => value < timestamp);
414
+ },
415
+ pipe(...pipes) {
416
+ return appendPipes(this, pipes, false);
417
+ },
418
+ to(def) {
419
+ return appendPipes(this, [makeType(parseDef(def, this.resolver), [], {})], false, true);
420
+ },
421
+ filter(fn) {
422
+ return makeType(this.ir, [{ kind: "filter", fn }, ...this[kSteps]], metaOf(this));
423
+ },
424
+ narrow(fn) {
425
+ return makeType(this.ir, [...this[kSteps], { kind: "narrow", fn }], metaOf(this));
426
+ },
427
+ brand() {
428
+ return this;
429
+ },
430
+ as() {
431
+ return this;
432
+ },
433
+ readonly() {
434
+ return this;
435
+ },
436
+ keyof() {
437
+ return makeType(keyOf(this.ir), [], {});
438
+ },
439
+ get(...path) {
440
+ if (path.length === 0)
441
+ return this;
442
+ let result = this.ir;
443
+ for (const key of path)
444
+ result = getPathIR(result, key);
445
+ return makeType(result, [], {});
446
+ },
447
+ pick(...keys) {
448
+ return makeType(selectObjectProps(this.ir, keys, true, "pick"), [], {});
449
+ },
450
+ omit(...keys) {
451
+ return makeType(selectObjectProps(this.ir, keys, false, "omit"), [], {});
452
+ },
453
+ partial() {
454
+ return makeType(setObjectOptionality(this.ir, true, "partial"), [], {});
455
+ },
456
+ required() {
457
+ return makeType(setObjectOptionality(this.ir, false, "required"), [], {});
458
+ },
459
+ map(mapper) {
460
+ const object = requireObject(this.ir, "map");
461
+ const props = object.props.flatMap(prop => {
462
+ const original = propertyFromIR(prop);
463
+ const mapped = mapper(original);
464
+ return (Array.isArray(mapped) ? mapped : [mapped]).map(property => propertyToIR((property.kind === "required" || property.kind === "optional"
465
+ ? property
466
+ : { ...property, kind: original.kind })));
467
+ });
468
+ return makeType({ ...object, props }, [], {});
469
+ },
470
+ merge(def) {
471
+ const merged = mergeObjectDefinition(this.ir, def, this.resolver);
472
+ return inheritScope(this, makeType(merged, [], {}));
473
+ },
474
+ extract(def) {
475
+ return inheritScope(this, makeType(distributeFilter(this.ir, parseDef(def, this.resolver), true), [], {}));
476
+ },
477
+ exclude(def) {
478
+ return inheritScope(this, makeType(distributeFilter(this.ir, parseDef(def, this.resolver), false), [], {}));
479
+ },
480
+ onUndeclaredKey(behavior) {
481
+ const extras = behavior === "ignore" ? "keep" : behavior;
482
+ const ir = withShallowExtras(this.ir, extras);
483
+ if (extras === "delete" && ir.k === "union") {
484
+ const objects = ir.members.filter((member) => member.k === "object");
485
+ for (let left = 0; left < objects.length; left++) {
486
+ for (let right = left + 1; right < objects.length; right++) {
487
+ const sharedRequired = objects[left].props.some(leftProp => !leftProp.opt &&
488
+ objects[right].props.some(rightProp => !rightProp.opt && rightProp.key === leftProp.key));
489
+ if (!sharedRequired) {
490
+ const leftExpression = expressionOf(objects[left]).replace(/ }$/, ", + (undeclared): delete }");
491
+ const rightExpression = expressionOf(objects[right]).replace(/ }$/, ", + (undeclared): delete }");
492
+ throw new OmpTypeError(`ParseError: An unordered union of a type including a morph and a type with overlapping input is indeterminate:\nLeft: ${leftExpression}\nRight: ${rightExpression}`);
493
+ }
494
+ }
495
+ }
496
+ }
497
+ return makeType(ir, this[kSteps], metaOf(this));
498
+ },
499
+ onDeepUndeclaredKey(behavior) {
500
+ return makeType(withDeepExtras(this.ir, behavior === "ignore" ? "keep" : behavior), this[kSteps], metaOf(this));
501
+ },
502
+ allows(data) {
503
+ const steps = this[kSteps];
504
+ let needsPredicates = false;
505
+ for (const step of steps) {
506
+ if (step.kind !== "pipe") {
507
+ needsPredicates = true;
508
+ break;
509
+ }
510
+ }
511
+ if (!needsPredicates) {
512
+ const allows = compileAllows(this.ir);
513
+ // Shadow the shared dispatcher once this schema has its specialized check.
514
+ this.allows = allows;
515
+ return allows(data);
516
+ }
517
+ for (const step of steps) {
518
+ if (step.kind === "filter" && !step.fn(data, new Ctx(data)))
519
+ return false;
520
+ }
521
+ const out = this[kBase](data);
522
+ if (out instanceof OmpErrors)
523
+ return false;
524
+ for (const step of steps) {
525
+ if (step.kind === "narrow" && !step.fn(out, new Ctx(out)))
526
+ return false;
527
+ }
528
+ return true;
529
+ },
530
+ assert(data) {
531
+ const out = this.run(data);
532
+ if (out instanceof OmpErrors)
533
+ throw new TraversalError(out);
534
+ return out;
535
+ },
536
+ from(data) {
537
+ const out = this.run(data);
538
+ if (out instanceof OmpErrors)
539
+ throw new TraversalError(out);
540
+ return out;
541
+ },
542
+ toJsonSchema(options) {
543
+ const ir = options?.io === "output" ? (this.opaqueOutput ? OPAQUE_OUTPUT_IR : (this.stepOut ?? this.ir)) : this.ir;
544
+ const description = options?.description ?? this.ir.desc;
545
+ if (description === undefined)
546
+ return irToJsonSchema(ir, options);
547
+ return irToJsonSchema(ir, { ...options, description });
548
+ },
549
+ };
550
+ Object.defineProperty(typeMethods, "expression", {
551
+ get() {
552
+ const input = expressionOf(this.ir);
553
+ if (!this.hasSteps)
554
+ return input;
555
+ if (this.opaqueOutput)
556
+ return `(In: ${input}) => Out<unknown>`;
557
+ return `(In: ${input}) => To<${expressionOf(this.stepOut ?? this.ir)}>`;
558
+ },
559
+ });
560
+ Object.defineProperty(typeMethods, "json", {
561
+ get() {
562
+ return arkJsonOf(this.ir);
563
+ },
564
+ });
565
+ Object.defineProperty(typeMethods, "props", {
566
+ get() {
567
+ const object = requireObject(this.ir, "props");
568
+ return object.props.map(prop => propertyFromIR(prop));
569
+ },
570
+ });
571
+ Object.defineProperty(typeMethods, "~standard", {
572
+ get() {
573
+ const jsonSchema = (io, options) => {
574
+ if (options.target !== "draft-2020-12" && options.target !== "draft-07") {
575
+ throw new OmpTypeError(`JSONSchema target '${options.target}' is not supported (must be "draft-2020-12" or "draft-07")`);
576
+ }
577
+ return this.toJsonSchema({ ...options.libraryOptions, target: options.target, io });
578
+ };
579
+ return {
580
+ version: 1,
581
+ vendor: "omptype",
582
+ validate: (value) => {
583
+ const out = this.run(value);
584
+ return out instanceof OmpErrors
585
+ ? { issues: out }
586
+ : { value: out };
587
+ },
588
+ jsonSchema: {
589
+ input: options => jsonSchema("input", options),
590
+ output: options => jsonSchema("output", options),
591
+ },
592
+ };
593
+ },
594
+ });
595
+ Object.defineProperty(typeMethods, "in", {
596
+ get() {
597
+ return makeType(projectIO(this.ir, "in"), [], {});
598
+ },
599
+ });
600
+ Object.defineProperty(typeMethods, "out", {
601
+ get() {
602
+ if (this.opaqueOutput)
603
+ return makeType({ k: "unknown" }, [], {});
604
+ return makeType(projectIO(this.stepOut ?? this.ir, "out"), [], {});
605
+ },
606
+ });
607
+ const allowsMethod = typeMethods.allows;
608
+ const assertMethod = typeMethods.assert;
609
+ const fromMethod = typeMethods.from;
610
+ Object.defineProperties(typeMethods, {
611
+ description: {
612
+ get() {
613
+ return descriptionOf(this.ir);
614
+ },
615
+ },
616
+ allows: {
617
+ get() {
618
+ const allows = (data) => allowsMethod.call(this, data);
619
+ Object.defineProperty(this, "allows", { value: allows, writable: true });
620
+ return allows;
621
+ },
622
+ },
623
+ assert: {
624
+ get() {
625
+ const assert = assertMethod.bind(this);
626
+ Object.defineProperty(this, "assert", { value: assert });
627
+ return assert;
628
+ },
629
+ },
630
+ from: {
631
+ get() {
632
+ const from = fromMethod.bind(this);
633
+ Object.defineProperty(this, "from", { value: from });
634
+ return from;
635
+ },
636
+ },
637
+ pipe: {
638
+ get() {
639
+ const pipe = Object.assign((...pipes) => appendPipes(this, pipes, false), {
640
+ try: (...pipes) => appendPipes(this, pipes, true),
641
+ });
642
+ Object.defineProperty(this, "pipe", { value: pipe });
643
+ return pipe;
644
+ },
645
+ },
646
+ });
647
+ // Share the fluent surface without per-schema method allocations or copies.
648
+ // Function.prototype remains in the chain, except bind is intentionally hidden
649
+ // so generic tool wrappers recognize callable schemas rather than rebinding them.
650
+ Object.setPrototypeOf(typeMethods, Function.prototype);
651
+ Object.defineProperty(typeMethods, "bind", { value: undefined });
652
+ function makeType(ir, steps, meta) {
653
+ let morph = false;
654
+ if (!isSimpleIR(ir)) {
655
+ ir = normalizeIR(ir);
656
+ morph = hasMorph(ir);
657
+ if (morph) {
658
+ normalizeDefaults(ir);
659
+ assertDeterminateMorphUnions(ir);
660
+ }
661
+ }
662
+ let calls = 0;
663
+ let impl = (data) => {
664
+ if (++calls >= JIT_THRESHOLD) {
665
+ impl = compile(ir);
666
+ return impl(data);
667
+ }
668
+ return walk(ir, data);
669
+ };
670
+ const base = (data) => impl(data);
671
+ const errorConfig = meta.errorConfig ?? ir.cfg;
672
+ const filterInput = steps.some(step => step.kind === "filter") ? projectIO(ir, "in") : undefined;
673
+ const validate = steps.length === 0
674
+ ? base
675
+ : (data, contextPath = []) => {
676
+ if (filterInput !== undefined) {
677
+ const inputResult = walk(filterInput, data);
678
+ if (inputResult instanceof OmpErrors)
679
+ return inputResult;
680
+ }
681
+ for (const step of steps) {
682
+ if (step.kind !== "filter")
683
+ continue;
684
+ const ctx = new Ctx(data, contextPath);
685
+ const result = step.fn(data, ctx);
686
+ if (result instanceof OmpErrors)
687
+ return errorConfig === undefined ? result : result.configure(errorConfig);
688
+ if (ctx.errors)
689
+ return errorConfig === undefined ? ctx.errors : ctx.errors.configure(errorConfig);
690
+ if (!result) {
691
+ return OmpErrors.single([], ctx.expectation ??
692
+ (step.fn.name ? `valid according to ${step.fn.name}` : "valid (input predicate failed)"), data, errorConfig);
693
+ }
694
+ }
695
+ let out = base(data);
696
+ if (out instanceof OmpErrors)
697
+ return out;
698
+ for (const step of steps) {
699
+ if (step.kind === "filter")
700
+ continue;
701
+ const ctx = new Ctx(out, contextPath);
702
+ if (step.kind === "narrow") {
703
+ const result = step.fn(out, ctx);
704
+ if (result instanceof OmpErrors) {
705
+ return errorConfig === undefined ? result : result.configure(errorConfig);
706
+ }
707
+ if (ctx.errors)
708
+ return errorConfig === undefined ? ctx.errors : ctx.errors.configure(errorConfig);
709
+ if (!result) {
710
+ return OmpErrors.single([], ctx.expectation ??
711
+ (step.fn.name ? `valid according to ${step.fn.name}` : "valid (narrow predicate failed)"), out, errorConfig);
712
+ }
713
+ }
714
+ else {
715
+ try {
716
+ out = step.fn(out, ctx);
717
+ }
718
+ catch (error) {
719
+ if (!step.try)
720
+ throw error;
721
+ const detail = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
722
+ return OmpErrors.single([], `valid (morph threw ${detail})`, out, errorConfig);
723
+ }
724
+ if (out instanceof OmpErrors) {
725
+ return errorConfig === undefined ? out : out.configure(errorConfig);
726
+ }
727
+ }
728
+ }
729
+ return out;
730
+ };
731
+ const needsClone = morph || steps.some(step => step.kind === "pipe");
732
+ const clone = meta.clone;
733
+ let callable = validate;
734
+ if (needsClone && clone !== undefined) {
735
+ if (clone === false) {
736
+ callable = (data, path) => {
737
+ const out = validate(data, path);
738
+ if (out instanceof OmpErrors ||
739
+ out === data ||
740
+ typeof data !== "object" ||
741
+ data === null ||
742
+ typeof out !== "object" ||
743
+ out === null) {
744
+ return out;
745
+ }
746
+ if (Array.isArray(data) && Array.isArray(out)) {
747
+ data.splice(0, data.length, ...out);
748
+ }
749
+ else {
750
+ const target = data;
751
+ const source = out;
752
+ for (const key of Reflect.ownKeys(target)) {
753
+ if (!Object.hasOwn(source, key))
754
+ Reflect.deleteProperty(target, key);
755
+ }
756
+ for (const key of Reflect.ownKeys(source))
757
+ target[key] = source[key];
758
+ }
759
+ return data;
760
+ };
761
+ }
762
+ else {
763
+ callable = (data, path) => validate(clone(data), path);
764
+ }
765
+ }
766
+ // Root defaults materialize for absent input: `schema(undefined)` and the
767
+ // Standard Schema boundary (`~standard.validate(undefined)`) both yield the
768
+ // default instead of a base-IR rejection. Factories run per call; static
769
+ // defaults reuse the precomputed validated output (mutable statics are
770
+ // rejected at `.default()` time).
771
+ if (meta.hasDefault === true) {
772
+ const inner = callable;
773
+ const value = meta.defaultValue;
774
+ callable = (data, path) => {
775
+ if (data !== undefined)
776
+ return inner(data, path);
777
+ if (meta.hasDefaultOutput === true)
778
+ return meta.defaultOutput;
779
+ return inner(typeof value === "function" ? value() : value, path);
780
+ };
781
+ }
782
+ const self = callable;
783
+ self[IR_BRAND] = true;
784
+ self[kBase] = base;
785
+ self[kSteps] = steps;
786
+ self.ir = ir;
787
+ self.hasSteps = steps.length > 0;
788
+ self.hasDefault = meta.hasDefault === true;
789
+ self.defaultValue = meta.defaultValue;
790
+ self.defaultOutput = meta.defaultOutput;
791
+ self.hasDefaultOutput = meta.hasDefaultOutput === true;
792
+ self.errorConfig = meta.errorConfig ?? ir.cfg;
793
+ self.clone = meta.clone;
794
+ self.run = callable;
795
+ self.$ = ARK_COMPAT_SCOPE;
796
+ for (let i = steps.length - 1; i >= 0; i--) {
797
+ const step = steps[i];
798
+ if (step.kind !== "pipe")
799
+ continue;
800
+ self.stepOut = step.out;
801
+ self.opaqueOutput = step.out === undefined;
802
+ break;
803
+ }
804
+ Object.setPrototypeOf(self, typeMethods);
805
+ return self;
806
+ }
807
+ function appendPipes(source, pipes, catchErrors, forcePipeline = false) {
808
+ let schema = source;
809
+ for (const candidate of pipes) {
810
+ const isSchema = (typeof candidate === "function" || (typeof candidate === "object" && candidate !== null)) &&
811
+ IR_BRAND in candidate;
812
+ if (isSchema) {
813
+ const target = candidate;
814
+ if (!forcePipeline &&
815
+ schema[kSteps].length === 0 &&
816
+ !target.hasSteps &&
817
+ !hasMorph(schema.ir) &&
818
+ !hasMorph(target.ir)) {
819
+ schema = makeType(intersect(schema.ir, target.ir), [], metaOf(schema));
820
+ continue;
821
+ }
822
+ const out = target.opaqueOutput ? undefined : (target.stepOut ?? target.ir);
823
+ schema = makeType(schema.ir, [...schema[kSteps], { kind: "pipe", fn: value => target.run(value), out, try: catchErrors }], metaOf(schema));
824
+ continue;
825
+ }
826
+ if (typeof candidate !== "function")
827
+ throw new OmpTypeError("pipe operands must be functions or Types");
828
+ schema = makeType(schema.ir, [...schema[kSteps], { kind: "pipe", fn: candidate, try: catchErrors }], metaOf(schema));
829
+ }
830
+ return inheritScope(source, schema);
831
+ }
832
+ function projectIO(ir, io) {
833
+ switch (ir.k) {
834
+ case "morph":
835
+ return projectIO(io === "in" || ir.out === undefined ? ir.input : ir.out, io);
836
+ case "sub":
837
+ if (io === "out" && ir.schema.opaqueOutput)
838
+ return { k: "unknown" };
839
+ return projectIO(io === "out" ? (ir.schema.stepOut ?? ir.schema.ir) : ir.schema.ir, io);
840
+ case "array":
841
+ return { ...ir, el: projectIO(ir.el, io) };
842
+ case "tuple":
843
+ return {
844
+ ...ir,
845
+ prefix: ir.prefix.map(item => ({
846
+ ...item,
847
+ opt: io === "in" ? item.opt || item.hasDefault === true : item.opt && !item.hasDefault,
848
+ val: projectIO(item.val, io),
849
+ hasDefault: false,
850
+ def: undefined,
851
+ defFactory: false,
852
+ defValidated: false,
853
+ })),
854
+ variadic: ir.variadic === undefined ? undefined : projectIO(ir.variadic, io),
855
+ postfix: ir.postfix.map(item => projectIO(item, io)),
856
+ };
857
+ case "object":
858
+ return {
859
+ ...ir,
860
+ props: ir.props.map(prop => ({
861
+ ...prop,
862
+ opt: io === "in" ? prop.opt || prop.hasDefault === true : prop.opt && !prop.hasDefault,
863
+ val: projectIO(prop.val, io),
864
+ hasDefault: false,
865
+ def: undefined,
866
+ defFactory: false,
867
+ defValidated: false,
868
+ })),
869
+ index: ir.index === undefined ? undefined : projectIO(ir.index, io),
870
+ symbolIndex: ir.symbolIndex === undefined ? undefined : projectIO(ir.symbolIndex, io),
871
+ patternIndexes: ir.patternIndexes?.map(index => ({
872
+ key: projectIO(index.key, io),
873
+ val: projectIO(index.val, io),
874
+ })),
875
+ extras: ir.extras === "delete" ? (io === "in" ? "keep" : "reject") : ir.extras,
876
+ };
877
+ case "union":
878
+ case "intersection":
879
+ return { ...ir, members: ir.members.map(member => projectIO(member, io)) };
880
+ case "refine":
881
+ return { ...ir, base: projectIO(ir.base, io) };
882
+ case "alias":
883
+ return { ...ir, resolve: () => projectIO(ir.resolve(), io) };
884
+ default:
885
+ return ir;
886
+ }
887
+ }
888
+ function morphIdentities(ir, identities = [], seen = new Set()) {
889
+ if (seen.has(ir))
890
+ return identities;
891
+ seen.add(ir);
892
+ switch (ir.k) {
893
+ case "morph":
894
+ identities.push(ir.out === undefined
895
+ ? ir.fn
896
+ : `declared:${expressionOf(projectIO(ir.input, "in"))}=>${expressionOf(projectIO(ir.out, "out"))}`);
897
+ morphIdentities(ir.input, identities, seen);
898
+ if (ir.out !== undefined)
899
+ morphIdentities(ir.out, identities, seen);
900
+ break;
901
+ case "sub": {
902
+ const schema = ir.schema;
903
+ for (const step of schema[kSteps])
904
+ if (step.kind === "pipe")
905
+ identities.push(step.fn);
906
+ morphIdentities(schema.ir, identities, seen);
907
+ break;
908
+ }
909
+ case "array":
910
+ morphIdentities(ir.el, identities, seen);
911
+ break;
912
+ case "tuple":
913
+ for (const item of ir.prefix)
914
+ morphIdentities(item.val, identities, seen);
915
+ if (ir.variadic !== undefined)
916
+ morphIdentities(ir.variadic, identities, seen);
917
+ for (const item of ir.postfix)
918
+ morphIdentities(item, identities, seen);
919
+ break;
920
+ case "object":
921
+ if (ir.extras === "delete")
922
+ identities.push(ir);
923
+ for (const prop of ir.props)
924
+ morphIdentities(prop.val, identities, seen);
925
+ if (ir.index !== undefined)
926
+ morphIdentities(ir.index, identities, seen);
927
+ if (ir.symbolIndex !== undefined)
928
+ morphIdentities(ir.symbolIndex, identities, seen);
929
+ for (const index of ir.patternIndexes ?? [])
930
+ morphIdentities(index.val, identities, seen);
931
+ break;
932
+ case "union":
933
+ case "intersection":
934
+ for (const member of ir.members)
935
+ morphIdentities(member, identities, seen);
936
+ break;
937
+ case "refine":
938
+ morphIdentities(ir.base, identities, seen);
939
+ break;
940
+ case "alias":
941
+ morphIdentities(ir.resolve(), identities, seen);
942
+ break;
943
+ }
944
+ return identities;
945
+ }
946
+ function assertDeterminateMorphUnions(ir, seen = new Set()) {
947
+ if (seen.has(ir))
948
+ return;
949
+ seen.add(ir);
950
+ if (ir.k === "union") {
951
+ for (let leftIndex = 0; leftIndex < ir.members.length; leftIndex++) {
952
+ const left = ir.members[leftIndex];
953
+ const leftMorphs = morphIdentities(left);
954
+ for (let rightIndex = leftIndex + 1; rightIndex < ir.members.length; rightIndex++) {
955
+ const right = ir.members[rightIndex];
956
+ const rightMorphs = morphIdentities(right);
957
+ if (leftMorphs.length === 0 && rightMorphs.length === 0)
958
+ continue;
959
+ if (leftMorphs.length === rightMorphs.length &&
960
+ leftMorphs.every((identity, index) => identity === rightMorphs[index])) {
961
+ continue;
962
+ }
963
+ // Unwrap one alias level eagerly: the disjointness probe relies on
964
+ // intersect() throwing, and deferred alias intersections resolve lazily.
965
+ let leftInput = projectIO(left, "in");
966
+ let rightInput = projectIO(right, "in");
967
+ if (leftInput.k === "alias")
968
+ leftInput = leftInput.resolve();
969
+ if (rightInput.k === "alias")
970
+ rightInput = rightInput.resolve();
971
+ if (leftInput.k === "object" && rightInput.k === "object") {
972
+ const leftKeys = new Set(leftInput.props.map(prop => prop.key));
973
+ const rightKeys = new Set(rightInput.props.map(prop => prop.key));
974
+ const leftRejectsRequiredRight = leftInput.extras === "reject" &&
975
+ rightInput.props.some(prop => !prop.opt && !prop.hasDefault && !leftKeys.has(prop.key));
976
+ const rightRejectsRequiredLeft = rightInput.extras === "reject" &&
977
+ leftInput.props.some(prop => !prop.opt && !prop.hasDefault && !rightKeys.has(prop.key));
978
+ if (leftRejectsRequiredRight || rightRejectsRequiredLeft)
979
+ continue;
980
+ }
981
+ try {
982
+ intersect(leftInput, rightInput);
983
+ }
984
+ catch (error) {
985
+ if (error instanceof OmpTypeError)
986
+ continue;
987
+ throw error;
988
+ }
989
+ throw new OmpTypeError("an unordered union with overlapping morph inputs is indeterminate");
990
+ }
991
+ }
992
+ }
993
+ switch (ir.k) {
994
+ case "alias":
995
+ assertDeterminateMorphUnions(ir.resolve(), seen);
996
+ break;
997
+ case "morph":
998
+ assertDeterminateMorphUnions(ir.input, seen);
999
+ if (ir.out !== undefined)
1000
+ assertDeterminateMorphUnions(ir.out, seen);
1001
+ break;
1002
+ case "sub":
1003
+ assertDeterminateMorphUnions(ir.schema.ir, seen);
1004
+ break;
1005
+ case "array":
1006
+ assertDeterminateMorphUnions(ir.el, seen);
1007
+ break;
1008
+ case "tuple":
1009
+ for (const item of ir.prefix)
1010
+ assertDeterminateMorphUnions(item.val, seen);
1011
+ if (ir.variadic !== undefined)
1012
+ assertDeterminateMorphUnions(ir.variadic, seen);
1013
+ for (const item of ir.postfix)
1014
+ assertDeterminateMorphUnions(item, seen);
1015
+ break;
1016
+ case "object":
1017
+ for (const prop of ir.props)
1018
+ assertDeterminateMorphUnions(prop.val, seen);
1019
+ if (ir.index !== undefined)
1020
+ assertDeterminateMorphUnions(ir.index, seen);
1021
+ if (ir.symbolIndex !== undefined)
1022
+ assertDeterminateMorphUnions(ir.symbolIndex, seen);
1023
+ for (const index of ir.patternIndexes ?? [])
1024
+ assertDeterminateMorphUnions(index.val, seen);
1025
+ break;
1026
+ case "union":
1027
+ case "intersection":
1028
+ for (const member of ir.members)
1029
+ assertDeterminateMorphUnions(member, seen);
1030
+ break;
1031
+ case "refine":
1032
+ assertDeterminateMorphUnions(ir.base, seen);
1033
+ break;
1034
+ }
1035
+ }
1036
+ function getPathIR(ir, requestedKey) {
1037
+ let key = requestedKey;
1038
+ if ((typeof key === "function" || (typeof key === "object" && key !== null)) && IR_BRAND in key) {
1039
+ const keySchema = key;
1040
+ if (keySchema.ir.k === "symbol")
1041
+ key = Symbol.for("omptype.index");
1042
+ else {
1043
+ const arrayIndex = type.arrayIndex;
1044
+ if (keySchema === arrayIndex)
1045
+ key = 0;
1046
+ else {
1047
+ throw new OmpTypeError(`${keySchema.expression} is not allowed as an array or object index; use a concrete property key`);
1048
+ }
1049
+ }
1050
+ }
1051
+ if (typeof key !== "string" && typeof key !== "number" && typeof key !== "symbol") {
1052
+ throw new OmpTypeError(`get keys must be strings, numbers, or symbols`);
1053
+ }
1054
+ if (ir.k === "alias")
1055
+ return getPathIR(ir.resolve(), key);
1056
+ if (ir.k === "sub")
1057
+ return getPathIR(ir.schema.ir, key);
1058
+ if (ir.k === "union") {
1059
+ return unionOf(ir.members.map(member => getPathIR(member, key)));
1060
+ }
1061
+ if (ir.k === "array") {
1062
+ const index = typeof key === "number" ? key : typeof key === "string" && /^\d+$/.test(key) ? Number(key) : -1;
1063
+ if (!Number.isSafeInteger(index) || index < 0)
1064
+ throw new OmpTypeError(`key ${String(key)} is not declared`);
1065
+ return unionOf([ir.el, { k: "undefined" }]);
1066
+ }
1067
+ if (ir.k === "tuple") {
1068
+ const index = typeof key === "number" ? key : typeof key === "string" && /^\d+$/.test(key) ? Number(key) : -1;
1069
+ if (!Number.isSafeInteger(index) || index < 0)
1070
+ throw new OmpTypeError(`key ${String(key)} is not declared`);
1071
+ if (index < ir.prefix.length) {
1072
+ const item = ir.prefix[index];
1073
+ return item.opt ? unionOf([{ k: "undefined" }, item.val]) : item.val;
1074
+ }
1075
+ if (ir.variadic === undefined)
1076
+ throw new OmpTypeError(`key ${String(key)} is not declared`);
1077
+ return unionOf([{ k: "undefined" }, ir.variadic, ...ir.postfix]);
1078
+ }
1079
+ if (ir.k === "undefined")
1080
+ return ir;
1081
+ if (ir.k !== "object")
1082
+ throw new OmpTypeError("get requires an object schema");
1083
+ const matches = [];
1084
+ const prop = ir.props.find(candidate => candidate.key === String(key));
1085
+ if (prop !== undefined)
1086
+ matches.push(prop.val);
1087
+ if (typeof key === "string") {
1088
+ if (ir.index !== undefined)
1089
+ matches.push(ir.index);
1090
+ for (const index of ir.patternIndexes ?? []) {
1091
+ if (!(walk(index.key, key) instanceof OmpErrors))
1092
+ matches.push(index.val);
1093
+ }
1094
+ }
1095
+ else if (typeof key === "symbol" && ir.symbolIndex !== undefined) {
1096
+ matches.push(ir.symbolIndex);
1097
+ }
1098
+ if (matches.length === 0)
1099
+ throw new OmpTypeError(`key ${String(key)} is not declared`);
1100
+ const value = matches.reduce((left, right) => intersect(left, right));
1101
+ return prop !== undefined && !prop.opt ? value : unionOf([value, { k: "undefined" }]);
1102
+ }
1103
+ function unionOf(members) {
1104
+ const flattened = members.flatMap(member => (member.k === "union" ? member.members : [member]));
1105
+ return flattened.length === 1 ? flattened[0] : { k: "union", members: flattened };
1106
+ }
1107
+ function expressionOf(ir, ancestors = new Set()) {
1108
+ if (ancestors.has(ir))
1109
+ return ir.k === "alias" ? ir.name : ir.k;
1110
+ const nextAncestors = new Set(ancestors);
1111
+ nextAncestors.add(ir);
1112
+ const child = (node) => expressionOf(node, nextAncestors);
1113
+ switch (ir.k) {
1114
+ case "alias":
1115
+ return child(ir.resolve());
1116
+ case "sub":
1117
+ return child(ir.schema.ir);
1118
+ case "unknown":
1119
+ case "null":
1120
+ case "undefined":
1121
+ case "boolean":
1122
+ case "bigint":
1123
+ case "symbol":
1124
+ case "never":
1125
+ return ir.k;
1126
+ case "anyobject":
1127
+ return "object";
1128
+ case "string":
1129
+ return "string";
1130
+ case "number":
1131
+ return ir.divisor !== undefined ? `number % ${ir.divisor}` : ir.int ? "number % 1" : "number";
1132
+ case "lit":
1133
+ return typeof ir.v === "string" ? JSON.stringify(ir.v) : String(ir.v);
1134
+ case "array": {
1135
+ const element = child(ir.el);
1136
+ return `${ir.el.k === "union" || ir.el.k === "intersection" ? `(${element})` : element}[]`;
1137
+ }
1138
+ case "tuple": {
1139
+ const items = ir.prefix.map(item => {
1140
+ const value = child(item.val);
1141
+ if (item.hasDefault)
1142
+ return `${value} = ${child({ k: "lit", v: item.def })}`;
1143
+ return `${value}${item.opt ? "?" : ""}`;
1144
+ });
1145
+ if (ir.variadic !== undefined)
1146
+ items.push(`...${child(ir.variadic)}[]`);
1147
+ items.push(...ir.postfix.map(child));
1148
+ return `[${items.join(", ")}]`;
1149
+ }
1150
+ case "object": {
1151
+ const properties = ir.props.map(prop => `${String(prop.key)}${prop.opt ? "?" : ""}: ${child(prop.val)}`);
1152
+ if (ir.index !== undefined)
1153
+ properties.unshift(`[string]: ${child(ir.index)}`);
1154
+ if (ir.symbolIndex !== undefined)
1155
+ properties.unshift(`[symbol]: ${child(ir.symbolIndex)}`);
1156
+ return `{ ${properties.join(", ")} }`;
1157
+ }
1158
+ case "union":
1159
+ return [...new Set(ir.members.map(child))].join(" | ");
1160
+ case "intersection":
1161
+ return ir.members.map(child).join(" & ");
1162
+ case "refine":
1163
+ return child(ir.base);
1164
+ case "morph":
1165
+ return `(In: ${child(ir.input)}) => Out<${child(ir.out ?? { k: "unknown" })}>`;
1166
+ case "instance":
1167
+ return ir.ctor.name || "object";
1168
+ }
1169
+ }
1170
+ function arkJsonOf(ir, ancestors = new Set()) {
1171
+ if (ancestors.has(ir))
1172
+ return ir.k === "alias" ? { alias: ir.name } : { cyclic: ir.k };
1173
+ const nextAncestors = new Set(ancestors);
1174
+ nextAncestors.add(ir);
1175
+ const child = (node) => arkJsonOf(node, nextAncestors);
1176
+ switch (ir.k) {
1177
+ case "alias":
1178
+ return child(ir.resolve());
1179
+ case "sub":
1180
+ return child(ir.schema.ir);
1181
+ case "lit":
1182
+ return {
1183
+ unit: ir.v === undefined ? "undefined" : typeof ir.v === "bigint" ? `${ir.v}n` : ir.v,
1184
+ };
1185
+ case "null":
1186
+ return { unit: null };
1187
+ case "undefined":
1188
+ return { unit: "undefined" };
1189
+ case "boolean":
1190
+ return [{ unit: false }, { unit: true }];
1191
+ case "union":
1192
+ case "intersection":
1193
+ return ir.members.map(child);
1194
+ case "array":
1195
+ return { proto: "Array", sequence: child(ir.el) };
1196
+ case "tuple":
1197
+ return {
1198
+ proto: "Array",
1199
+ sequence: {
1200
+ prefix: ir.prefix.map(item => child(item.val)),
1201
+ ...(ir.variadic === undefined ? {} : { variadic: child(ir.variadic) }),
1202
+ ...(ir.postfix.length === 0 ? {} : { postfix: ir.postfix.map(child) }),
1203
+ },
1204
+ };
1205
+ case "object":
1206
+ return {
1207
+ domain: "object",
1208
+ required: ir.props
1209
+ .filter(prop => !prop.opt && !prop.hasDefault)
1210
+ .map(prop => ({ key: prop.key, value: child(prop.val) })),
1211
+ optional: ir.props
1212
+ .filter(prop => prop.opt || prop.hasDefault)
1213
+ .map(prop => ({
1214
+ key: prop.key,
1215
+ value: child(prop.val),
1216
+ ...(prop.hasDefault
1217
+ ? {
1218
+ default: prop.defFactory && typeof prop.def === "function"
1219
+ ? `$ark.${prop.def.name || "default"}`
1220
+ : prop.def,
1221
+ }
1222
+ : {}),
1223
+ })),
1224
+ };
1225
+ case "refine":
1226
+ return child(ir.base);
1227
+ case "morph":
1228
+ return { in: child(ir.input), ...(ir.out === undefined ? {} : { declaredOut: child(ir.out) }) };
1229
+ case "instance":
1230
+ return { proto: ir.ctor.name };
1231
+ case "anyobject":
1232
+ return { domain: "object" };
1233
+ default:
1234
+ return ir.k;
1235
+ }
1236
+ }
1237
+ function requireObject(ir, operation) {
1238
+ if (ir.k !== "object")
1239
+ throw new OmpTypeError(`${operation} requires an object schema`);
1240
+ return ir;
1241
+ }
1242
+ function selectObjectProps(ir, keys, keepSelected, operation) {
1243
+ const object = requireObject(ir, operation);
1244
+ const selected = new Set(keys);
1245
+ for (const key of selected) {
1246
+ if (!object.props.some(prop => prop.key === key))
1247
+ throw new OmpTypeError(`key ${String(key)} does not exist`);
1248
+ }
1249
+ return { ...object, props: object.props.filter(prop => selected.has(prop.key) === keepSelected) };
1250
+ }
1251
+ function setObjectOptionality(ir, optional, operation) {
1252
+ const object = requireObject(ir, operation);
1253
+ return { ...object, props: object.props.map(prop => ({ ...prop, opt: optional })) };
1254
+ }
1255
+ function mergeObjectDefinition(ir, definition, resolve) {
1256
+ return mergeObjects(requireObject(ir, "merge"), requireObject(parseDef(definition, resolve), "merge"));
1257
+ }
1258
+ function propertyFromIR(prop) {
1259
+ return {
1260
+ kind: prop.opt ? "optional" : "required",
1261
+ key: prop.key,
1262
+ value: makeType(prop.val, [], {}),
1263
+ ...(prop.hasDefault ? { default: prop.def } : {}),
1264
+ meta: {},
1265
+ };
1266
+ }
1267
+ function propertyToIR(property) {
1268
+ if (property.kind !== "required" && property.kind !== "optional") {
1269
+ throw new OmpTypeError(`mapped property ${String(property.key)} has invalid kind`);
1270
+ }
1271
+ if (!(IR_BRAND in property.value)) {
1272
+ throw new OmpTypeError(`mapped property ${String(property.key)} must contain a schema value`);
1273
+ }
1274
+ const hasDefault = Object.hasOwn(property, "default");
1275
+ return {
1276
+ key: property.key,
1277
+ opt: property.kind === "optional",
1278
+ val: embed(property.value),
1279
+ ...(hasDefault
1280
+ ? { def: property.default, defFactory: typeof property.default === "function", hasDefault: true }
1281
+ : {}),
1282
+ };
1283
+ }
1284
+ function acceptsDateIR(ir) {
1285
+ if (ir.k === "instance")
1286
+ return ir.ctor === Date;
1287
+ if (ir.k === "refine")
1288
+ return acceptsDateIR(ir.base);
1289
+ if (ir.k === "union")
1290
+ return ir.members.every(acceptsDateIR);
1291
+ return false;
1292
+ }
1293
+ function dateRefinement(schema, timestamp, relation, predicate) {
1294
+ if (!Number.isFinite(timestamp))
1295
+ throw new OmpTypeError("date bound must be valid");
1296
+ if (!acceptsDateIR(schema.ir))
1297
+ throw new OmpTypeError("date bounds require a Date type");
1298
+ const bound = new Date(timestamp);
1299
+ return makeType({
1300
+ k: "refine",
1301
+ base: schema.ir,
1302
+ pred: value => value instanceof Date && predicate(value.valueOf()),
1303
+ expected: `a Date ${relation} ${bound.toISOString()}`,
1304
+ json: relation.includes("after") ? { minimum: bound.toISOString() } : { maximum: bound.toISOString() },
1305
+ }, schema[kSteps], metaOf(schema));
1306
+ }
1307
+ function selectNodes(root, kind) {
1308
+ const selected = [];
1309
+ const seen = new Set();
1310
+ const visit = (node) => {
1311
+ if (seen.has(node))
1312
+ return;
1313
+ seen.add(node);
1314
+ const nodeKind = node.k === "lit" ? "unit" : node.k;
1315
+ if (kind === nodeKind || kind === node.k) {
1316
+ selected.push(node.k === "lit" ? { kind: nodeKind, node, unit: node.v } : { kind: nodeKind, node });
1317
+ }
1318
+ switch (node.k) {
1319
+ case "alias":
1320
+ visit(node.resolve());
1321
+ break;
1322
+ case "array":
1323
+ visit(node.el);
1324
+ break;
1325
+ case "tuple":
1326
+ for (const item of node.prefix)
1327
+ visit(item.val);
1328
+ if (node.variadic !== undefined)
1329
+ visit(node.variadic);
1330
+ for (const item of node.postfix)
1331
+ visit(item);
1332
+ break;
1333
+ case "object":
1334
+ for (const prop of node.props)
1335
+ visit(prop.val);
1336
+ if (node.index !== undefined)
1337
+ visit(node.index);
1338
+ if (node.symbolIndex !== undefined)
1339
+ visit(node.symbolIndex);
1340
+ for (const index of node.patternIndexes ?? []) {
1341
+ visit(index.key);
1342
+ visit(index.val);
1343
+ }
1344
+ break;
1345
+ case "union":
1346
+ case "intersection":
1347
+ for (const member of node.members)
1348
+ visit(member);
1349
+ break;
1350
+ case "refine":
1351
+ visit(node.base);
1352
+ break;
1353
+ case "morph":
1354
+ visit(node.input);
1355
+ if (node.out !== undefined)
1356
+ visit(node.out);
1357
+ break;
1358
+ case "sub":
1359
+ visit(node.schema.ir);
1360
+ break;
1361
+ }
1362
+ };
1363
+ visit(root);
1364
+ return selected;
1365
+ }
1366
+ function mergeObjects(left, right) {
1367
+ const props = [...left.props];
1368
+ for (const prop of right.props) {
1369
+ const index = props.findIndex(candidate => candidate.key === prop.key);
1370
+ if (index < 0)
1371
+ props.push(prop);
1372
+ else
1373
+ props[index] = prop;
1374
+ }
1375
+ return {
1376
+ k: "object",
1377
+ props,
1378
+ index: right.index ?? left.index,
1379
+ symbolIndex: right.symbolIndex ?? left.symbolIndex,
1380
+ patternIndexes: left.patternIndexes === undefined && right.patternIndexes === undefined
1381
+ ? undefined
1382
+ : [...(left.patternIndexes ?? []), ...(right.patternIndexes ?? [])],
1383
+ extras: right.extras === "keep" ? left.extras : right.extras,
1384
+ };
1385
+ }
1386
+ function withShallowExtras(ir, extras) {
1387
+ if (ir.k === "object")
1388
+ return { ...ir, extras };
1389
+ if (ir.k === "union")
1390
+ return { ...ir, members: ir.members.map(member => withShallowExtras(member, extras)) };
1391
+ if (ir.k === "alias")
1392
+ return withShallowExtras(ir.resolve(), extras);
1393
+ throw new OmpTypeError("onUndeclaredKey requires an object schema");
1394
+ }
1395
+ function withDeepExtras(ir, extras) {
1396
+ switch (ir.k) {
1397
+ case "object":
1398
+ return {
1399
+ ...ir,
1400
+ extras,
1401
+ props: ir.props.map(prop => ({ ...prop, val: withDeepExtras(prop.val, extras) })),
1402
+ index: ir.index === undefined ? undefined : withDeepExtras(ir.index, extras),
1403
+ symbolIndex: ir.symbolIndex === undefined ? undefined : withDeepExtras(ir.symbolIndex, extras),
1404
+ patternIndexes: ir.patternIndexes?.map(index => ({
1405
+ key: withDeepExtras(index.key, extras),
1406
+ val: withDeepExtras(index.val, extras),
1407
+ })),
1408
+ };
1409
+ case "array":
1410
+ return { ...ir, el: withDeepExtras(ir.el, extras) };
1411
+ case "tuple":
1412
+ return {
1413
+ ...ir,
1414
+ prefix: ir.prefix.map(item => ({ ...item, val: withDeepExtras(item.val, extras) })),
1415
+ variadic: ir.variadic === undefined ? undefined : withDeepExtras(ir.variadic, extras),
1416
+ postfix: ir.postfix.map(item => withDeepExtras(item, extras)),
1417
+ };
1418
+ case "union":
1419
+ case "intersection":
1420
+ return { ...ir, members: ir.members.map(member => withDeepExtras(member, extras)) };
1421
+ case "refine":
1422
+ return { ...ir, base: withDeepExtras(ir.base, extras) };
1423
+ case "morph":
1424
+ return {
1425
+ ...ir,
1426
+ input: withDeepExtras(ir.input, extras),
1427
+ out: ir.out === undefined ? undefined : withDeepExtras(ir.out, extras),
1428
+ };
1429
+ default:
1430
+ return ir;
1431
+ }
1432
+ }
1433
+ function intersectTupleWithArray(tuple, array) {
1434
+ if (array.min !== undefined || array.max !== undefined) {
1435
+ return { k: "intersection", members: [tuple, array] };
1436
+ }
1437
+ return {
1438
+ ...tuple,
1439
+ prefix: tuple.prefix.map(item => ({ ...item, val: intersect(item.val, array.el) })),
1440
+ variadic: tuple.variadic === undefined ? undefined : intersect(tuple.variadic, array.el),
1441
+ postfix: tuple.postfix.map(item => intersect(item, array.el)),
1442
+ };
1443
+ }
1444
+ function intersectTuples(left, right) {
1445
+ if (left.postfix.length !== 0 ||
1446
+ right.postfix.length !== 0 ||
1447
+ left.prefix.some(item => item.hasDefault) ||
1448
+ right.prefix.some(item => item.hasDefault)) {
1449
+ return { k: "intersection", members: [left, right] };
1450
+ }
1451
+ const leftRequired = left.prefix.filter(item => !item.opt).length;
1452
+ const rightRequired = right.prefix.filter(item => !item.opt).length;
1453
+ const minimum = Math.max(leftRequired, rightRequired);
1454
+ const leftMaximum = left.variadic === undefined ? left.prefix.length : Number.POSITIVE_INFINITY;
1455
+ const rightMaximum = right.variadic === undefined ? right.prefix.length : Number.POSITIVE_INFINITY;
1456
+ const maximum = Math.min(leftMaximum, rightMaximum);
1457
+ if (minimum > maximum)
1458
+ throw new OmpTypeError("tuple length intersection is unsatisfiable");
1459
+ const prefixLength = Number.isFinite(maximum) ? maximum : Math.max(left.prefix.length, right.prefix.length);
1460
+ const prefix = [];
1461
+ for (let index = 0; index < prefixLength; index++) {
1462
+ const leftItem = left.prefix[index];
1463
+ const rightItem = right.prefix[index];
1464
+ const leftNode = leftItem?.val ?? left.variadic;
1465
+ const rightNode = rightItem?.val ?? right.variadic;
1466
+ if (leftNode === undefined || rightNode === undefined)
1467
+ break;
1468
+ const required = (leftItem !== undefined && !leftItem.opt) || (rightItem !== undefined && !rightItem.opt);
1469
+ try {
1470
+ prefix.push({ val: intersect(leftNode, rightNode), opt: !required });
1471
+ }
1472
+ catch (error) {
1473
+ if (required || !(error instanceof OmpTypeError))
1474
+ throw error;
1475
+ break;
1476
+ }
1477
+ }
1478
+ const variadic = leftMaximum === Number.POSITIVE_INFINITY && rightMaximum === Number.POSITIVE_INFINITY
1479
+ ? intersect(left.variadic, right.variadic)
1480
+ : undefined;
1481
+ return { k: "tuple", prefix, variadic, postfix: [] };
1482
+ }
1483
+ const kIntersections = Symbol("omptype.intersections");
1484
+ /** Intersect two IR nodes, rejecting statically disjoint domains. */
1485
+ function intersect(a, b) {
1486
+ if (a.k === "alias" || b.k === "alias") {
1487
+ // Defer through a lazy alias so cyclic references terminate: revisiting
1488
+ // the same pair while it is being resolved returns the same node instead
1489
+ // of recursing forever.
1490
+ const target = a;
1491
+ target[kIntersections] ??= new WeakMap();
1492
+ const cache = target[kIntersections];
1493
+ const existing = cache.get(b);
1494
+ if (existing !== undefined)
1495
+ return existing;
1496
+ let resolved;
1497
+ const reference = {
1498
+ k: "alias",
1499
+ name: a.k === "alias" ? a.name : b.k === "alias" ? b.name : "intersection",
1500
+ resolve: () => (resolved ??= intersectResolved(a.k === "alias" ? a.resolve() : a, b.k === "alias" ? b.resolve() : b)),
1501
+ };
1502
+ cache.set(b, reference);
1503
+ return reference;
1504
+ }
1505
+ return intersectResolved(a, b);
1506
+ }
1507
+ function intersectResolved(a, b) {
1508
+ if (a.k === "never" || b.k === "never")
1509
+ throw new OmpTypeError("intersection with never is unsatisfiable");
1510
+ if (a.k === "unknown")
1511
+ return b;
1512
+ if (b.k === "unknown")
1513
+ return a;
1514
+ if (a === b)
1515
+ return a;
1516
+ if (a.k === "morph" && b.k === "morph") {
1517
+ if (a.fn !== b.fn || a.out !== b.out) {
1518
+ throw new OmpTypeError("intersection of distinct morphs is indeterminate");
1519
+ }
1520
+ return { ...a, input: intersect(a.input, b.input) };
1521
+ }
1522
+ if (a.k === "morph")
1523
+ return { ...a, input: intersect(a.input, b) };
1524
+ if (b.k === "morph")
1525
+ return { ...b, input: intersect(a, b.input) };
1526
+ if (a.k === "sub" && a.schema.hasSteps) {
1527
+ if (b.k === "sub" && b.schema.hasSteps) {
1528
+ if (a.schema === b.schema)
1529
+ return a;
1530
+ throw new OmpTypeError("intersection of distinct morphs is indeterminate");
1531
+ }
1532
+ const schema = a.schema;
1533
+ return embed(makeType(intersect(schema.ir, b), schema[kSteps], metaOf(schema)));
1534
+ }
1535
+ if (b.k === "sub" && b.schema.hasSteps)
1536
+ return intersect(b, a);
1537
+ if (a.k === "union" || b.k === "union") {
1538
+ const union = a.k === "union" ? a : b.k === "union" ? b : undefined;
1539
+ if (union === undefined)
1540
+ throw new OmpTypeError("union intersection invariant failed");
1541
+ const branches = union.members;
1542
+ const other = a.k === "union" ? b : a;
1543
+ const members = [];
1544
+ for (const branch of branches) {
1545
+ try {
1546
+ members.push(intersect(branch, other));
1547
+ }
1548
+ catch (error) {
1549
+ if (!(error instanceof OmpTypeError))
1550
+ throw error;
1551
+ }
1552
+ }
1553
+ if (members.length === 0)
1554
+ throw new OmpTypeError("intersection has no satisfiable branches");
1555
+ return members.length === 1 ? members[0] : { k: "union", members };
1556
+ }
1557
+ if (a.k === "lit") {
1558
+ if (walk(b, a.v) instanceof OmpErrors)
1559
+ throw new OmpTypeError("literal is excluded by the intersection");
1560
+ return a;
1561
+ }
1562
+ if (b.k === "lit")
1563
+ return intersect(b, a);
1564
+ if (a.k === "object" && b.k === "object") {
1565
+ const props = [...a.props];
1566
+ for (const bp of b.props) {
1567
+ const index = props.findIndex(prop => prop.key === bp.key);
1568
+ if (index < 0)
1569
+ props.push(bp);
1570
+ else {
1571
+ const ap = props[index];
1572
+ const required = (!ap.opt && !ap.hasDefault) || (!bp.opt && !bp.hasDefault);
1573
+ if (ap.hasDefault && bp.hasDefault && !Object.is(ap.def, bp.def)) {
1574
+ throw new OmpTypeError(`ParseError: Invalid intersection of default values ${String(ap.def)} & ${String(bp.def)}`);
1575
+ }
1576
+ const defaulted = required ? undefined : ap.hasDefault ? ap : bp.hasDefault ? bp : undefined;
1577
+ props[index] = {
1578
+ key: ap.key,
1579
+ opt: ap.opt && bp.opt,
1580
+ val: intersect(ap.val, bp.val),
1581
+ ...(defaulted
1582
+ ? {
1583
+ def: defaulted.def,
1584
+ defFactory: defaulted.defFactory,
1585
+ hasDefault: true,
1586
+ defValidated: defaulted.defValidated,
1587
+ }
1588
+ : {}),
1589
+ };
1590
+ }
1591
+ }
1592
+ const extras = a.extras === "reject" || b.extras === "reject"
1593
+ ? "reject"
1594
+ : a.extras === "delete" || b.extras === "delete"
1595
+ ? "delete"
1596
+ : "keep";
1597
+ const index = a.index && b.index ? intersect(a.index, b.index) : (a.index ?? b.index);
1598
+ return { k: "object", props, index, extras };
1599
+ }
1600
+ if (a.k === "string" && b.k === "string") {
1601
+ const min = maxOf(a.min, b.min);
1602
+ const max = minOf(a.max, b.max);
1603
+ if (min !== undefined && max !== undefined && min > max) {
1604
+ throw new OmpTypeError("string length intersection is unsatisfiable");
1605
+ }
1606
+ return { k: "string", min, max, url: a.url || b.url };
1607
+ }
1608
+ if (a.k === "number" && b.k === "number") {
1609
+ const min = maxOf(a.min, b.min);
1610
+ const max = minOf(a.max, b.max);
1611
+ const xmin = min !== undefined && ((a.min === min && a.xmin === true) || (b.min === min && b.xmin === true));
1612
+ const xmax = max !== undefined && ((a.max === max && a.xmax === true) || (b.max === max && b.xmax === true));
1613
+ if (min !== undefined && max !== undefined && (min > max || (min === max && (xmin || xmax)))) {
1614
+ throw new OmpTypeError("numeric range intersection is unsatisfiable");
1615
+ }
1616
+ if (a.divisor !== undefined && b.divisor !== undefined && a.divisor !== b.divisor) {
1617
+ return { k: "intersection", members: [a, b] };
1618
+ }
1619
+ return {
1620
+ k: "number",
1621
+ int: a.int || b.int,
1622
+ divisor: a.divisor ?? b.divisor,
1623
+ min,
1624
+ max,
1625
+ xmin,
1626
+ xmax,
1627
+ };
1628
+ }
1629
+ if (a.k === "array" && b.k === "array") {
1630
+ const min = maxOf(a.min, b.min);
1631
+ const max = minOf(a.max, b.max);
1632
+ if (min !== undefined && max !== undefined && min > max) {
1633
+ throw new OmpTypeError("array length intersection is unsatisfiable");
1634
+ }
1635
+ return { k: "array", el: intersect(a.el, b.el), min, max };
1636
+ }
1637
+ if (a.k === "tuple" && b.k === "tuple")
1638
+ return intersectTuples(a, b);
1639
+ if (a.k === "tuple" && b.k === "array")
1640
+ return intersectTupleWithArray(a, b);
1641
+ if (a.k === "array" && b.k === "tuple")
1642
+ return intersectTupleWithArray(b, a);
1643
+ if (a.k === "instance" && b.k === "instance") {
1644
+ if (a.ctor === b.ctor || a.ctor.prototype instanceof b.ctor)
1645
+ return a;
1646
+ if (b.ctor.prototype instanceof a.ctor)
1647
+ return b;
1648
+ throw new OmpTypeError(`intersection of ${a.expected} and ${b.expected} is unsatisfiable`);
1649
+ }
1650
+ if (a.k === b.k && ["null", "undefined", "boolean", "bigint", "symbol", "anyobject"].includes(a.k))
1651
+ return a;
1652
+ if ((a.k === "object" && (b.k === "array" || b.k === "tuple")) ||
1653
+ (b.k === "object" && (a.k === "array" || a.k === "tuple"))) {
1654
+ return { k: "intersection", members: [a, b] };
1655
+ }
1656
+ const leftDomain = domainOf(a);
1657
+ const rightDomain = domainOf(b);
1658
+ if (leftDomain !== undefined && rightDomain !== undefined && leftDomain !== rightDomain) {
1659
+ throw new OmpTypeError(`intersection of ${leftDomain} and ${rightDomain} is unsatisfiable`);
1660
+ }
1661
+ if (a.k === "anyobject" && rightDomain === "object")
1662
+ return b;
1663
+ if (b.k === "anyobject" && leftDomain === "object")
1664
+ return a;
1665
+ const members = [...(a.k === "intersection" ? a.members : [a]), ...(b.k === "intersection" ? b.members : [b])];
1666
+ return { k: "intersection", members };
1667
+ }
1668
+ /** Reduce parsed unions/intersections to their observable semantic form. */
1669
+ function normalizeIR(ir) {
1670
+ switch (ir.k) {
1671
+ case "intersection": {
1672
+ const members = ir.members.map(normalizeIR);
1673
+ if (members.length === 0)
1674
+ return { k: "unknown" };
1675
+ return members.slice(1).reduce(intersect, members[0]);
1676
+ }
1677
+ case "union": {
1678
+ const members = [];
1679
+ let changed = false;
1680
+ for (let index = 0; index < ir.members.length; index++) {
1681
+ const original = ir.members[index];
1682
+ const member = normalizeIR(original);
1683
+ changed ||= member !== original;
1684
+ if (member.k === "union") {
1685
+ members.push(...member.members);
1686
+ changed = true;
1687
+ }
1688
+ else if (member.k === "never") {
1689
+ changed = true;
1690
+ }
1691
+ else if (member.k === "unknown") {
1692
+ return { k: "unknown" };
1693
+ }
1694
+ else {
1695
+ members.push(member);
1696
+ }
1697
+ }
1698
+ if (members.every(member => member.k === "lit" &&
1699
+ (member.v === null || (typeof member.v !== "object" && typeof member.v !== "function")))) {
1700
+ const pruned = [];
1701
+ for (const member of members) {
1702
+ if (member.k === "lit" && pruned.some(candidate => candidate.k === "lit" && candidate.v === member.v)) {
1703
+ changed = true;
1704
+ }
1705
+ else {
1706
+ pruned.push(member);
1707
+ }
1708
+ }
1709
+ if (pruned.length === 0)
1710
+ return { k: "never" };
1711
+ if (pruned.length === 1)
1712
+ return pruned[0];
1713
+ if (pruned.length === 2 && pruned.every(member => member.k === "lit" && typeof member.v === "boolean")) {
1714
+ return { k: "boolean" };
1715
+ }
1716
+ return changed ? { ...ir, members: pruned } : ir;
1717
+ }
1718
+ const pruned = members.filter((member, index) => !members.some((candidate, candidateIndex) => candidateIndex !== index &&
1719
+ !hasMorph(member) &&
1720
+ !hasMorph(candidate) &&
1721
+ isSubtype(member, candidate) &&
1722
+ (!isSubtype(candidate, member) || candidateIndex < index)));
1723
+ if (pruned.length === 0)
1724
+ return { k: "never" };
1725
+ if (pruned.length === 1)
1726
+ return pruned[0];
1727
+ if (pruned.length === 2 && pruned.every(member => member.k === "lit" && typeof member.v === "boolean")) {
1728
+ return { k: "boolean" };
1729
+ }
1730
+ if (!changed &&
1731
+ !pruned.some(member => member.k === "alias") &&
1732
+ pruned.length === ir.members.length &&
1733
+ pruned.every((member, index) => member === ir.members[index])) {
1734
+ return ir;
1735
+ }
1736
+ return { ...ir, members: pruned };
1737
+ }
1738
+ case "array": {
1739
+ const element = normalizeIR(ir.el);
1740
+ return element === ir.el && ir.el.k !== "alias" ? ir : { ...ir, el: element };
1741
+ }
1742
+ case "tuple": {
1743
+ const prefix = ir.prefix.map(item => {
1744
+ const value = normalizeIR(item.val);
1745
+ return value === item.val ? item : { ...item, val: value };
1746
+ });
1747
+ const variadic = ir.variadic === undefined ? undefined : normalizeIR(ir.variadic);
1748
+ const postfix = ir.postfix.map(normalizeIR);
1749
+ if (!ir.prefix.some(item => item.val.k === "alias") &&
1750
+ ir.variadic?.k !== "alias" &&
1751
+ !ir.postfix.some(item => item.k === "alias") &&
1752
+ prefix.every((item, index) => item === ir.prefix[index]) &&
1753
+ variadic === ir.variadic &&
1754
+ postfix.every((item, index) => item === ir.postfix[index])) {
1755
+ return ir;
1756
+ }
1757
+ return { ...ir, prefix, variadic, postfix };
1758
+ }
1759
+ case "object": {
1760
+ let props;
1761
+ for (let index = 0; index < ir.props.length; index++) {
1762
+ const prop = ir.props[index];
1763
+ const value = normalizeIR(prop.val);
1764
+ if (value === prop.val)
1765
+ continue;
1766
+ props ??= [...ir.props];
1767
+ props[index] = { ...prop, val: value };
1768
+ }
1769
+ const index = ir.index === undefined ? undefined : normalizeIR(ir.index);
1770
+ const symbolIndex = ir.symbolIndex === undefined ? undefined : normalizeIR(ir.symbolIndex);
1771
+ const patternIndexes = ir.patternIndexes?.map(pattern => {
1772
+ const key = normalizeIR(pattern.key);
1773
+ const val = normalizeIR(pattern.val);
1774
+ return key === pattern.key && val === pattern.val ? pattern : { key, val };
1775
+ });
1776
+ if (props === undefined &&
1777
+ !ir.props.some(prop => prop.val.k === "alias") &&
1778
+ ir.index?.k !== "alias" &&
1779
+ ir.symbolIndex?.k !== "alias" &&
1780
+ !ir.patternIndexes?.some(pattern => pattern.key.k === "alias" || pattern.val.k === "alias") &&
1781
+ index === ir.index &&
1782
+ symbolIndex === ir.symbolIndex &&
1783
+ patternIndexes?.every((pattern, patternIndex) => pattern === ir.patternIndexes?.[patternIndex]) !== false) {
1784
+ return ir;
1785
+ }
1786
+ return { ...ir, props: props ?? ir.props, index, symbolIndex, patternIndexes };
1787
+ }
1788
+ case "refine": {
1789
+ const base = normalizeIR(ir.base);
1790
+ return base === ir.base && ir.base.k !== "alias" ? ir : { ...ir, base };
1791
+ }
1792
+ case "morph": {
1793
+ const input = normalizeIR(ir.input);
1794
+ const out = ir.out === undefined ? undefined : normalizeIR(ir.out);
1795
+ return input === ir.input && out === ir.out && ir.input.k !== "alias" && ir.out?.k !== "alias"
1796
+ ? ir
1797
+ : { ...ir, input, out };
1798
+ }
1799
+ case "alias":
1800
+ return ir;
1801
+ default:
1802
+ return ir;
1803
+ }
1804
+ }
1805
+ function domainOf(ir) {
1806
+ switch (ir.k) {
1807
+ case "null":
1808
+ return "null";
1809
+ case "undefined":
1810
+ case "boolean":
1811
+ case "bigint":
1812
+ case "symbol":
1813
+ case "string":
1814
+ case "number":
1815
+ return ir.k;
1816
+ case "array":
1817
+ case "tuple":
1818
+ return "array";
1819
+ case "object":
1820
+ case "anyobject":
1821
+ case "instance":
1822
+ return "object";
1823
+ case "lit":
1824
+ return ir.v === null ? "null" : Array.isArray(ir.v) ? "array" : typeof ir.v;
1825
+ case "refine":
1826
+ return domainOf(ir.base);
1827
+ case "morph":
1828
+ return domainOf(ir.input);
1829
+ case "sub":
1830
+ return domainOf(ir.schema.ir);
1831
+ case "alias":
1832
+ return domainOf(ir.resolve());
1833
+ case "union":
1834
+ case "intersection": {
1835
+ const first = domainOf(ir.members[0] ?? { k: "never" });
1836
+ return ir.members.every(member => domainOf(member) === first) ? first : undefined;
1837
+ }
1838
+ default:
1839
+ return undefined;
1840
+ }
1841
+ }
1842
+ function lowerBoundWithin(source, target) {
1843
+ if (target.min === undefined)
1844
+ return true;
1845
+ if (source.min === undefined || source.min < target.min)
1846
+ return false;
1847
+ return source.min !== target.min || target.xmin !== true || source.xmin === true;
1848
+ }
1849
+ function upperBoundWithin(source, target) {
1850
+ if (target.max === undefined)
1851
+ return true;
1852
+ if (source.max === undefined || source.max > target.max)
1853
+ return false;
1854
+ return source.max !== target.max || target.xmax !== true || source.xmax === true;
1855
+ }
1856
+ function lengthWithin(source, target) {
1857
+ return ((target.min === undefined || (source.min !== undefined && source.min >= target.min)) &&
1858
+ (target.max === undefined || (source.max !== undefined && source.max <= target.max)));
1859
+ }
1860
+ function isSubtype(source, target, seen = new WeakMap()) {
1861
+ if (source === target || target.k === "unknown" || source.k === "never")
1862
+ return true;
1863
+ let targets = seen.get(source);
1864
+ if (targets?.has(target))
1865
+ return true;
1866
+ if (targets === undefined) {
1867
+ targets = new Set();
1868
+ seen.set(source, targets);
1869
+ }
1870
+ targets.add(target);
1871
+ if (source.k === "alias")
1872
+ return isSubtype(source.resolve(), target, seen);
1873
+ if (target.k === "alias")
1874
+ return isSubtype(source, target.resolve(), seen);
1875
+ if (source.k === "union")
1876
+ return source.members.every(member => isSubtype(member, target, seen));
1877
+ if (target.k === "union")
1878
+ return target.members.some(member => isSubtype(source, member, seen));
1879
+ if (target.k === "intersection")
1880
+ return target.members.every(member => isSubtype(source, member, seen));
1881
+ if (source.k === "intersection")
1882
+ return source.members.some(member => isSubtype(member, target, seen));
1883
+ if (source.k === "lit")
1884
+ return !(walk(target, source.v) instanceof OmpErrors);
1885
+ if (source.k === "refine")
1886
+ return isSubtype(source.base, target, seen);
1887
+ if (source.k === "morph")
1888
+ return isSubtype(source.out ?? source.input, target, seen);
1889
+ if (source.k === "sub")
1890
+ return isSubtype(source.schema.ir, target, seen);
1891
+ if (target.k === "refine" || target.k === "morph" || target.k === "sub")
1892
+ return false;
1893
+ if (source.k === "string" && target.k === "string") {
1894
+ return lengthWithin(source, target) && (!target.url || source.url === true);
1895
+ }
1896
+ if (source.k === "number" && target.k === "number") {
1897
+ return (lowerBoundWithin(source, target) &&
1898
+ upperBoundWithin(source, target) &&
1899
+ (!target.int || source.int === true) &&
1900
+ (target.divisor === undefined || (source.divisor !== undefined && source.divisor % target.divisor === 0)));
1901
+ }
1902
+ if (source.k === "array" && target.k === "array") {
1903
+ return lengthWithin(source, target) && isSubtype(source.el, target.el, seen);
1904
+ }
1905
+ if (source.k === "object" && target.k === "object") {
1906
+ for (const targetProp of target.props) {
1907
+ const sourceProp = source.props.find(prop => prop.key === targetProp.key);
1908
+ if (sourceProp === undefined) {
1909
+ if (!targetProp.opt)
1910
+ return false;
1911
+ continue;
1912
+ }
1913
+ if (!targetProp.opt && sourceProp.opt)
1914
+ return false;
1915
+ if (!isSubtype(sourceProp.val, targetProp.val, seen))
1916
+ return false;
1917
+ }
1918
+ if (target.extras === "reject") {
1919
+ if (source.extras !== "reject")
1920
+ return false;
1921
+ if (target.index === undefined &&
1922
+ source.props.some(sourceProp => !target.props.some(targetProp => targetProp.key === sourceProp.key))) {
1923
+ return false;
1924
+ }
1925
+ }
1926
+ return true;
1927
+ }
1928
+ if (source.k === "instance" && target.k === "instance") {
1929
+ return source.ctor === target.ctor || source.ctor.prototype instanceof target.ctor;
1930
+ }
1931
+ if (source.k === "object" && target.k === "anyobject")
1932
+ return true;
1933
+ if (source.k === "instance" && target.k === "anyobject")
1934
+ return true;
1935
+ if (source.k === "tuple" && target.k === "array") {
1936
+ return (source.prefix.every(item => isSubtype(item.val, target.el, seen)) &&
1937
+ source.postfix.every(item => isSubtype(item, target.el, seen)) &&
1938
+ (source.variadic === undefined || isSubtype(source.variadic, target.el, seen)));
1939
+ }
1940
+ if (source.k !== target.k)
1941
+ return false;
1942
+ switch (source.k) {
1943
+ case "null":
1944
+ case "undefined":
1945
+ case "boolean":
1946
+ case "bigint":
1947
+ case "symbol":
1948
+ case "anyobject":
1949
+ return true;
1950
+ case "tuple":
1951
+ return target.k === "tuple" && expectedTuple(source) === expectedTuple(target);
1952
+ case "instance":
1953
+ return target.k === "instance" && source.ctor === target.ctor;
1954
+ default:
1955
+ return false;
1956
+ }
1957
+ }
1958
+ function expectedTuple(tuple) {
1959
+ return JSON.stringify({
1960
+ prefix: tuple.prefix.map(item => [item.opt, item.hasDefault, expectedOf(item.val)]),
1961
+ variadic: tuple.variadic === undefined ? undefined : expectedOf(tuple.variadic),
1962
+ postfix: tuple.postfix.map(expectedOf),
1963
+ });
1964
+ }
1965
+ function irEquals(left, right) {
1966
+ return isSubtype(left, right) && isSubtype(right, left);
1967
+ }
1968
+ function maxOf(a, b) {
1969
+ if (a === undefined)
1970
+ return b;
1971
+ if (b === undefined)
1972
+ return a;
1973
+ return Math.max(a, b);
1974
+ }
1975
+ function minOf(a, b) {
1976
+ if (a === undefined)
1977
+ return b;
1978
+ if (b === undefined)
1979
+ return a;
1980
+ return Math.min(a, b);
1981
+ }
1982
+ function withLengthBound(ir, side, bound) {
1983
+ if (ir.k === "array" || ir.k === "string") {
1984
+ return side === "min" ? { ...ir, min: bound } : { ...ir, max: bound };
1985
+ }
1986
+ throw new OmpTypeError(`cannot apply length bound to ${ir.k}`);
1987
+ }
1988
+ function withNumericBound(ir, side, bound, exclusive = false) {
1989
+ if (!Number.isFinite(bound))
1990
+ throw new OmpTypeError("numeric bound must be finite");
1991
+ if (ir.k === "number") {
1992
+ return side === "min" ? { ...ir, min: bound, xmin: exclusive } : { ...ir, max: bound, xmax: exclusive };
1993
+ }
1994
+ if (ir.k === "union") {
1995
+ return { ...ir, members: ir.members.map(member => withNumericBound(member, side, bound, exclusive)) };
1996
+ }
1997
+ throw new OmpTypeError(`cannot apply numeric bound to ${ir.k}`);
1998
+ }
1999
+ const GENERIC_META = Symbol("omptype.generic");
2000
+ function validateGenericParameters(parameters) {
2001
+ const names = new Set();
2002
+ for (const parameter of parameters) {
2003
+ if (!/^[A-Za-z_$]\w*$/.test(parameter.name)) {
2004
+ throw new OmpTypeError(`invalid generic parameter "${parameter.name}"`);
2005
+ }
2006
+ if (names.has(parameter.name))
2007
+ throw new OmpTypeError(`duplicate generic parameter "${parameter.name}"`);
2008
+ names.add(parameter.name);
2009
+ }
2010
+ if (parameters.length === 0)
2011
+ throw new OmpTypeError("generic declarations require at least one parameter");
2012
+ }
2013
+ function parseGenericParameters(source) {
2014
+ const trimmed = source.trim();
2015
+ const body = trimmed.startsWith("<") && trimmed.endsWith(">") ? trimmed.slice(1, -1) : trimmed;
2016
+ const parts = [];
2017
+ let start = 0;
2018
+ let depth = 0;
2019
+ let quote = "";
2020
+ for (let index = 0; index < body.length; index++) {
2021
+ const char = body[index];
2022
+ if (quote !== "") {
2023
+ if (char === quote && body[index - 1] !== "\\")
2024
+ quote = "";
2025
+ continue;
2026
+ }
2027
+ if (char === "'" || char === '"' || char === "`")
2028
+ quote = char;
2029
+ else if (char === "<" || char === "(" || char === "[")
2030
+ depth++;
2031
+ else if (char === ">" || char === ")" || char === "]")
2032
+ depth = Math.max(0, depth - 1);
2033
+ else if (char === "," && depth === 0) {
2034
+ parts.push(body.slice(start, index).trim());
2035
+ start = index + 1;
2036
+ }
2037
+ }
2038
+ parts.push(body.slice(start).trim());
2039
+ const parameters = parts.map(part => {
2040
+ const constrained = part.match(/^([A-Za-z_$]\w*)\s+extends\s+(.+)$/s);
2041
+ return constrained === null ? { name: part } : { name: constrained[1], constraintDef: constrained[2].trim() };
2042
+ });
2043
+ validateGenericParameters(parameters);
2044
+ return parameters;
2045
+ }
2046
+ function parseGenericDeclaration(source) {
2047
+ const match = source.trim().match(/^([A-Za-z_$]\w*)\s*(<.*>)$/s);
2048
+ if (match === null)
2049
+ return undefined;
2050
+ return { name: match[1], parameters: parseGenericParameters(match[2]) };
2051
+ }
2052
+ function isRuntimeGeneric(value) {
2053
+ return typeof value === "function" && GENERIC_META in value;
2054
+ }
2055
+ function genericResolver(parameters, arguments_, outer) {
2056
+ const byName = new Map();
2057
+ for (let index = 0; index < parameters.length; index++)
2058
+ byName.set(parameters[index].name, arguments_[index]);
2059
+ const resolve = ((name) => byName.get(name) ?? outer?.(name));
2060
+ resolve.hasGeneric = outer?.hasGeneric;
2061
+ resolve.generic = outer?.generic;
2062
+ return resolve;
2063
+ }
2064
+ function parseGenericArgument(definition, outer) {
2065
+ if (outer === undefined) {
2066
+ try {
2067
+ return parseDef(definition);
2068
+ }
2069
+ catch (error) {
2070
+ if (!(error instanceof OmpTypeError) || !error.message.includes('unknown keyword "this"'))
2071
+ throw error;
2072
+ }
2073
+ }
2074
+ let root;
2075
+ const self = {
2076
+ k: "alias",
2077
+ name: "this",
2078
+ resolve: () => {
2079
+ if (root === undefined || root === self)
2080
+ throw new OmpTypeError('"this" cannot be used as a root definition');
2081
+ return root;
2082
+ },
2083
+ };
2084
+ const resolve = ((name) => (name === "this" ? self : outer?.(name)));
2085
+ if (outer !== undefined) {
2086
+ resolve.hasGeneric = outer.hasGeneric;
2087
+ resolve.generic = outer.generic;
2088
+ }
2089
+ else {
2090
+ // The retry only exists to serve "this"; parses of this-free member
2091
+ // strings inside the definition may still share the string cache.
2092
+ markThisOnlyResolver(resolve);
2093
+ }
2094
+ root = parseDef(definition, resolve);
2095
+ if (root === self)
2096
+ throw new OmpTypeError('"this" cannot be used as a root definition');
2097
+ return root;
2098
+ }
2099
+ function genericBodyIR(parameters, definition, arguments_, outer) {
2100
+ const resolve = genericResolver(parameters, arguments_, outer);
2101
+ const body = typeof definition === "function" && !(IR_BRAND in definition)
2102
+ ? definition(Object.fromEntries(parameters.map((parameter, index) => [
2103
+ parameter.name,
2104
+ makeType(arguments_[index], EMPTY_STEPS, EMPTY_META),
2105
+ ])))
2106
+ : definition;
2107
+ return parseDef(body, resolve);
2108
+ }
2109
+ function createRuntimeGeneric(parameters, definition, outer, validateBody = true) {
2110
+ const constraintResolve = ((name) => outer?.(name));
2111
+ constraintResolve.hasGeneric = outer?.hasGeneric;
2112
+ constraintResolve.generic = outer?.generic;
2113
+ validateGenericParameters(parameters);
2114
+ const placeholders = parameters.map(parameter => parameter.constraintDef === undefined
2115
+ ? { k: "unknown" }
2116
+ : parseDef(parameter.constraintDef, constraintResolve));
2117
+ if (validateBody)
2118
+ genericBodyIR(parameters, definition, placeholders, outer);
2119
+ const meta = {
2120
+ parameters,
2121
+ instantiateIR(arguments_) {
2122
+ if (arguments_.length !== parameters.length) {
2123
+ throw new OmpTypeError(`generic expects ${parameters.length} arguments (received ${arguments_.length})`);
2124
+ }
2125
+ for (let index = 0; index < parameters.length; index++) {
2126
+ const parameter = parameters[index];
2127
+ if (parameter.constraintDef === undefined)
2128
+ continue;
2129
+ const constraint = parseDef(parameter.constraintDef, constraintResolve);
2130
+ if (!isSubtype(arguments_[index], constraint)) {
2131
+ throw new OmpTypeError(`${parameter.name} must be assignable to its constraint`);
2132
+ }
2133
+ }
2134
+ return genericBodyIR(parameters, definition, arguments_, outer);
2135
+ },
2136
+ };
2137
+ const generic = Object.assign((...arguments_) => makeType(meta.instantiateIR(arguments_.map(argument => parseGenericArgument(argument, outer))), EMPTY_STEPS, EMPTY_META), { [GENERIC_META]: meta });
2138
+ Object.defineProperty(generic, GENERIC_META, { value: meta });
2139
+ return generic;
2140
+ }
2141
+ export function type(first) {
2142
+ // biome-ignore lint/complexity/noArguments: Avoid allocating a rest array for the dominant single-definition call.
2143
+ const count = arguments.length;
2144
+ if (count === 2 && typeof first === "string" && first.trimStart().startsWith("<")) {
2145
+ // biome-ignore lint/complexity/noArguments: The generic path reads its second positional argument without a rest array.
2146
+ return createRuntimeGeneric(parseGenericParameters(first), arguments[1]);
2147
+ }
2148
+ let definition = first;
2149
+ if (count !== 1) {
2150
+ const expression = new Array(count);
2151
+ for (let index = 0; index < count; index++) {
2152
+ // biome-ignore lint/complexity/noArguments: Only multi-part expressions pay to materialize an argument array.
2153
+ expression[index] = arguments[index];
2154
+ }
2155
+ definition = expression;
2156
+ }
2157
+ return makeType(parseGenericArgument(definition), EMPTY_STEPS, EMPTY_META);
2158
+ }
2159
+ function keywordSchema(name) {
2160
+ const ir = keywordIR(name);
2161
+ if (ir === undefined)
2162
+ throw new OmpTypeError(`missing built-in keyword ${name}`);
2163
+ return makeType(ir, [], {});
2164
+ }
2165
+ function parsedKeyword(name) {
2166
+ return Object.assign(keywordSchema(name), {
2167
+ parse: keywordSchema(`${name}.parse`),
2168
+ });
2169
+ }
2170
+ function preformattedKeyword(name) {
2171
+ return Object.assign(keywordSchema(name), {
2172
+ preformatted: keywordSchema(`${name}.preformatted`),
2173
+ });
2174
+ }
2175
+ function caseResolver(value) {
2176
+ if (typeof value !== "function")
2177
+ throw new OmpTypeError("match case values must be functions");
2178
+ return (input, ...args) => Reflect.apply(value, undefined, [input, ...args]);
2179
+ }
2180
+ function unionIR(branches) {
2181
+ const members = branches.map(branch => branch.schema.ir);
2182
+ if (members.length === 0)
2183
+ return { k: "never" };
2184
+ if (members.length === 1)
2185
+ return members[0];
2186
+ return { k: "union", members };
2187
+ }
2188
+ function publicMatcher(state, fallback) {
2189
+ const fallbackResolver = typeof fallback === "function" ? caseResolver(fallback) : undefined;
2190
+ const casesIR = unionIR(state.branches);
2191
+ let casesSchema;
2192
+ if (state.key === undefined || state.branches.length === 0) {
2193
+ casesSchema =
2194
+ state.key === undefined
2195
+ ? makeType(casesIR, EMPTY_STEPS, EMPTY_META)
2196
+ : state.parse({ [state.key]: "never" });
2197
+ }
2198
+ else {
2199
+ const first = state.branches[0].schema.ir;
2200
+ if (first.k !== "object")
2201
+ throw new OmpTypeError("match.at cases must define object schemas");
2202
+ const propertyKey = String(state.key);
2203
+ const values = [];
2204
+ for (const branch of state.branches) {
2205
+ if (branch.schema.ir.k !== "object")
2206
+ throw new OmpTypeError("match.at cases must define object schemas");
2207
+ const property = branch.schema.ir.props.find(candidate => candidate.key === propertyKey);
2208
+ if (property === undefined)
2209
+ throw new OmpTypeError(`match.at case is missing ${propertyKey}`);
2210
+ values.push(property.val);
2211
+ }
2212
+ const value = values.length === 1 ? values[0] : { k: "union", members: values };
2213
+ casesSchema = makeType({
2214
+ ...first,
2215
+ props: first.props.map(property => (property.key === propertyKey ? { ...property, val: value } : property)),
2216
+ }, EMPTY_STEPS, EMPTY_META);
2217
+ }
2218
+ const execute = (input, args) => {
2219
+ let matchedInput = input;
2220
+ if (state.input !== undefined) {
2221
+ const validated = state.input.run(input);
2222
+ if (validated instanceof OmpErrors)
2223
+ return validated;
2224
+ matchedInput = validated;
2225
+ }
2226
+ for (const branch of state.branches) {
2227
+ const matched = branch.schema.run(matchedInput);
2228
+ if (!(matched instanceof OmpErrors))
2229
+ return branch.resolve(matched, ...args);
2230
+ }
2231
+ if (fallbackResolver !== undefined)
2232
+ return fallbackResolver(matchedInput, ...args);
2233
+ return casesSchema.run(matchedInput);
2234
+ };
2235
+ const schema = makeType({ k: "unknown" }, [{ kind: "pipe", fn: input => execute(input, []) }], EMPTY_META);
2236
+ const callable = ((value, ...args) => {
2237
+ const result = execute(value, args);
2238
+ if ((fallback === "assert" || fallback === "never") && result instanceof OmpErrors) {
2239
+ throw new TraversalError(result);
2240
+ }
2241
+ return result;
2242
+ });
2243
+ Object.assign(callable, schema);
2244
+ Object.setPrototypeOf(callable, typeMethods);
2245
+ return callable;
2246
+ }
2247
+ function addMatchCases(state, cases) {
2248
+ const branches = [...state.branches];
2249
+ let fallback;
2250
+ for (const rawDefinition of Reflect.ownKeys(cases)) {
2251
+ const value = Reflect.get(cases, rawDefinition);
2252
+ if (rawDefinition === "default") {
2253
+ if (value !== "assert" && value !== "never" && value !== "reject" && typeof value !== "function") {
2254
+ throw new OmpTypeError('match default must be "assert", "never", "reject" or a function');
2255
+ }
2256
+ fallback = value;
2257
+ continue;
2258
+ }
2259
+ const definition = typeof rawDefinition === "symbol" ? rawDefinition : String(rawDefinition);
2260
+ const caseDefinition = state.key === undefined ? definition : { [state.key]: definition };
2261
+ branches.push({
2262
+ definition,
2263
+ schema: state.parse(caseDefinition),
2264
+ resolve: caseResolver(value),
2265
+ });
2266
+ }
2267
+ const next = { ...state, branches };
2268
+ return fallback === undefined ? createMatchParser(next) : publicMatcher(next, fallback);
2269
+ }
2270
+ function createMatchParser(state) {
2271
+ const parser = ((cases) => addMatchCases(state, cases));
2272
+ parser.case = (definition, resolver) => {
2273
+ const caseDefinition = state.key === undefined ? definition : { [state.key]: definition };
2274
+ return createMatchParser({
2275
+ ...state,
2276
+ branches: [
2277
+ ...state.branches,
2278
+ {
2279
+ definition,
2280
+ schema: state.parse(caseDefinition),
2281
+ resolve: caseResolver(resolver),
2282
+ },
2283
+ ],
2284
+ });
2285
+ };
2286
+ parser.match = cases => addMatchCases(state, cases);
2287
+ parser.default = fallback => publicMatcher(state, fallback);
2288
+ function at(key, cases) {
2289
+ if (state.key !== undefined)
2290
+ throw new OmpTypeError("match.at may only be specified once");
2291
+ const next = createMatchParser({ ...state, key });
2292
+ return cases === undefined ? next : next.match(cases);
2293
+ }
2294
+ parser.at = at;
2295
+ parser.strings = cases => {
2296
+ if (state.key === undefined)
2297
+ throw new OmpTypeError("match.strings requires match.at(key)");
2298
+ const definitions = {};
2299
+ for (const key of Reflect.ownKeys(cases)) {
2300
+ definitions[key === "default" ? key : JSON.stringify(String(key))] = Reflect.get(cases, key);
2301
+ }
2302
+ return addMatchCases(state, definitions);
2303
+ };
2304
+ parser.in = (...args) => {
2305
+ if (state.input !== undefined)
2306
+ throw new OmpTypeError("match.in may only be specified once");
2307
+ return createMatchParser({
2308
+ ...state,
2309
+ ...(args.length === 0 ? {} : { input: state.parse(args[0]) }),
2310
+ });
2311
+ };
2312
+ return parser;
2313
+ }
2314
+ /** Build a fluent first-match dispatcher from schema definitions. */
2315
+ const matchBuilder = createMatchParser({
2316
+ parse: definition => type.raw(definition),
2317
+ branches: [],
2318
+ });
2319
+ export { matchBuilder as match };
2320
+ function fnExpression(ir) {
2321
+ switch (ir.k) {
2322
+ case "unknown":
2323
+ case "null":
2324
+ case "undefined":
2325
+ case "boolean":
2326
+ case "bigint":
2327
+ case "symbol":
2328
+ case "never":
2329
+ case "string":
2330
+ case "number":
2331
+ return ir.k;
2332
+ case "anyobject":
2333
+ return "object";
2334
+ case "lit":
2335
+ return typeof ir.v === "string" ? JSON.stringify(ir.v) : String(ir.v);
2336
+ case "union":
2337
+ return ir.members.map(fnExpression).join(" | ");
2338
+ case "intersection":
2339
+ return ir.members.map(fnExpression).join(" & ");
2340
+ case "array": {
2341
+ const element = fnExpression(ir.el);
2342
+ return ir.el.k === "unknown" ? "Array" : `${element.includes(" | ") ? `(${element})` : element}[]`;
2343
+ }
2344
+ case "tuple": {
2345
+ const elements = ir.prefix.map(item => {
2346
+ const expression = fnExpression(item.val);
2347
+ if (item.hasDefault)
2348
+ return `${expression} = ${String(item.def)}`;
2349
+ return item.opt ? `${expression}?` : expression;
2350
+ });
2351
+ if (ir.variadic !== undefined)
2352
+ elements.push(`...${fnExpression({ k: "array", el: ir.variadic })}`);
2353
+ elements.push(...ir.postfix.map(fnExpression));
2354
+ return `[${elements.join(", ")}]`;
2355
+ }
2356
+ case "object":
2357
+ return `{ ${ir.props
2358
+ .map(property => `${String(property.key)}${property.opt ? "?" : ""}: ${fnExpression(property.val)}`)
2359
+ .join(", ")} }`;
2360
+ case "refine":
2361
+ return fnExpression(ir.base);
2362
+ case "morph":
2363
+ return `(In: ${fnExpression(ir.input)}) => To<${fnExpression(ir.out ?? { k: "unknown" })}>`;
2364
+ case "instance":
2365
+ return ir.ctor.name || "object";
2366
+ case "alias":
2367
+ return fnExpression(ir.resolve());
2368
+ case "sub": {
2369
+ const schema = ir.schema;
2370
+ if (!schema.hasSteps)
2371
+ return fnExpression(schema.ir);
2372
+ return `(In: ${fnExpression(schema.ir)}) => To<${fnExpression(schema.stepOut ?? { k: "unknown" })}>`;
2373
+ }
2374
+ }
2375
+ }
2376
+ function normalizeFnParameter(definition) {
2377
+ if (typeof definition !== "string")
2378
+ return definition;
2379
+ const optional = definition.match(/^(.*[^\s])\?$/);
2380
+ if (optional)
2381
+ return [optional[1], "?"];
2382
+ const defaulted = definition.match(/^(.*?)\s*=\s*(.+)$/);
2383
+ if (defaulted) {
2384
+ const source = defaulted[2];
2385
+ const value = source === "true"
2386
+ ? true
2387
+ : source === "false"
2388
+ ? false
2389
+ : source === "null"
2390
+ ? null
2391
+ : Number.isNaN(Number(source))
2392
+ ? source
2393
+ : Number(source);
2394
+ return [defaulted[1], "=", value];
2395
+ }
2396
+ return definition;
2397
+ }
2398
+ function makeFn(resolve) {
2399
+ function parser(...definitions) {
2400
+ const marker = definitions.indexOf(":");
2401
+ if (marker !== -1 && (marker !== definitions.length - 2 || definitions.lastIndexOf(":") !== marker)) {
2402
+ throw new OmpTypeError('":" must be followed by exactly one return type e.g:\nfn("string", ":", "number")(s => s.length)');
2403
+ }
2404
+ const spreadIndexes = [];
2405
+ for (let index = 0; index < definitions.length; index++) {
2406
+ if (definitions[index] === "...")
2407
+ spreadIndexes.push(index);
2408
+ }
2409
+ if (spreadIndexes.length > 1) {
2410
+ const secondSpread = definitions[spreadIndexes[1] + 1];
2411
+ if (Array.isArray(secondSpread) &&
2412
+ secondSpread.some(element => typeof element === "string" && (element.endsWith("?") || element.includes("=")))) {
2413
+ throw new OmpTypeError("An optional element may not follow a variadic element");
2414
+ }
2415
+ throw new OmpTypeError("A tuple may have at most one variadic element");
2416
+ }
2417
+ if (spreadIndexes.length === 1 && spreadIndexes[0] + 2 < (marker === -1 ? definitions.length : marker)) {
2418
+ const preceding = definitions.slice(0, spreadIndexes[0]);
2419
+ if (preceding.some(element => typeof element === "string" && (element.endsWith("?") || /\s=\s/.test(element)))) {
2420
+ throw new OmpTypeError("A postfix required element cannot follow an optional or defaultable element");
2421
+ }
2422
+ }
2423
+ const parameterDefinitions = (marker === -1 ? definitions : definitions.slice(0, marker)).map(normalizeFnParameter);
2424
+ const params = makeType(parseDef(parameterDefinitions, resolve), [], {});
2425
+ const returns = marker === -1
2426
+ ? makeType({ k: "unknown" }, [], {})
2427
+ : makeType(parseDef(definitions[marker + 1], resolve), [], {});
2428
+ const parameterExpression = fnExpression(params.ir);
2429
+ const returnsExpression = fnExpression(returns.ir);
2430
+ return (implementation) => {
2431
+ if (typeof implementation !== "function")
2432
+ throw new OmpTypeError("type.fn requires a function implementation");
2433
+ const raw = (...arguments_) => {
2434
+ const validatedArguments = params.assert(arguments_);
2435
+ const result = Reflect.apply(implementation, undefined, validatedArguments);
2436
+ return returns.assert(result);
2437
+ };
2438
+ const typed = raw.bind(undefined);
2439
+ Object.defineProperties(typed, {
2440
+ name: { value: `bound typed ${implementation.name}`, configurable: true },
2441
+ raw: { value: implementation, enumerable: true },
2442
+ params: { value: params, enumerable: true },
2443
+ returns: { value: returns, enumerable: true },
2444
+ expression: {
2445
+ value: `(${parameterExpression.slice(1, -1)}) => ${returnsExpression}`,
2446
+ enumerable: true,
2447
+ },
2448
+ });
2449
+ return typed;
2450
+ };
2451
+ }
2452
+ return Object.assign(parser, { raw: parser });
2453
+ }
2454
+ /** Fix a schema's externally declared static type without changing its runtime validation. */
2455
+ // biome-ignore lint/complexity/noBannedTypes: empty default options object
2456
+ export function declare() {
2457
+ return {
2458
+ type: definition => type(definition),
2459
+ };
2460
+ }
2461
+ function isTypeValue(value) {
2462
+ return (typeof value === "function" || (typeof value === "object" && value !== null)) && IR_BRAND in value;
2463
+ }
2464
+ function resolveAlias(ir) {
2465
+ const seen = new Set();
2466
+ let current = ir;
2467
+ while (current.k === "alias" && !seen.has(current)) {
2468
+ seen.add(current);
2469
+ current = current.resolve();
2470
+ }
2471
+ return current;
2472
+ }
2473
+ function sameUnionMember(left, right) {
2474
+ const a = resolveAlias(left);
2475
+ const b = resolveAlias(right);
2476
+ if (a.k === "lit" && b.k === "lit")
2477
+ return Object.is(a.v, b.v);
2478
+ if (a.k !== b.k)
2479
+ return false;
2480
+ switch (a.k) {
2481
+ case "unknown":
2482
+ case "never":
2483
+ case "null":
2484
+ case "undefined":
2485
+ case "boolean":
2486
+ case "bigint":
2487
+ case "symbol":
2488
+ case "anyobject":
2489
+ return true;
2490
+ default:
2491
+ return false;
2492
+ }
2493
+ }
2494
+ function buildOr(definitions, resolve) {
2495
+ const members = [];
2496
+ const add = (candidate) => {
2497
+ const resolved = resolveAlias(candidate);
2498
+ if (resolved.k === "unknown") {
2499
+ members.length = 0;
2500
+ members.push(resolved);
2501
+ return false;
2502
+ }
2503
+ if (resolved.k === "never")
2504
+ return true;
2505
+ if (resolved.k === "union") {
2506
+ for (const member of resolved.members) {
2507
+ if (!add(member))
2508
+ return false;
2509
+ }
2510
+ return true;
2511
+ }
2512
+ if (!members.some(member => sameUnionMember(member, candidate)))
2513
+ members.push(candidate);
2514
+ return true;
2515
+ };
2516
+ for (const definition of definitions) {
2517
+ if (!add(parseDef(definition, resolve)))
2518
+ break;
2519
+ }
2520
+ const ir = members.length === 0 ? { k: "never" } : members.length === 1 ? members[0] : { k: "union", members };
2521
+ return makeType(ir, [], {});
2522
+ }
2523
+ function buildAnd(definitions, resolve) {
2524
+ if (definitions.length === 0)
2525
+ return makeType({ k: "unknown" }, [], {});
2526
+ let ir = parseDef(definitions[0], resolve);
2527
+ for (let index = 1; index < definitions.length; index++) {
2528
+ ir = intersect(ir, parseDef(definitions[index], resolve));
2529
+ }
2530
+ return makeType(ir, [], {});
2531
+ }
2532
+ function requireNaryObject(ir) {
2533
+ const resolved = resolveAlias(ir);
2534
+ if (resolved.k !== "object")
2535
+ throw new OmpTypeError("merge requires an object schema");
2536
+ return resolved;
2537
+ }
2538
+ function buildMerge(definitions, resolve) {
2539
+ if (definitions.length === 0)
2540
+ return makeType({ k: "anyobject" }, [], {});
2541
+ let object = requireNaryObject(parseDef(definitions[0], resolve));
2542
+ for (let index = 1; index < definitions.length; index++) {
2543
+ object = mergeObjects(object, requireNaryObject(parseDef(definitions[index], resolve)));
2544
+ }
2545
+ return makeType(object, [], {});
2546
+ }
2547
+ function buildPipe(definitions, resolve) {
2548
+ if (definitions.length === 0)
2549
+ return makeType({ k: "unknown" }, [], {});
2550
+ const first = definitions[0];
2551
+ let schema = typeof first === "function" && !isTypeValue(first)
2552
+ ? appendPipes(makeType({ k: "unknown" }, [], {}), [first], false, true)
2553
+ : isTypeValue(first)
2554
+ ? first
2555
+ : makeType(parseDef(first, resolve), [], {});
2556
+ for (let index = 1; index < definitions.length; index++) {
2557
+ const definition = definitions[index];
2558
+ const pipe = typeof definition === "function" && !isTypeValue(definition)
2559
+ ? definition
2560
+ : isTypeValue(definition)
2561
+ ? definition
2562
+ : makeType(parseDef(definition, resolve), [], {});
2563
+ schema = appendPipes(schema, [pipe], false, true);
2564
+ }
2565
+ return schema;
2566
+ }
2567
+ function naryStatics(resolve) {
2568
+ return {
2569
+ or: (...definitions) => buildOr(definitions, resolve),
2570
+ and: (...definitions) => buildAnd(definitions, resolve),
2571
+ merge: (...definitions) => buildMerge(definitions, resolve),
2572
+ pipe: (...definitions) => buildPipe(definitions, resolve),
2573
+ };
2574
+ }
2575
+ (function (type) {
2576
+ /** Error aggregate returned by failed validations (`result instanceof type.errors`). */
2577
+ type.errors = OmpErrors;
2578
+ /** Build a union from zero or more definitions. */
2579
+ function or(...definitions) {
2580
+ return buildOr(definitions);
2581
+ }
2582
+ type.or = or;
2583
+ /** Build an intersection from zero or more definitions. */
2584
+ function and(...definitions) {
2585
+ return buildAnd(definitions);
2586
+ }
2587
+ type.and = and;
2588
+ /** Right-biased object merge over zero or more definitions. */
2589
+ function merge(...definitions) {
2590
+ return buildMerge(definitions);
2591
+ }
2592
+ type.merge = merge;
2593
+ /** Compose Types, definitions, and morph callbacks from left to right. */
2594
+ function pipe(...definitions) {
2595
+ return buildPipe(definitions);
2596
+ }
2597
+ type.pipe = pipe;
2598
+ const normalize = Object.assign(keywordSchema("string.normalize"), {
2599
+ preformatted: keywordSchema("string.normalize.NFC.preformatted"),
2600
+ NFC: preformattedKeyword("string.normalize.NFC"),
2601
+ NFD: preformattedKeyword("string.normalize.NFD"),
2602
+ NFKC: preformattedKeyword("string.normalize.NFKC"),
2603
+ NFKD: preformattedKeyword("string.normalize.NFKD"),
2604
+ });
2605
+ const base64 = Object.assign(keywordSchema("string.base64"), {
2606
+ url: keywordSchema("string.base64.url"),
2607
+ });
2608
+ const date = Object.assign(parsedKeyword("string.date"), {
2609
+ iso: parsedKeyword("string.date.iso"),
2610
+ epoch: parsedKeyword("string.date.epoch"),
2611
+ });
2612
+ const ip = Object.assign(keywordSchema("string.ip"), {
2613
+ v4: keywordSchema("string.ip.v4"),
2614
+ v6: keywordSchema("string.ip.v6"),
2615
+ });
2616
+ const uuid = Object.assign(keywordSchema("string.uuid"), {
2617
+ v1: keywordSchema("string.uuid.v1"),
2618
+ v2: keywordSchema("string.uuid.v2"),
2619
+ v3: keywordSchema("string.uuid.v3"),
2620
+ v4: keywordSchema("string.uuid.v4"),
2621
+ v5: keywordSchema("string.uuid.v5"),
2622
+ v6: keywordSchema("string.uuid.v6"),
2623
+ v7: keywordSchema("string.uuid.v7"),
2624
+ v8: keywordSchema("string.uuid.v8"),
2625
+ });
2626
+ /** String validator and its refinement/morph keyword module. */
2627
+ type.string = Object.defineProperties(makeType({ k: "string" }, [], {}), Object.getOwnPropertyDescriptors({
2628
+ alpha: keywordSchema("string.alpha"),
2629
+ alphanumeric: keywordSchema("string.alphanumeric"),
2630
+ base64,
2631
+ capitalize: preformattedKeyword("string.capitalize"),
2632
+ creditCard: keywordSchema("string.creditCard"),
2633
+ date,
2634
+ digits: keywordSchema("string.digits"),
2635
+ email: keywordSchema("string.email"),
2636
+ hex: keywordSchema("string.hex"),
2637
+ integer: parsedKeyword("string.integer"),
2638
+ ip,
2639
+ json: parsedKeyword("string.json"),
2640
+ lower: preformattedKeyword("string.lower"),
2641
+ normalize,
2642
+ numeric: parsedKeyword("string.numeric"),
2643
+ regex: keywordSchema("string.regex"),
2644
+ semver: keywordSchema("string.semver"),
2645
+ trim: preformattedKeyword("string.trim"),
2646
+ upper: preformattedKeyword("string.upper"),
2647
+ url: parsedKeyword("string.url"),
2648
+ uuid,
2649
+ }));
2650
+ /** Runtime parser keyword family. */
2651
+ type.parse = {
2652
+ number: keywordSchema("parse.number"),
2653
+ integer: keywordSchema("parse.integer"),
2654
+ json: keywordSchema("parse.json"),
2655
+ date: keywordSchema("parse.date"),
2656
+ url: keywordSchema("parse.url"),
2657
+ boolean: keywordSchema("parse.boolean"),
2658
+ bigint: keywordSchema("parse.bigint"),
2659
+ };
2660
+ /** Number validator with integer refinement. */
2661
+ type.number = Object.assign(makeType({ k: "number" }, [], {}), {
2662
+ integer: makeType({ k: "number", int: true }, [], {}),
2663
+ });
2664
+ /** Schema-valued key representing any non-negative integer array index. */
2665
+ type.arrayIndex = makeType({
2666
+ k: "refine",
2667
+ base: { k: "string" },
2668
+ pred: value => typeof value === "string" && /^(?:0|[1-9]\d*)$/.test(value),
2669
+ expected: "a non-negative integer string",
2670
+ }, [], {});
2671
+ /** Boolean validator. */
2672
+ type.boolean = makeType({ k: "boolean" }, [], {});
2673
+ /** Bigint validator. */
2674
+ type.bigint = makeType({ k: "bigint" }, [], {});
2675
+ /** Symbol validator. */
2676
+ type.symbol = makeType({ k: "symbol" }, [], {});
2677
+ /** Non-null object validator. */
2678
+ type.object = makeType({ k: "anyobject" }, [], {});
2679
+ /** Unknown validator. */
2680
+ type.unknown = makeType({ k: "unknown" }, [], {});
2681
+ /** Alias of the unknown validator. */
2682
+ type.any = type.unknown;
2683
+ /** Validator that rejects every value. */
2684
+ type.never = makeType({ k: "never" }, [], {});
2685
+ /** ArkType's built-in keyword namespace, including invokable utility generics. */
2686
+ type.keywords = {
2687
+ number: { integer: type.number.integer },
2688
+ Map: keywordSchema("Map"),
2689
+ Set: keywordSchema("Set"),
2690
+ RegExp: keywordSchema("RegExp"),
2691
+ File: keywordSchema("File"),
2692
+ Error: keywordSchema("Error"),
2693
+ // biome-ignore lint/complexity/noBannedTypes: built-in Function keyword
2694
+ Function: keywordSchema("Function"),
2695
+ Array: {
2696
+ liftFrom(definition) {
2697
+ const element = parseDef(definition);
2698
+ const array = { k: "array", el: element, desc: "an object" };
2699
+ return makeType({
2700
+ k: "morph",
2701
+ input: { k: "union", members: [element, array] },
2702
+ fn: value => (globalThis.Array.isArray(value) ? value : [value]),
2703
+ out: array,
2704
+ }, [], {});
2705
+ },
2706
+ },
2707
+ Record(key, value) {
2708
+ const keyIR = parseDef(key);
2709
+ if (keyIR.k !== "string" && keyIR.k !== "symbol") {
2710
+ throw new OmpTypeError("Record key must be assignable to string or symbol");
2711
+ }
2712
+ const valueIR = parseDef(value);
2713
+ const ir = keyIR.k === "symbol"
2714
+ ? { k: "object", props: [], symbolIndex: valueIR, extras: "keep" }
2715
+ : { k: "object", props: [], index: valueIR, extras: "keep" };
2716
+ return makeType(ir, [], {});
2717
+ },
2718
+ Partial(definition) {
2719
+ return makeType(setObjectOptionality(parseDef(definition), true, "partial"), [], {});
2720
+ },
2721
+ Required(definition) {
2722
+ return makeType(setObjectOptionality(parseDef(definition), false, "required"), [], {});
2723
+ },
2724
+ Pick(definition, ...keys) {
2725
+ return makeType(selectObjectProps(parseDef(definition), keys, true, "pick"), [], {});
2726
+ },
2727
+ Omit(definition, ...keys) {
2728
+ return makeType(selectObjectProps(parseDef(definition), keys, false, "omit"), [], {});
2729
+ },
2730
+ Merge(left, right) {
2731
+ return makeType(mergeObjectDefinition(parseDef(left), right), [], {});
2732
+ },
2733
+ object: {
2734
+ json: Object.defineProperties(keywordSchema("object.json"), {
2735
+ stringify: {
2736
+ value: keywordSchema("object.json.stringify"),
2737
+ enumerable: true,
2738
+ },
2739
+ }),
2740
+ },
2741
+ unknown: { any: keywordSchema("unknown.any") },
2742
+ };
2743
+ /** Date instance validator. */
2744
+ // biome-ignore lint/suspicious/noShadowRestrictedNames: ArkType exposes this exact keyword.
2745
+ type.Date = makeType({ k: "instance", ctor: globalThis.Date, expected: "a Date" }, [], {});
2746
+ /** Validate instances of `ctor`. */
2747
+ function instanceOf(ctor) {
2748
+ if (typeof ctor !== "function" || ctor.prototype === undefined) {
2749
+ throw new OmpTypeError("instanceof operands must be constructors");
2750
+ }
2751
+ const name = Reflect.get(ctor, "name");
2752
+ const expected = ctor.prototype === Error.prototype
2753
+ ? "an Error"
2754
+ : typeof name === "string" && name.length > 0
2755
+ ? `an instance of ${name}`
2756
+ : "an instance";
2757
+ return makeType({ k: "instance", ctor, expected }, [], {});
2758
+ }
2759
+ type.instanceOf = instanceOf;
2760
+ /** Validate one exact unit value. */
2761
+ function unit(value) {
2762
+ return makeType({ k: "lit", v: value }, [], {});
2763
+ }
2764
+ type.unit = unit;
2765
+ /** Union of literal values from a runtime array. */
2766
+ function enumerated(...values) {
2767
+ const members = values.map(value => ({ k: "lit", v: value }));
2768
+ const ir = members.length === 0 ? { k: "never" } : members.length === 1 ? members[0] : { k: "union", members };
2769
+ return makeType(ir, [], {});
2770
+ }
2771
+ type.enumerated = enumerated;
2772
+ /** Enumerate an enum-like object's forward values, excluding numeric reverse mappings. */
2773
+ // biome-ignore lint/suspicious/noShadowRestrictedNames: Object.prototype.valueOf method name API
2774
+ function valueOf(values) {
2775
+ const members = [];
2776
+ for (const key in values) {
2777
+ if (/^(?:0|[1-9]\d*)$/.test(key))
2778
+ continue;
2779
+ members.push({ k: "lit", v: values[key] });
2780
+ }
2781
+ const ir = members.length === 0 ? { k: "never" } : members.length === 1 ? members[0] : { k: "union", members };
2782
+ return makeType(ir, [], {});
2783
+ }
2784
+ type.valueOf = valueOf;
2785
+ /** Fluent first-match dispatcher, also exported as standalone `match`. */
2786
+ type.match = matchBuilder;
2787
+ /** Preserve a definition's literal type while authoring reusable modules. */
2788
+ function define(definition) {
2789
+ return definition;
2790
+ }
2791
+ type.define = define;
2792
+ /** Build a function whose arguments and optional declared return are validated. */
2793
+ type.fn = makeFn();
2794
+ /** Fix an externally declared static type while retaining runtime validation. */
2795
+ // biome-ignore lint/complexity/noBannedTypes: empty default options object
2796
+ type.declare = () => ({
2797
+ type: definition => type(definition),
2798
+ });
2799
+ /** Build a lazy named scope from aliases and recursive definitions. */
2800
+ function scope(aliases, options) {
2801
+ return buildScope(aliases, options);
2802
+ }
2803
+ type.scope = scope;
2804
+ /** Compile a named schema module whose definitions may reference each other. */
2805
+ function module(definitions, options) {
2806
+ return scope(definitions, options).export();
2807
+ }
2808
+ type.module = module;
2809
+ function generic(...arguments_) {
2810
+ if (arguments_.length === 2 && typeof arguments_[0] === "string" && arguments_[0].trimStart().startsWith("<")) {
2811
+ return createRuntimeGeneric(parseGenericParameters(arguments_[0]), arguments_[1]);
2812
+ }
2813
+ const parameters = arguments_.map(parameter => {
2814
+ if (typeof parameter === "string")
2815
+ return { name: parameter.trim() };
2816
+ if (Array.isArray(parameter) && typeof parameter[0] === "string") {
2817
+ return { name: parameter[0].trim(), constraintDef: parameter[1] };
2818
+ }
2819
+ throw new OmpTypeError("generic parameters must be names or [name, constraint] pairs");
2820
+ });
2821
+ validateGenericParameters(parameters);
2822
+ return (definition) => createRuntimeGeneric(parameters, definition);
2823
+ }
2824
+ type.generic = generic;
2825
+ /** Untyped builder for runtime-assembled definitions. */
2826
+ function raw(def) {
2827
+ return makeType(parseDef(def), [], {});
2828
+ }
2829
+ type.raw = raw;
2830
+ })(type || (type = {}));
2831
+ // Reserved words cannot be declared as namespace bindings, but ArkType exposes
2832
+ // them as runtime keyword properties.
2833
+ Object.assign(type, {
2834
+ null: makeType({ k: "null" }, [], {}),
2835
+ undefined: makeType({ k: "undefined" }, [], {}),
2836
+ true: makeType({ k: "lit", v: true }, [], {}),
2837
+ false: makeType({ k: "lit", v: false }, [], {}),
2838
+ });
2839
+ const MODULE_SCOPE = Symbol("omptype.moduleScope");
2840
+ /** Build a scope whose aliases resolve lazily, including recursive cycles. */
2841
+ export function scope(aliases, options) {
2842
+ return buildScope(aliases, options);
2843
+ }
2844
+ (function (scope) {
2845
+ /** Preserve a scope definition's literal shape without constructing it. */
2846
+ function define(definitions) {
2847
+ return definitions;
2848
+ }
2849
+ scope.define = define;
2850
+ })(scope || (scope = {}));
2851
+ function isRuntimeModule(value) {
2852
+ return typeof value === "object" && value !== null && MODULE_SCOPE in value;
2853
+ }
2854
+ function buildScope(aliases, options) {
2855
+ const scopeMeta = options?.clone === undefined ? EMPTY_META : { clone: options.clone };
2856
+ const withScopeConfig = (ir) => options?.divisor === undefined ? ir : configureSelected(ir, options.divisor, { kind: "divisor" });
2857
+ const entries = new Map();
2858
+ for (const sourceName in aliases) {
2859
+ const isPrivate = sourceName.startsWith("#");
2860
+ const visibleName = isPrivate ? sourceName.slice(1) : sourceName;
2861
+ const declaration = parseGenericDeclaration(visibleName);
2862
+ const external = isRuntimeGeneric(aliases[sourceName]) ? aliases[sourceName] : undefined;
2863
+ const name = declaration?.name ?? visibleName;
2864
+ if (entries.has(name))
2865
+ throw new OmpTypeError(`alias "${name}" is declared as both public and private`);
2866
+ entries.set(name, {
2867
+ name,
2868
+ sourceName,
2869
+ private: isPrivate,
2870
+ genericParameters: declaration?.parameters ?? external?.[GENERIC_META].parameters,
2871
+ definition: aliases[sourceName],
2872
+ generic: external,
2873
+ materialized: false,
2874
+ });
2875
+ }
2876
+ const references = new Map();
2877
+ const targets = new Map();
2878
+ let scopeValue;
2879
+ const materialize = (entry) => {
2880
+ if (entry.materialized)
2881
+ return entry.definition;
2882
+ entry.materialized = true;
2883
+ if (entry.genericParameters === undefined &&
2884
+ typeof entry.definition === "function" &&
2885
+ !(IR_BRAND in entry.definition)) {
2886
+ entry.definition = Reflect.apply(entry.definition, undefined, []);
2887
+ }
2888
+ return entry.definition;
2889
+ };
2890
+ const moduleSchema = (module, parts) => {
2891
+ let current = module;
2892
+ for (const part of parts) {
2893
+ if (!isRuntimeModule(current))
2894
+ return undefined;
2895
+ const next = current[part];
2896
+ if (next === undefined)
2897
+ return undefined;
2898
+ current = next;
2899
+ }
2900
+ if (isRuntimeModule(current)) {
2901
+ const root = current.root;
2902
+ return root !== undefined && !isRuntimeModule(root) ? root : undefined;
2903
+ }
2904
+ return current;
2905
+ };
2906
+ const resolve = ((path) => {
2907
+ const [name, ...parts] = path.split(".");
2908
+ const entry = entries.get(name);
2909
+ if (entry === undefined || entry.genericParameters !== undefined)
2910
+ return undefined;
2911
+ const definition = materialize(entry);
2912
+ if (isRuntimeModule(definition)) {
2913
+ const schema = moduleSchema(definition, parts);
2914
+ return schema === undefined ? undefined : embed(schema);
2915
+ }
2916
+ if (parts.length !== 0)
2917
+ return undefined;
2918
+ const existing = references.get(name);
2919
+ if (existing !== undefined)
2920
+ return existing;
2921
+ const reference = {
2922
+ k: "alias",
2923
+ name,
2924
+ resolve: () => {
2925
+ const target = targets.get(name);
2926
+ if (target !== undefined)
2927
+ return target;
2928
+ const parsed = parseDef(definition, resolve);
2929
+ targets.set(name, parsed);
2930
+ return parsed;
2931
+ },
2932
+ };
2933
+ references.set(name, reference);
2934
+ return reference;
2935
+ });
2936
+ const genericFor = (entry) => {
2937
+ if (entry.generic !== undefined)
2938
+ return entry.generic;
2939
+ const parameters = entry.genericParameters;
2940
+ if (parameters === undefined)
2941
+ throw new OmpTypeError(`alias "${entry.name}" is not generic`);
2942
+ entry.generic = createRuntimeGeneric(parameters, entry.definition, resolve, false);
2943
+ return entry.generic;
2944
+ };
2945
+ const genericInstantiations = new Map();
2946
+ resolve.hasGeneric = name => entries.get(name)?.genericParameters !== undefined;
2947
+ resolve.generic = (name, arguments_) => {
2948
+ const entry = entries.get(name);
2949
+ if (entry === undefined || entry.genericParameters === undefined)
2950
+ return undefined;
2951
+ const key = `${name}<${arguments_.map(expectedOf).join(",")}>`;
2952
+ const existing = genericInstantiations.get(key);
2953
+ if (existing !== undefined)
2954
+ return existing;
2955
+ let target;
2956
+ const reference = {
2957
+ k: "alias",
2958
+ name: key,
2959
+ resolve: () => {
2960
+ target ??= genericFor(entry)[GENERIC_META].instantiateIR(arguments_);
2961
+ return target;
2962
+ },
2963
+ };
2964
+ genericInstantiations.set(key, reference);
2965
+ target = genericFor(entry)[GENERIC_META].instantiateIR(arguments_);
2966
+ return target;
2967
+ };
2968
+ const bind = (schema) => {
2969
+ Reflect.set(schema, "$", scopeValue);
2970
+ Reflect.set(schema, "resolver", resolve);
2971
+ return schema;
2972
+ };
2973
+ const parseScoped = (definition) => bind(makeType(withScopeConfig(parseDef(definition, resolve)), EMPTY_STEPS, scopeMeta));
2974
+ const scopedMatch = createMatchParser({
2975
+ parse: definition => parseScoped(definition),
2976
+ branches: [],
2977
+ });
2978
+ const scoped = Object.assign((definition) => parseScoped(definition), type, {
2979
+ fn: makeFn(resolve),
2980
+ match: scopedMatch,
2981
+ ...naryStatics(resolve),
2982
+ });
2983
+ const targetFor = (name) => {
2984
+ const resolved = resolve(name);
2985
+ if (resolved === undefined)
2986
+ throw new OmpTypeError(`unknown alias "${name}"`);
2987
+ return resolved.k === "alias" ? resolved.resolve() : resolved;
2988
+ };
2989
+ const schemaFor = (name) => bind(makeType(withScopeConfig(targetFor(name)), EMPTY_STEPS, scopeMeta));
2990
+ const bindModule = (names) => {
2991
+ const module = {};
2992
+ Object.defineProperty(module, MODULE_SCOPE, { value: scopeValue });
2993
+ for (const name of names) {
2994
+ const entry = entries.get(name);
2995
+ if (entry === undefined)
2996
+ continue;
2997
+ if (entry.genericParameters !== undefined) {
2998
+ module[name] = genericFor(entry);
2999
+ continue;
3000
+ }
3001
+ const definition = materialize(entry);
3002
+ module[name] = isRuntimeModule(definition) ? definition : schemaFor(name);
3003
+ }
3004
+ return module;
3005
+ };
3006
+ scopeValue = {
3007
+ type: scoped,
3008
+ match: scopedMatch,
3009
+ define(definition) {
3010
+ return definition;
3011
+ },
3012
+ resolve(name) {
3013
+ return schemaFor(name);
3014
+ },
3015
+ import(...names) {
3016
+ const selected = names.length === 0
3017
+ ? [...entries.values()].filter(entry => !entry.private)
3018
+ : names.map(name => {
3019
+ const entry = entries.get(name);
3020
+ if (entry === undefined)
3021
+ throw new OmpTypeError(`unknown alias "${name}"`);
3022
+ return entry;
3023
+ });
3024
+ const imported = {};
3025
+ for (const entry of selected) {
3026
+ imported[`#${entry.sourceName.startsWith("#") ? entry.sourceName.slice(1) : entry.sourceName}`] =
3027
+ entry.genericParameters === undefined ? schemaFor(entry.name) : genericFor(entry);
3028
+ }
3029
+ return imported;
3030
+ },
3031
+ export(...names) {
3032
+ const selected = names.length === 0 ? [...entries.values()].filter(entry => !entry.private).map(entry => entry.name) : names;
3033
+ // Export is the eager boundary: malformed aliases and bad thunks fail here,
3034
+ // while recursive references inside valid definitions stay lazy.
3035
+ for (const entry of entries.values()) {
3036
+ if (entry.genericParameters !== undefined)
3037
+ genericFor(entry);
3038
+ else if (!isRuntimeModule(materialize(entry)))
3039
+ targetFor(entry.name);
3040
+ }
3041
+ return bindModule(selected);
3042
+ },
3043
+ get json() {
3044
+ const json = {};
3045
+ const add = (prefix, module) => {
3046
+ for (const name of Object.keys(module)) {
3047
+ const value = module[name];
3048
+ const path = prefix === "" ? name : `${prefix}.${name}`;
3049
+ if (isRuntimeModule(value))
3050
+ add(path, value);
3051
+ else
3052
+ json[path] = Reflect.get(value, "json");
3053
+ }
3054
+ };
3055
+ add("", bindModule([...entries.values()].filter(entry => !entry.private).map(entry => entry.name)));
3056
+ return json;
3057
+ },
3058
+ };
3059
+ return scopeValue;
3060
+ }
3061
+ /** `hasMorph` re-export for diagnostics/tooling. */
3062
+ export { hasMorph };