import { type ArkErrors, type BaseRoot, type Morph } from "@ark/schema"; import { Callable, type conform, type ErrorMessage, type ErrorType, type isDisjoint, type Key, type numericStringKeyOf, type propValueOf, type unionToTuple } from "@ark/util"; import type { distill, Out } from "./attributes.ts"; import type { type } from "./keywords/keywords.ts"; import type { Inferred } from "./methods/base.ts"; import type { BaseCompletions } from "./parser/string.ts"; import type { InternalScope } from "./scope.ts"; type MatchParserContext = { cases: Morph[]; $: unknown; input: input; checked: boolean; key: PropertyKey | null; }; declare namespace ctx { type from = ctx; type init<$, input = unknown, checked extends boolean = false> = from<{ cases: []; $: $; input: input; checked: checked; key: null; }>; type atKey = from<{ cases: ctx["cases"]; $: ctx["$"]; input: ctx["input"]; checked: ctx["checked"]; key: key; }>; } export interface MatchParser<$> extends CaseMatchParser> { in(def: type.validate): ChainableMatchParser, true>>; in(...args: [typedInput] extends [never] ? [ ErrorMessage<"in requires a definition or type argument (in('string') or in())"> ] : []): ChainableMatchParser>; in(def: type.validate): ChainableMatchParser, true>>; case: CaseParser>; at: AtParser>; } type addCasesToContext = cases extends Morph[] ? ctx.from<{ $: ctx["$"]; input: ctx["input"]; cases: [...ctx["cases"], ...cases]; checked: ctx["checked"]; key: ctx["key"]; }> : never; type addDefaultToContext> = ctx.from<{ $: ctx["$"]; input: defaultCase extends "never" ? Morph.In : ctx["input"]; 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 CaseKeyKind = "def" | "string"; type casesToMorphTuple = unionToTuple]: cases[def] extends (Morph) ? kind extends "def" ? (In: inferCaseArg) => o : (In: maybeLiftToKey) => o : never; }>>; type addCasesToParser = cases extends { default: infer defaultDef extends DefaultCase; } ? finalizeMatchParser>, defaultDef> : ChainableMatchParser>>; type inferCaseArg = _finalizeCaseArg, ctx>, ctx, endpoint>; type maybeLiftToKey = ctx["key"] extends PropertyKey ? { [k in ctx["key"]]: t; } : t; type _finalizeCaseArg = [ distill, distill ] extends [infer i, infer result] ? [ i ] extends [ctx["input"]] ? result : Extract extends never ? result : Extract : never; type CaseParser = (def: type.validate, resolve: (In: inferCaseArg) => ret) => ChainableMatchParser) => ret]>>; type validateKey = ctx["key"] extends Key ? ErrorMessage : ctx["cases"]["length"] extends 0 ? keyof ctx["input"] extends never ? key : conform : ErrorMessage; interface StringsParser { (def: cases extends validateStringCases ? cases : validateStringCases): addCasesToParser; } type validateStringCases = unknown extends ctx["input"] ? { [k in keyof cases]?: k extends "default" ? DefaultCase : (In: _finalizeCaseArg, ctx, "out">) => unknown; } & { default?: DefaultCase; } : { [k in keyof cases]?: k extends "default" ? DefaultCase : k extends stringValue ? (In: _finalizeCaseArg, ctx, "out">) => unknown : ErrorType<`${k & string} must be a possible string value`>; } & { [k in stringValue]?: unknown; } & { default?: DefaultCase; }; type stringValue = ctx["input"] extends string ? ctx["input"] : ctx["key"] extends keyof ctx["input"] ? ctx["input"][ctx["key"]] extends infer s extends string ? s : never : never; interface AtParser { (key: validateKey): ChainableMatchParser>; >(key: validateKey, cases: cases extends validateCases ? cases : errorCases): addCasesToParser; } interface ChainableMatchParser { case: CaseParser; match: CaseMatchParser; default: DefaultMethod; at: AtParser; /** @experimental */ strings: StringsParser; } export type DefaultCaseKeyword = "never" | "assert" | "reject"; type DefaultCase> = DefaultCaseKeyword | Morph; type DefaultMethod = >(def: def) => finalizeMatchParser; type validateCases = { [def in keyof cases | BaseCompletions]?: def extends "default" ? DefaultCase : def extends number ? (In: inferCaseArg<`${def}`, ctx, "out">) => unknown : def extends type.validate ? (In: inferCaseArg) => unknown : type.validate; }; type errorCases = { [def in keyof cases]?: def extends "default" ? DefaultCase : def extends number ? (In: inferCaseArg<`${def}`, ctx, "out">) => unknown : def extends type.validate ? (In: inferCaseArg) => unknown : ErrorType>; } & { [k in BaseCompletions]?: (In: inferCaseArg) => unknown; } & { default?: DefaultCase; }; export type CaseMatchParser = (def: cases extends validateCases ? cases : errorCases) => addCasesToParser; type finalizeMatchParser> = addDefaultToContext extends (infer ctx extends MatchParserContext) ? Match : never; export interface Match extends Inferred<(In: Morph.In) => Out>> { (data: data): { [i in numericStringKeyOf]: isDisjoint> extends true ? never : Morph.Out; }[numericStringKeyOf]; } export declare class InternalMatchParser extends Callable { $: InternalScope; constructor($: InternalScope); in(def?: unknown): InternalChainedMatchParser; at(key: Key, cases?: InternalCases): InternalChainedMatchParser | Match; case(when: unknown, then: Morph): InternalChainedMatchParser; } type InternalCases = Record; type InternalCaseParserFn = (cases: InternalCases) => InternalChainedMatchParser | Match; type CaseEntry = [BaseRoot, Morph] | ["default", DefaultCase]; export declare class InternalChainedMatchParser extends Callable { $: InternalScope; in: BaseRoot | undefined; protected key: Key | undefined; protected branches: BaseRoot[]; 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; } export declare const throwOnDefault: ArkErrors.Handler; export declare const chainedAtMessage = "A key matcher must be specified before the first case i.e. match.at('foo') or match.in().at('bar')"; export type chainedAtMessage = typeof chainedAtMessage; export declare const doubleAtMessage = "At most one key matcher may be specified per expression"; export type doubleAtMessage = typeof doubleAtMessage; export {};