/** * The public entry point for typed JSON and typed scalar fields. * * Given a field's `documentation` plus its metadata, this returns either a Zod * expression and the imports it needs, or a reason it could not be produced. * It reads no DMMF, writes no files, and knows nothing about any emitter, so * every emitter can call it the same way. * * Two guarantees the callers depend on: * * - **With no `typedJson` config the answer is always `none`.** Generated * output is then byte-identical to today, which is the compatibility contract * for the many schemas that carry PJTG annotations for a different generator. * - **The returned expression carries no optionality and no null sentinel.** * It replaces exactly the base-schema token the emitter would otherwise have * used, and the emitter keeps applying `.optional()`, `.nullable()` and the * `JsonNullValueInput` union exactly as it does now. */ import { type ResolvedTypedJsonConfig, type TypedJsonTypeResolution } from '../config/typed-json'; import type { CustomImport } from '../parsers/zod-comments'; import { type PjtgAnnotation } from './annotation-parser'; /** An import to add to the emitted file, shaped like the `@zod.import` pipeline's. */ export type TypedJsonImport = CustomImport; export interface TypedJsonFieldContext { fieldName: string; modelName?: string; /** The field's `documentation`, straight from the DMMF. */ documentation?: string | null; /** True for a list field. The annotation then describes the ELEMENT type. */ isList?: boolean; /** Informational. Optionality is applied by the caller, never here. */ isOptional?: boolean; /** * Directory of the file being emitted, relative to the generator output root, * for example `schemas/objects` or `schemas/variants/pure`. Used to rewrite a * relative `schemaModule`. Omit it and the specifier is used as configured. */ outputSubdir?: string; /** Extension to append to relative specifiers, e.g. `.js` under NodeNext. */ importExtension?: string; } interface TypedJsonResultBase { /** Diagnostics worth logging. Never fatal. */ warnings: string[]; /** True when the field also carries any `@zod.` annotation. */ hasZodAnnotations: boolean; } /** One `[TypeName]` the field's schema depends on, and how it resolved. */ export interface TypedJsonTypeUse { typeName: string; resolution: TypedJsonTypeResolution; } export interface TypedJsonResolved extends TypedJsonResultBase { status: 'resolved'; /** * The schema for one value of the field. For a list field this is the element * schema, which is what the CRUD and pure-model emitters both want, because * each already applies its own list wrapper. */ elementExpression: string; /** The whole field's schema: `elementExpression`, wrapped in `z.array` if it is a list. */ expression: string; /** Imports the expression needs. Empty when it needs none. */ imports: TypedJsonImport[]; annotation: PjtgAnnotation; /** * Every type name the expression used, with the resolution it came from. * Feeds `buildTypedJsonNamespace`, which must declare the schema actually * used for the field rather than form a second opinion about it. */ typeUses: TypedJsonTypeUse[]; /** * True only when `expression` is rooted in `z.string()`, so a native * `@db.VarChar(n)` length constraint may still be appended to it. * * The CRUD emitter appends `.max(n)` for `@db.VarChar(n)` on every `String` * field, replaced base schema or not, and `z.enum([...]).max(8)` is a module * that throws `TypeError: z.enum(...).max is not a function` the moment it is * imported. Callers must skip that step when this is false. */ allowsStringLengthConstraints: boolean; } export interface TypedJsonNone extends TypedJsonResultBase { status: 'none'; } export interface TypedJsonSuperseded extends TypedJsonResultBase { status: 'superseded'; reason: string; annotation: PjtgAnnotation; } export interface TypedJsonUnconvertible extends TypedJsonResultBase { status: 'unconvertible'; reason: string; annotation: PjtgAnnotation | null; } export type TypedJsonResult = TypedJsonResolved | TypedJsonNone | TypedJsonSuperseded | TypedJsonUnconvertible; /** * Resolve one field's PJTG annotation to a Zod expression. * * Never throws. Returns `none` when there is nothing to do, which includes the * case of `typedJson` not being configured at all. */ export declare function resolveTypedJsonField(context: TypedJsonFieldContext, config: ResolvedTypedJsonConfig | undefined | null): TypedJsonResult; /** * Rewrite `schemaModule` so it resolves from the directory being emitted into. * * A relative specifier is read from the generator output root, because one * literal string cannot be correct in `schemas/objects`, `schemas/models` and * `schemas/variants/pure` at once. Package specifiers pass through untouched. */ export declare function resolveImportSpecifier(schemaModule: string, context: Pick): string; export {};