Comparing version 2.1.6 to 2.1.7
@@ -12,2 +12,3 @@ import { type ArkErrors, type BaseRoot, type Morph } from "@ark/schema"; | ||
input: input; | ||
checked: boolean; | ||
key: PropertyKey | null; | ||
@@ -17,6 +18,7 @@ }; | ||
type from<ctx extends MatchParserContext> = ctx; | ||
type init<$, input = unknown> = from<{ | ||
type init<$, input = unknown, checked extends boolean = false> = from<{ | ||
cases: []; | ||
$: $; | ||
input: input; | ||
checked: checked; | ||
key: null; | ||
@@ -28,2 +30,3 @@ }>; | ||
input: ctx["input"]; | ||
checked: ctx["checked"]; | ||
key: key; | ||
@@ -33,7 +36,7 @@ }>; | ||
export interface MatchParser<$> extends CaseMatchParser<ctx.init<$>> { | ||
in<const def>(def: type.validate<def, $>): ChainableMatchParser<ctx.init<$, type.infer<def, $>>>; | ||
in<const def>(def: type.validate<def, $>): ChainableMatchParser<ctx.init<$, type.infer<def, $>, true>>; | ||
in<const typedInput = never>(...args: [typedInput] extends [never] ? [ | ||
ErrorMessage<"from requires a definition or type argument (from('string') or from<string>())"> | ||
ErrorMessage<"in requires a definition or type argument (in('string') or in<string>())"> | ||
] : []): ChainableMatchParser<ctx.init<$, typedInput>>; | ||
in<const def>(def: type.validate<def, $>): ChainableMatchParser<ctx.init<$, type.infer<def, $>>>; | ||
in<const def>(def: type.validate<def, $>): ChainableMatchParser<ctx.init<$, type.infer<def, $>, true>>; | ||
case: CaseParser<ctx.init<$>>; | ||
@@ -46,2 +49,3 @@ at: AtParser<ctx.init<$>>; | ||
cases: [...ctx["cases"], ...cases]; | ||
checked: ctx["checked"]; | ||
key: ctx["key"]; | ||
@@ -52,14 +56,24 @@ }> : never; | ||
input: defaultCase extends "never" ? Morph.In<ctx["cases"][number]> : ctx["input"]; | ||
cases: defaultCase extends Morph ? [...ctx["cases"], defaultCase] : defaultCase extends "never" | "assert" ? ctx["cases"] : [...ctx["cases"], (In: ctx["input"]) => ArkErrors]; | ||
cases: defaultCase extends "never" | "assert" ? ctx["cases"] : defaultCase extends Morph ? ctx["checked"] extends true ? [ | ||
(In: unknown) => ArkErrors, | ||
...ctx["cases"], | ||
defaultCase | ||
] : [...ctx["cases"], defaultCase] : [ | ||
...ctx["cases"], | ||
(In: ctx["input"]) => ArkErrors | ||
]; | ||
checked: ctx["checked"]; | ||
key: ctx["key"]; | ||
}>; | ||
type casesToMorphTuple<cases, ctx extends MatchParserContext> = unionToTuple<propValueOf<{ | ||
[def in Exclude<keyof cases, "default">]: cases[def] extends (Morph<never, infer o>) ? (In: inferCaseArg<def extends number ? `${number}` : def, ctx, "in">) => o : never; | ||
type CaseKeyKind = "def" | "string"; | ||
type casesToMorphTuple<cases, ctx extends MatchParserContext, kind extends CaseKeyKind> = unionToTuple<propValueOf<{ | ||
[def in Exclude<keyof cases, "default">]: cases[def] extends (Morph<never, infer o>) ? kind extends "def" ? (In: inferCaseArg<def extends number ? `${number}` : def, ctx, "in">) => o : (In: maybeLiftToKey<def, ctx>) => o : never; | ||
}>>; | ||
type addCasesToParser<cases, ctx extends MatchParserContext> = cases extends { | ||
type addCasesToParser<cases, ctx extends MatchParserContext, kind extends CaseKeyKind> = cases extends { | ||
default: infer defaultDef extends DefaultCase<ctx>; | ||
} ? finalizeMatchParser<addCasesToContext<ctx, casesToMorphTuple<cases, ctx>>, defaultDef> : ChainableMatchParser<addCasesToContext<ctx, casesToMorphTuple<cases, ctx>>>; | ||
type inferCaseArg<def, ctx extends MatchParserContext, endpoint extends "in" | "out"> = _finalizeCaseArg<ctx["key"] extends PropertyKey ? { | ||
[k in ctx["key"]]: type.infer<def, ctx["$"]>; | ||
} : type.infer<def, ctx["$"]>, ctx, endpoint>; | ||
} ? finalizeMatchParser<addCasesToContext<ctx, casesToMorphTuple<cases, ctx, kind>>, defaultDef> : ChainableMatchParser<addCasesToContext<ctx, casesToMorphTuple<cases, ctx, kind>>>; | ||
type inferCaseArg<def, ctx extends MatchParserContext, endpoint extends "in" | "out"> = _finalizeCaseArg<maybeLiftToKey<type.infer<def, ctx["$"]>, ctx>, ctx, endpoint>; | ||
type maybeLiftToKey<t, ctx extends MatchParserContext> = ctx["key"] extends PropertyKey ? { | ||
[k in ctx["key"]]: t; | ||
} : t; | ||
type _finalizeCaseArg<t, ctx extends MatchParserContext, endpoint extends "in" | "out"> = [ | ||
@@ -71,5 +85,12 @@ distill<t, "in">, | ||
type validateKey<key extends Key, ctx extends MatchParserContext> = ctx["key"] extends Key ? ErrorMessage<doubleAtMessage> : ctx["cases"]["length"] extends 0 ? keyof ctx["input"] extends never ? key : conform<key, keyof ctx["input"]> : ErrorMessage<chainedAtMessage>; | ||
interface StringsParser<ctx extends MatchParserContext> { | ||
<const cases>(def: cases extends validateStringCases<cases, ctx> ? cases : validateStringCases<cases, ctx>): addCasesToParser<cases, ctx, "string">; | ||
} | ||
type validateStringCases<cases, ctx extends MatchParserContext> = { | ||
[k in keyof cases | stringValue<ctx> | "default"]?: k extends "default" ? DefaultCase<ctx> : k extends stringValue<ctx> ? (In: _finalizeCaseArg<maybeLiftToKey<k, ctx>, ctx, "out">) => unknown : ErrorType<`${k & string} must be a possible string value`>; | ||
}; | ||
type stringValue<ctx extends MatchParserContext> = ctx["key"] extends keyof ctx["input"] ? ctx["input"][ctx["key"]] extends string ? ctx["input"][ctx["key"]] : never : ctx["input"] extends string ? ctx["input"] : never; | ||
interface AtParser<ctx extends MatchParserContext> { | ||
<const key extends string>(key: validateKey<key, ctx>): ChainableMatchParser<ctx.atKey<ctx, key>>; | ||
<const key extends string, const cases, ctxAtKey extends MatchParserContext = ctx.atKey<ctx, key>>(key: validateKey<key, ctx>, cases: cases extends validateCases<cases, ctxAtKey> ? cases : errorCases<cases, ctxAtKey>): addCasesToParser<cases, ctxAtKey>; | ||
<const key extends string, const cases, ctxAtKey extends MatchParserContext = ctx.atKey<ctx, key>>(key: validateKey<key, ctx>, cases: cases extends validateCases<cases, ctxAtKey> ? cases : errorCases<cases, ctxAtKey>): addCasesToParser<cases, ctxAtKey, "def">; | ||
} | ||
@@ -81,2 +102,4 @@ interface ChainableMatchParser<ctx extends MatchParserContext> { | ||
at: AtParser<ctx>; | ||
/** @experimental */ | ||
strings: StringsParser<ctx>; | ||
} | ||
@@ -96,3 +119,3 @@ export type DefaultCaseKeyword = "never" | "assert" | "reject"; | ||
}; | ||
export type CaseMatchParser<ctx extends MatchParserContext> = <const cases>(def: cases extends validateCases<cases, ctx> ? cases : errorCases<cases, ctx>) => addCasesToParser<cases, ctx>; | ||
export type CaseMatchParser<ctx extends MatchParserContext> = <const cases>(def: cases extends validateCases<cases, ctx> ? cases : errorCases<cases, ctx>) => addCasesToParser<cases, ctx, "def">; | ||
type finalizeMatchParser<ctx extends MatchParserContext, defaultCase extends DefaultCase<ctx>> = addDefaultToContext<ctx, defaultCase> extends (infer ctx extends MatchParserContext) ? Match<ctx["input"], ctx["cases"]> : never; | ||
@@ -107,3 +130,3 @@ export interface Match<In = any, cases extends Morph[] = Morph[]> extends Inferred<(In: Morph.In<cases[number]>) => Out<ReturnType<cases[number]>>> { | ||
constructor($: InternalScope); | ||
in(): InternalChainedMatchParser; | ||
in(def?: unknown): InternalChainedMatchParser; | ||
at(key: Key, cases?: InternalCases): InternalChainedMatchParser | Match; | ||
@@ -114,10 +137,15 @@ case(when: unknown, then: Morph): InternalChainedMatchParser; | ||
type InternalCaseParserFn = (cases: InternalCases) => InternalChainedMatchParser | Match; | ||
type CaseEntry = [BaseRoot, Morph] | ["default", DefaultCase]; | ||
export declare class InternalChainedMatchParser extends Callable<InternalCaseParserFn> { | ||
$: InternalScope; | ||
in: BaseRoot | undefined; | ||
protected key: Key | undefined; | ||
protected branches: BaseRoot[]; | ||
constructor($: InternalScope); | ||
constructor($: InternalScope, In?: BaseRoot); | ||
at(key: Key, cases?: InternalCases): InternalChainedMatchParser | Match; | ||
case(def: unknown, resolver: Morph): InternalChainedMatchParser; | ||
protected caseEntry(node: BaseRoot, resolver: Morph): InternalChainedMatchParser; | ||
match(cases: InternalCases): InternalChainedMatchParser | Match; | ||
strings(cases: InternalCases): InternalChainedMatchParser | Match; | ||
protected caseEntries(entries: CaseEntry[]): InternalChainedMatchParser | Match; | ||
default(defaultCase: DefaultCase): Match; | ||
@@ -124,0 +152,0 @@ } |
@@ -11,4 +11,4 @@ import { intrinsic } from "@ark/schema"; | ||
} | ||
in() { | ||
return new InternalChainedMatchParser(this.$); | ||
in(def) { | ||
return new InternalChainedMatchParser(this.$, def === undefined ? undefined : this.$.parse(def)); | ||
} | ||
@@ -24,23 +24,9 @@ at(key, cases) { | ||
$; | ||
in; | ||
key; | ||
branches = []; | ||
constructor($) { | ||
super(cases => { | ||
const entries = Object.entries(cases); | ||
for (let i = 0; i < entries.length; i++) { | ||
const [k, v] = entries[i]; | ||
if (k === "default") { | ||
if (i !== entries.length - 1) { | ||
throwParseError(`default may only be specified as the last key of a switch definition`); | ||
} | ||
return this.default(v); | ||
} | ||
if (typeof v !== "function") { | ||
return throwParseError(`Value for case "${k}" must be a function (was ${domainOf(v)})`); | ||
} | ||
this.case(k, v); | ||
} | ||
return this; | ||
}); | ||
constructor($, In) { | ||
super(cases => this.caseEntries(Object.entries(cases).map(([k, v]) => k === "default" ? [k, v] : [this.$.parse(k), v]))); | ||
this.$ = $; | ||
this.in = In; | ||
} | ||
@@ -56,4 +42,7 @@ at(key, cases) { | ||
case(def, resolver) { | ||
const wrappableDef = this.key ? { [this.key]: def } : def; | ||
const branch = this.$.parse(wrappableDef).pipe(resolver); | ||
return this.caseEntry(this.$.parse(def), resolver); | ||
} | ||
caseEntry(node, resolver) { | ||
const wrappableNode = this.key ? this.$.parse({ [this.key]: node }) : node; | ||
const branch = wrappableNode.pipe(resolver); | ||
this.branches.push(branch); | ||
@@ -65,2 +54,23 @@ return this; | ||
} | ||
strings(cases) { | ||
return this.caseEntries(Object.entries(cases).map(([k, v]) => k === "default" ? | ||
[k, v] | ||
: [this.$.node("unit", { unit: k }), v])); | ||
} | ||
caseEntries(entries) { | ||
for (let i = 0; i < entries.length; i++) { | ||
const [k, v] = entries[i]; | ||
if (k === "default") { | ||
if (i !== entries.length - 1) { | ||
throwParseError(`default may only be specified as the last key of a switch definition`); | ||
} | ||
return this.default(v); | ||
} | ||
if (typeof v !== "function") { | ||
return throwParseError(`Value for case "${k}" must be a function (was ${domainOf(v)})`); | ||
} | ||
this.caseEntry(k, v); | ||
} | ||
return this; | ||
} | ||
default(defaultCase) { | ||
@@ -75,4 +85,12 @@ if (typeof defaultCase === "function") | ||
schema.meta = { onFail: throwOnDefault }; | ||
const matcher = this.$.finalize(this.$.node("union", schema)); | ||
return matcher; | ||
const cases = this.$.node("union", schema); | ||
if (!this.in) | ||
return this.$.finalize(cases); | ||
let inputValidatedCases = this.in.pipe(cases); | ||
if (defaultCase === "never" || defaultCase === "assert") { | ||
inputValidatedCases = inputValidatedCases.withMeta({ | ||
onFail: throwOnDefault | ||
}); | ||
} | ||
return this.$.finalize(inputValidatedCases); | ||
} | ||
@@ -79,0 +97,0 @@ } |
{ | ||
"name": "arktype", | ||
"description": "Optimized runtime validation for TypeScript syntax", | ||
"version": "2.1.6", | ||
"version": "2.1.7", | ||
"license": "MIT", | ||
@@ -37,4 +37,4 @@ "repository": { | ||
"dependencies": { | ||
"@ark/util": "0.44.1", | ||
"@ark/schema": "0.44.1" | ||
"@ark/util": "0.44.2", | ||
"@ark/schema": "0.44.2" | ||
}, | ||
@@ -41,0 +41,0 @@ "publishConfig": { |
262354
5074
+ Added@ark/schema@0.44.2(transitive)
+ Added@ark/util@0.44.2(transitive)
- Removed@ark/schema@0.44.1(transitive)
- Removed@ark/util@0.44.1(transitive)
Updated@ark/schema@0.44.2
Updated@ark/util@0.44.2