@buckeyestudio/omptype 18.4.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/infer.ts ADDED
@@ -0,0 +1,457 @@
1
+ /** Type-level input and output inference for definitions accepted by omptype. */
2
+
3
+ type Whitespace = " " | "\n" | "\r" | "\t";
4
+
5
+ type TrimLeft<s extends string> = s extends `${Whitespace}${infer rest}` ? TrimLeft<rest> : s;
6
+ type TrimRight<s extends string> = s extends `${infer rest}${Whitespace}` ? TrimRight<rest> : s;
7
+ type Trim<s extends string> = TrimLeft<TrimRight<s>>;
8
+
9
+ /**
10
+ * Flat keyword lookup. An indexed access is one instantiation level, unlike a
11
+ * nested conditional chain — this sits under every string-DSL property, so its
12
+ * depth is multiplied by every layer of object nesting above it.
13
+ * `never` is intentionally absent: the parser rejects it and the fallback in
14
+ * `InferMember` treats a missing entry as "not a primitive".
15
+ */
16
+ type ArkAny = ReturnType<typeof JSON.parse>;
17
+
18
+ interface PrimitiveMap {
19
+ string: string;
20
+ "string.url": string;
21
+ number: number;
22
+ "number.integer": number;
23
+ "number.epoch": number;
24
+ "number.safe": number;
25
+ "number.NaN": number;
26
+ "number.Infinity": number;
27
+ "number.NegativeInfinity": number;
28
+ boolean: boolean;
29
+ null: null;
30
+ undefined: undefined;
31
+ unknown: unknown;
32
+ "unknown.any": ArkAny;
33
+ any: unknown;
34
+ object: object;
35
+ bigint: bigint;
36
+ symbol: symbol;
37
+ Key: PropertyKey;
38
+ Date: Date;
39
+ Array: unknown[];
40
+ Function: Function;
41
+ RegExp: RegExp;
42
+ File: File;
43
+ Error: Error;
44
+ Set: Set<unknown>;
45
+ Map: Map<unknown, unknown>;
46
+ WeakSet: WeakSet<WeakKey>;
47
+ WeakMap: WeakMap<WeakKey, unknown>;
48
+ Promise: Promise<unknown>;
49
+ FormData: FormData;
50
+ "object.json": unknown;
51
+ true: true;
52
+ false: false;
53
+ }
54
+
55
+ type Merge<left, right> = left extends object
56
+ ? right extends object
57
+ ? Omit<left, keyof right> & right
58
+ : never
59
+ : never;
60
+
61
+ type InferUtility<s extends string> = s extends `Record<${string},${infer value}>`
62
+ ? Record<string, InferString<value>>
63
+ : s extends `Array<${infer element}>` | `Array.liftFrom<${infer element}>`
64
+ ? InferString<element>[]
65
+ : s extends `Partial<${infer value}>`
66
+ ? Partial<InferString<value>>
67
+ : s extends `Required<${infer value}>`
68
+ ? Required<InferString<value>>
69
+ : s extends `Pick<${infer value},${infer keys}>`
70
+ ? Pick<InferString<value>, Extract<InferString<keys>, keyof InferString<value>>>
71
+ : s extends `Omit<${infer value},${infer keys}>`
72
+ ? Omit<InferString<value>, Extract<InferString<keys>, keyof InferString<value>>>
73
+ : s extends `Merge<${infer left},${infer right}>`
74
+ ? Merge<InferString<left>, InferString<right>>
75
+ : never;
76
+
77
+ /** Output types of morph (`.parse`) keywords; `never` when `s` is not one. */
78
+ type InferParse<s extends string> = s extends
79
+ | "string.numeric.parse"
80
+ | "string.integer.parse"
81
+ | "parse.number"
82
+ | "parse.integer"
83
+ ? number
84
+ : s extends "string.date.parse" | "string.date.iso.parse" | "string.date.epoch.parse" | "parse.date"
85
+ ? Date
86
+ : s extends "string.url.parse" | "parse.url"
87
+ ? URL
88
+ : s extends "string.json.parse" | "parse.json"
89
+ ? unknown
90
+ : s extends "object.json.stringify"
91
+ ? string
92
+ : s extends "FormData.parse"
93
+ ? Record<string, Bun.FormDataEntryValue | Bun.FormDataEntryValue[]>
94
+ : s extends "parse.boolean"
95
+ ? boolean
96
+ : s extends "parse.bigint"
97
+ ? bigint
98
+ : never;
99
+
100
+ /**
101
+ * Member inference as a flat false-branch chain: TypeScript tail-evaluates
102
+ * chained conditionals in the false position, so this stays at constant
103
+ * instantiation depth where the previous `extends infer` ladder nested every
104
+ * fallback inside a true branch and accumulated depth per step.
105
+ */
106
+ type InferMember<member extends string> = Trim<member> extends infer s extends string ? InferMemberTrimmed<s> : unknown;
107
+
108
+ type InferMemberTrimmed<s extends string> = s extends `(${infer inner})`
109
+ ? InferString<inner>
110
+ : s extends `${infer element}[]`
111
+ ? InferMember<element>[]
112
+ : s extends `'${infer literal}'` | `"${infer literal}"`
113
+ ? literal
114
+ : s extends `d'${string}'` | `d"${string}"`
115
+ ? Date
116
+ : s extends `\`${string}\``
117
+ ? string
118
+ : s extends `/${string}/${string}` | `/${string}/`
119
+ ? string
120
+ : s extends `${infer literal extends number}`
121
+ ? literal
122
+ : s extends keyof PrimitiveMap
123
+ ? PrimitiveMap[s]
124
+ : [InferParse<s>] extends [never]
125
+ ? InferUtility<s> extends infer utility
126
+ ? [utility] extends [never]
127
+ ? InferMemberFallback<s>
128
+ : utility
129
+ : unknown
130
+ : InferParse<s>;
131
+
132
+ type InferMemberFallback<s extends string> = s extends `string.${string}`
133
+ ? string
134
+ : s extends `${string}Date${string}`
135
+ ? Date
136
+ : s extends `${string}string${string}`
137
+ ? string
138
+ : s extends `${string}number${string}`
139
+ ? number
140
+ : unknown;
141
+
142
+ /** Split unions without distributing over the accumulated members. */
143
+ type InferUnion<s extends string, result = never> = s extends `${infer head}|${infer tail}`
144
+ ? InferUnion<tail, result | InferMember<head>>
145
+ : result | InferMember<s>;
146
+
147
+ /** Input side of one union member: morph keywords accept their source type. */
148
+ type InferMemberIn<member extends string> =
149
+ Trim<member> extends infer s extends string
150
+ ? s extends `${string}.parse` | `parse.${string}`
151
+ ? string
152
+ : InferMemberTrimmed<s>
153
+ : unknown;
154
+
155
+ /** Split unions on the input side without distributing over accumulated members. */
156
+ type InferUnionIn<s extends string, result = never> = s extends `${infer head}|${infer tail}`
157
+ ? InferUnionIn<tail, result | InferMemberIn<head>>
158
+ : result | InferMemberIn<s>;
159
+
160
+ type HasInlineDefault<s extends string> = s extends `${string}=${string}`
161
+ ? s extends `${string}<${string}` | `${string}>${string}`
162
+ ? false
163
+ : true
164
+ : false;
165
+
166
+ type WithoutInlineDefault<s extends string> =
167
+ HasInlineDefault<s> extends true ? (s extends `${infer base}=${string}` ? Trim<base> : s) : s;
168
+
169
+ type InferStringOutput<s extends string> = InferUnion<s>;
170
+
171
+ /** String-DSL output inference. */
172
+ export type InferString<s extends string> =
173
+ WithoutInlineDefault<Trim<s>> extends infer trimmed extends string
174
+ ? trimmed extends `${infer base}?`
175
+ ? InferString<base>
176
+ : trimmed extends `(${infer inner})[]`
177
+ ? InferUnion<inner>[]
178
+ : InferStringOutput<trimmed>
179
+ : unknown;
180
+
181
+ /** String-DSL input inference, preserving the source side of morph keywords. */
182
+ export type InferStringIn<s extends string> =
183
+ WithoutInlineDefault<Trim<s>> extends infer trimmed extends string
184
+ ? trimmed extends `${infer base}?`
185
+ ? InferStringIn<base>
186
+ : trimmed extends `(${infer inner})[]`
187
+ ? InferUnionIn<inner>[]
188
+ : InferUnionIn<trimmed>
189
+ : unknown;
190
+
191
+ type HasDefault<def> = def extends string
192
+ ? HasInlineDefault<def>
193
+ : def extends readonly [unknown, "=", unknown]
194
+ ? true
195
+ : def extends { readonly hasDefault: true }
196
+ ? true
197
+ : false;
198
+
199
+ type DefinitionKeys<def extends object> = Exclude<keyof def, "+" | "[string]" | "...">;
200
+
201
+ type IsOptionalProp<key, def> = key extends `${string}?`
202
+ ? true
203
+ : def extends string
204
+ ? Trim<def> extends `${string}?`
205
+ ? true
206
+ : false
207
+ : def extends readonly [unknown, "?"]
208
+ ? true
209
+ : false;
210
+
211
+ type PropName<key extends PropertyKey> = key extends `${infer name}?` ? name : key;
212
+ type UnwrapProperty<def> = def extends readonly [infer value, "?" | "=", ...unknown[]] ? value : def;
213
+ type Simplify<t> = { [key in keyof t]: t[key] };
214
+
215
+ type OutputRequired<def extends object> = {
216
+ -readonly [
217
+ key in DefinitionKeys<def> as IsOptionalProp<key, def[key]> extends true
218
+ ? HasDefault<def[key]> extends true
219
+ ? PropName<key>
220
+ : never
221
+ : PropName<key>
222
+ ]-?: InferDef<UnwrapProperty<def[key]>>;
223
+ };
224
+
225
+ type OutputOptional<def extends object> = {
226
+ -readonly [
227
+ key in DefinitionKeys<def> as IsOptionalProp<key, def[key]> extends true
228
+ ? HasDefault<def[key]> extends true
229
+ ? never
230
+ : PropName<key>
231
+ : never
232
+ ]?: InferDef<UnwrapProperty<def[key]>>;
233
+ };
234
+
235
+ type InputRequired<def extends object> = {
236
+ -readonly [
237
+ key in DefinitionKeys<def> as IsOptionalProp<key, def[key]> extends true
238
+ ? never
239
+ : HasDefault<def[key]> extends true
240
+ ? never
241
+ : PropName<key>
242
+ ]-?: InferDefIn<UnwrapProperty<def[key]>>;
243
+ };
244
+
245
+ type InputOptional<def extends object> = {
246
+ -readonly [
247
+ key in DefinitionKeys<def> as IsOptionalProp<key, def[key]> extends true
248
+ ? PropName<key>
249
+ : HasDefault<def[key]> extends true
250
+ ? PropName<key>
251
+ : never
252
+ ]?: InferDefIn<UnwrapProperty<def[key]>>;
253
+ };
254
+
255
+ /**
256
+ * CYCLE SAFETY: when a fluent generic method is called on a schema whose def
257
+ * embeds other schemas, TypeScript instantiates `InferDef<def>` while `def`
258
+ * is still generic. `"..." extends keyof def` resolves TRUE under permissive
259
+ * instantiation (`keyof any` contains every literal), so spread/index members
260
+ * cannot be deferred by wrapper conditionals — a bare `InferDef<def["..."]>`
261
+ * member re-enters this expansion and instantiates without bound (TS2589).
262
+ * Interface members only instantiate when resolved, so routing the recursive
263
+ * reference through `DefBox` keeps generic instantiation shallow: it stops at
264
+ * a type reference plus an indexed access instead of expanding `InferDef`.
265
+ */
266
+ interface DefBox<def> {
267
+ readonly out: InferDef<def>;
268
+ readonly in: InferDefIn<def>;
269
+ }
270
+
271
+ type OutputSpread<def extends object> = "..." extends keyof def ? DefBox<def["..."]>["out"] : unknown;
272
+ type InputSpread<def extends object> = "..." extends keyof def ? DefBox<def["..."]>["in"] : unknown;
273
+ type OutputIndex<def extends object> = "[string]" extends keyof def
274
+ ? Record<string, DefBox<def["[string]"]>["out"]>
275
+ : unknown;
276
+ type InputIndex<def extends object> = "[string]" extends keyof def
277
+ ? Record<string, DefBox<def["[string]"]>["in"]>
278
+ : unknown;
279
+
280
+ type InferObject<def extends object> = "[string]" extends keyof def
281
+ ? [DefinitionKeys<def>] extends [never]
282
+ ? Record<string, DefBox<def["[string]"]>["out"]>
283
+ : Simplify<OutputRequired<def> & OutputOptional<def> & OutputSpread<def>> & OutputIndex<def>
284
+ : Simplify<OutputRequired<def> & OutputOptional<def> & OutputSpread<def>>;
285
+
286
+ type InferObjectIn<def extends object> = "[string]" extends keyof def
287
+ ? [DefinitionKeys<def>] extends [never]
288
+ ? Record<string, DefBox<def["[string]"]>["in"]>
289
+ : Simplify<InputRequired<def> & InputOptional<def> & InputSpread<def>> & InputIndex<def>
290
+ : Simplify<InputRequired<def> & InputOptional<def> & InputSpread<def>>;
291
+
292
+ /** Object-literal inference used by fluent composition overloads. */
293
+ export type InferObjectDef<def extends object> = InferObject<def>;
294
+
295
+ type InferLiteralDef<def> = def extends { readonly infer: infer output }
296
+ ? output
297
+ : def extends string
298
+ ? InferString<def>
299
+ : def extends object
300
+ ? InferObjectLiteral<def>
301
+ : unknown;
302
+
303
+ type InferLiteralDefIn<def> = def extends { readonly inferIn: infer input }
304
+ ? input
305
+ : def extends string
306
+ ? InferStringIn<def>
307
+ : def extends object
308
+ ? InferObjectLiteralIn<def>
309
+ : unknown;
310
+
311
+ type LiteralRequired<def extends object> = {
312
+ -readonly [
313
+ key in DefinitionKeys<def> as IsOptionalProp<key, def[key]> extends true
314
+ ? HasDefault<def[key]> extends true
315
+ ? PropName<key>
316
+ : never
317
+ : PropName<key>
318
+ ]-?: InferLiteralDef<UnwrapProperty<def[key]>>;
319
+ };
320
+
321
+ type LiteralOptional<def extends object> = {
322
+ -readonly [
323
+ key in DefinitionKeys<def> as IsOptionalProp<key, def[key]> extends true
324
+ ? HasDefault<def[key]> extends true
325
+ ? never
326
+ : PropName<key>
327
+ : never
328
+ ]?: InferLiteralDef<UnwrapProperty<def[key]>>;
329
+ };
330
+
331
+ type LiteralRequiredIn<def extends object> = {
332
+ -readonly [
333
+ key in DefinitionKeys<def> as IsOptionalProp<key, def[key]> extends true
334
+ ? never
335
+ : HasDefault<def[key]> extends true
336
+ ? never
337
+ : PropName<key>
338
+ ]-?: InferLiteralDefIn<UnwrapProperty<def[key]>>;
339
+ };
340
+
341
+ type LiteralOptionalIn<def extends object> = {
342
+ -readonly [
343
+ key in DefinitionKeys<def> as IsOptionalProp<key, def[key]> extends true
344
+ ? PropName<key>
345
+ : HasDefault<def[key]> extends true
346
+ ? PropName<key>
347
+ : never
348
+ ]?: InferLiteralDefIn<UnwrapProperty<def[key]>>;
349
+ };
350
+
351
+ /** Object-literal inference that unwraps embedded schema values one level deep. */
352
+ export type InferObjectLiteral<def extends object> = Simplify<LiteralRequired<def> & LiteralOptional<def>>;
353
+
354
+ /** Input-side object-literal inference (embedded schemas contribute `inferIn`). */
355
+ export type InferObjectLiteralIn<def extends object> = Simplify<LiteralRequiredIn<def> & LiteralOptionalIn<def>>;
356
+
357
+ type InstanceOf<ctor> = ctor extends abstract new (...args: never[]) => infer instance ? instance : never;
358
+ type SpreadOutput<def> = InferDef<def> extends readonly (infer element)[] ? element[] : never[];
359
+ type SpreadInput<def> = InferDefIn<def> extends readonly (infer element)[] ? element[] : never[];
360
+
361
+ type InferTupleOutput<defs extends readonly unknown[], result extends unknown[] = []> = defs extends readonly []
362
+ ? result
363
+ : defs extends readonly ["...", infer spread, ...infer rest]
364
+ ? [...result, ...SpreadOutput<spread>, ...InferTupleOutput<rest>]
365
+ : defs extends readonly [infer head, ...infer rest]
366
+ ? head extends readonly [infer value, "?"]
367
+ ? InferTupleOutput<rest, [...result, InferDef<value>?]>
368
+ : head extends readonly [infer value, "=", unknown]
369
+ ? InferTupleOutput<rest, [...result, InferDef<value>]>
370
+ : InferTupleOutput<rest, [...result, InferDef<head>]>
371
+ : result;
372
+
373
+ type InferTupleInput<defs extends readonly unknown[], result extends unknown[] = []> = defs extends readonly []
374
+ ? result
375
+ : defs extends readonly ["...", infer spread, ...infer rest]
376
+ ? [...result, ...SpreadInput<spread>, ...InferTupleInput<rest>]
377
+ : defs extends readonly [infer head, ...infer rest]
378
+ ? head extends readonly [infer value, "?" | "=", ...unknown[]]
379
+ ? InferTupleInput<rest, [...result, InferDefIn<value>?]>
380
+ : InferTupleInput<rest, [...result, InferDefIn<head>]>
381
+ : result;
382
+
383
+ /**
384
+ * True only for `any` (`1 & any` is `any`; `0 extends any` holds). During
385
+ * relation checking TypeScript instantiates these aliases permissively with
386
+ * every type parameter replaced by `any`, and under `any` the object branch
387
+ * recurses forever (`any["..."]` is `any` again). Cutting `any` off up front
388
+ * makes permissive instantiation terminate immediately, mirroring ArkType's
389
+ * `anyOrNever` guards.
390
+ */
391
+ type IsAny<def> = 0 extends 1 & def ? true : false;
392
+
393
+ /** Infer the validated output type produced by a definition. */
394
+ export type InferDef<def = unknown> =
395
+ IsAny<def> extends true
396
+ ? unknown
397
+ : def extends { readonly infer: infer output }
398
+ ? output
399
+ : def extends string
400
+ ? InferString<def>
401
+ : def extends RegExp
402
+ ? string
403
+ : def extends readonly [infer element, "[]"]
404
+ ? InferDef<element>[]
405
+ : def extends readonly [infer left, "|", infer right]
406
+ ? InferDef<left> | InferDef<right>
407
+ : def extends readonly [infer left, "&", infer right]
408
+ ? InferDef<left> & InferDef<right>
409
+ : def extends readonly [unknown, "=>", (...args: never[]) => infer output]
410
+ ? output
411
+ : def extends readonly [unknown, "|>", infer output]
412
+ ? InferDef<output>
413
+ : def extends readonly [infer base, ":", unknown] | readonly [infer base, "@", unknown]
414
+ ? InferDef<base>
415
+ : def extends readonly ["keyof", infer base]
416
+ ? keyof InferDef<base>
417
+ : def extends readonly ["instanceof", ...infer constructors]
418
+ ? InstanceOf<constructors[number]>
419
+ : def extends readonly ["===", ...infer values]
420
+ ? values[number]
421
+ : def extends readonly unknown[]
422
+ ? InferTupleOutput<def>
423
+ : def extends object
424
+ ? InferObject<def>
425
+ : unknown;
426
+
427
+ /** Infer values accepted before defaults and morphs are applied. */
428
+ export type InferDefIn<def = unknown> =
429
+ IsAny<def> extends true
430
+ ? unknown
431
+ : def extends { readonly inferIn: infer input }
432
+ ? input
433
+ : def extends string
434
+ ? InferStringIn<def>
435
+ : def extends RegExp
436
+ ? string
437
+ : def extends readonly [infer element, "[]"]
438
+ ? InferDefIn<element>[]
439
+ : def extends readonly [infer left, "|", infer right]
440
+ ? InferDefIn<left> | InferDefIn<right>
441
+ : def extends readonly [infer left, "&", infer right]
442
+ ? InferDefIn<left> & InferDefIn<right>
443
+ : def extends readonly [infer input, "=>", unknown] | readonly [infer input, "|>", unknown]
444
+ ? InferDefIn<input>
445
+ : def extends readonly [infer base, ":", unknown] | readonly [infer base, "@", unknown]
446
+ ? InferDefIn<base>
447
+ : def extends readonly ["keyof", infer base]
448
+ ? keyof InferDefIn<base>
449
+ : def extends readonly ["instanceof", ...infer constructors]
450
+ ? InstanceOf<constructors[number]>
451
+ : def extends readonly ["===", ...infer values]
452
+ ? values[number]
453
+ : def extends readonly unknown[]
454
+ ? InferTupleInput<def>
455
+ : def extends object
456
+ ? InferObjectIn<def>
457
+ : unknown;