import type { PslDiagnostic } from '@prisma-next/framework-components/psl-ast'; import type { Result } from '@prisma-next/utils/result'; import type { Simplify, UnionToIntersection } from '@prisma-next/utils/types'; import type { SourceFile } from '../source-file'; import type { FieldSymbol, ModelSymbol } from '../symbol-table'; import type { ExpressionAst } from '../syntax/ast/expressions'; export type AttributeLevel = 'field' | 'model' | 'block'; export interface ArgType { readonly kind: string; readonly label: string; // phantom carrier for `T`; never read at runtime. readonly _out?: T; parse(arg: ExpressionAst, ctx: InterpretCtx): Result; } export interface InterpretCtx { readonly level: AttributeLevel; readonly sourceId: string; readonly sourceFile: SourceFile; readonly selfModel: ModelSymbol; resolveReferencedModel(): ModelSymbol | undefined; readonly field?: FieldSymbol; } export interface OptionalArgType extends ArgType { // the engine detects optionality by checking for this marker (`'optional' in param`). readonly optional: true; readonly hasDefault: boolean; readonly defaultValue?: T; } export type Param = ArgType; export interface PositionalParam { readonly key: string; readonly type: Param; } export interface AttributeSpec { readonly level: AttributeLevel; readonly name: string; readonly positional: readonly PositionalParam[]; readonly named: Readonly>>; readonly refine?: (parsed: Out, ctx: InterpretCtx) => readonly PslDiagnostic[]; } export type OutOf

= P extends ArgType ? T : never; export type NamedOut>> = Simplify< { [K in keyof N as N[K] extends OptionalArgType ? never : K]: OutOf } & { [K in keyof N as N[K] extends OptionalArgType ? K : never]?: OutOf; } >; type PosEntryObject = E['type'] extends OptionalArgType ? { [K in E['key']]?: OutOf } : { [K in E['key']]: OutOf }; export type PosOut = Simplify< UnionToIntersection<{ [I in keyof Pos]: PosEntryObject }[number]> >; export type AttributeOut< Pos extends readonly PositionalParam[], Named extends Record>, > = Simplify & NamedOut>; // `S` is unconstrained on purpose: `refine` makes `Out` contravariant, so a bound like `S extends AttributeSpec` would reject every spec that uses `refine`. export type InferAttr = S extends AttributeSpec ? Out : never;