import type {
evaluate,
List,
NumberLiteral,
Thunk
} from "../../../dev/utils/src/main.js"
import type {
IndexedPropInput,
NonVariadicIndexMatcherSource,
VariadicIndexMatcherSource
} from "./indexed.js"
import type { PropValueInput } from "./named.js"
import type { NamedPropsInput, PropsInput, PropsInputTuple } from "./props.js"
import type { inferTypeInput, TypeInput, TypeNode } from "./type.js"
export type inferPropsInput =
input extends PropsInputTuple
? inferIndexed>
: input extends NamedPropsInput
? inferNamedProps
: never
type inferIndexed<
indexed extends IndexedPropInput[],
result = unknown
> = indexed extends [
infer entry extends IndexedPropInput,
...infer tail extends IndexedPropInput[]
]
? inferIndexed<
tail,
entry["key"] extends { readonly regex: VariadicIndexMatcherSource }
? result extends List
? [...result, ...inferTypeInput[]]
: never
: entry["key"] extends {
readonly regex: NonVariadicIndexMatcherSource
}
? inferTypeInput[]
: Record<
Extract, PropertyKey>,
inferTypeInput
>
>
: result
type inferNamedProps<
named extends NamedPropsInput,
indexed extends IndexedPropInput[]
> = [named, indexed[0]["key"]] extends
| [TupleLengthProps, unknown]
| [unknown, { readonly regex: VariadicIndexMatcherSource }]
? inferNonVariadicTupleProps &
inferObjectLiteralProps<
Omit
>
: inferObjectLiteralProps
type inferObjectLiteralProps = {} extends named
? unknown
: evaluate<
{
[k in requiredKeyOf]: inferPropValue
} & {
[k in optionalKeyOf]?: inferPropValue
}
>
type inferPropValue = value extends Thunk<
infer ret
>
? inferResolvedPropValue
: inferResolvedPropValue
type inferResolvedPropValue = value extends TypeNode
? t
: inferTypeInput
type stringifiedNumericKeyOf = `${Extract}`
type inferNonVariadicTupleProps<
named extends NamedPropsInput,
result extends unknown[] = []
> = `${result["length"]}` extends stringifiedNumericKeyOf
? inferNonVariadicTupleProps<
named,
[...result, inferPropValue]
>
: result
type TupleLengthProps = {
readonly length: {
readonly prerequisite: true
readonly value: { readonly basis: readonly ["===", length] }
}
}
type requiredKeyOf = Exclude<
keyof input,
optionalKeyOf
>
type optionalKeyOf = {
[k in keyof input]: input[k]["optional"] extends true ? k : never
}[keyof input]