import { BaseField, CollectionSchemaBase, Field, Operator, SchemaBase } from './dsl.js'; import { TableSchema } from './db.js'; import type { EntitySchema } from './entity.js'; import type { ImportBase } from './import-base.js'; import type { TokenSchema } from './token.js'; /** Re-export — Operator lives on the DSL level (see dsl.ts). */ export type { Operator } from './dsl.js'; /** Re-export — ImportBase lives on its own module (see import-base.ts). */ export type { ImportBase } from './import-base.js'; /** Re-export — MockDescriptor lives on its own module (see mock.ts). */ export type { MockDescriptor } from './mock.js'; /** * Reference to an existing TypeBox base schema by its import location. * Serializable metadata: the driver renders `import { name } from 'from'` * and `Type.Intersect([name, ...])` — the runtime schema is never loaded by the DSL. */ export interface ImportRef extends ImportBase { /** * Generic type arguments for the base schema (e.g. PageResult(OrderRow)). * Two forms, both local DTOs: * string — the DTO export name * DtoMessage — the DTO instance itself; the driver resolves it to its name */ args?: (string | DtoMessage)[]; } export type DtoArrayFieldDef = BaseField & { type: 'array'; jsType: 'array'; /** Element type: inline DtoField, or a reference to an existing DTO (rendered by name) */ items: DtoField | DtoMessage; }; export type DtoObjectFieldDef = BaseField & { type: 'object'; jsType: 'object'; properties: Record; }; export declare class DtoField implements SchemaBase { /** DTO 语义字段名(接口字段名),与 field.name(数据库列名)含义不同。 * 构造时未知,由 buildMessage 从 map key 反写。 */ name: string; /** 字段描述 */ description?: string; /** 所属容器(buildMessage / defineRouteData / definePageData 反写) */ schema?: CollectionSchemaBase; field: Field | DtoArrayFieldDef | DtoObjectFieldDef; pattern?: string; optional?: boolean; operator?: Operator; /** TypeBox default annotation (API contract level); falls back to field.default (DB default) */ default?: unknown; /** Optional reference to another DtoField — this field reuses the referenced field's type/constraints */ ref?: DtoField; /** Server-injection marker: this field is filled from the token at runtime * (client never sends it). Set by fromToken(); the driver renders it as an * Optional field inside a __inject base of the DTO. */ injectFrom?: TokenSchema; constructor(field: Field | DtoArrayFieldDef | DtoObjectFieldDef); setPattern(value: string): this; setDescription(value: string): this; getDescription(): string | undefined; /** True when this field wraps a DB column (picked via from()); false for inline fields. */ isColumn(): boolean; setOptional(value: boolean): this; /** Set a default value — emitted as a TypeBox schema default annotation */ setDefault(value: unknown): this; /** Reference another DtoField — this field reuses the referenced field's type/constraints */ setRef(value: DtoField): this; /** 查询比较操作符(query 方向字段)。Rule B: 查询字段恒为可选 */ setOperator(value: Operator): this; /** optional 优先于 field.optional */ isOptional(): boolean; } export declare class DtoArrayField extends DtoField { field: DtoArrayFieldDef; /** Element type: inline DtoField or a referenced DtoMessage (rendered by name). */ items(): DtoField | DtoMessage; } export declare class DtoObjectField extends DtoField { field: DtoObjectFieldDef; properties(): Record; } export declare enum DtoDirection { Input = "input", Output = "output", Query = "query", Pk = "pk" } export declare class DtoMessage implements CollectionSchemaBase { type: string; name: string; description?: string; /** 方向:输入或输出 */ direction: DtoDirection; fields: Record; /** TypeBox base schemas to intersect with at generation time (e.g. PageRequest) */ bases: ImportRef[]; constructor(name: string, direction: DtoDirection, fields: Record, description?: string); /** 引用已存在的 TypeBox base schema,例如 include({ from: '@pylonts/core', name: 'PageRequest' }) */ include(...refs: ImportRef[]): this; } export declare function dtoField(field: Field | DtoArrayFieldDef | DtoObjectFieldDef): DtoField; /** Structural check — DtoMessage instances may come from a different module copy, so instanceof is unreliable. */ export declare function isDtoMessage(v: unknown): v is DtoMessage; /** Structural check — a DtoField wraps a Field in a .field property and has no .type of its own. */ export declare function isDtoField(v: unknown): v is DtoField; /** Resolve a ref chain to its terminal DtoField (the one without .ref). * Cycles are a DSL definition error — fail loudly at render time. */ export declare function resolveDtoRefChain(f: DtoField): DtoField; /** TS type of a DtoField in generated code. * A field shared by reference (its schema is the owning DTO — utils args * like `args: { items: OrderSubmitRequest.fields.items }`) renders as an * indexed access on the DTO's generated type (the DTO owns the structure). * Array elements render by name (`ItemDto[]` — named DTO) or by recursion * (`Array` — scalar). Plain wire objects (objectField) render * their property shape (`{ key: type }`); DtoField-class containers are * rejected at build time (DTOs must not nest inline structures). * Enum → its JS name, date/datetime → string. */ export declare function dtoFieldJsType(df: DtoField): string; /** Enum JS names referenced by a DtoField, recursing into inline array/object * wrappers; DtoMessage item references stop the walk. First-occurrence order. */ export declare function dtoCollectEnumRefs(df: DtoField, out?: string[]): string[]; export declare function dtoArrayField(def: { items: DtoField | DtoMessage; } & Omit): DtoArrayField; export declare function dtoObjectField(def: { properties: Record; } & Omit): DtoObjectField; /** DTOs must not nest DtoField-class containers inline: dtoObjectField / * dtoArrayField instances (and dtoField(dtoObjectField(...))-style wraps) * have no reusable name — extract a named DTO and reference it as an array * element (dtoArrayField({ items: namedDto })), and array items must be a * named DTO or a scalar field. Plain Field containers (objectField / * arrayField — wire-format nesting) stay legal and render inline. * DtoField-class wrappers (dtoField(dtoArrayField(...))) carry the def * inside the instance's .field, so both layers are unwrapped. */ export declare function assertNoInlineContainers(dtoName: string, fields: Record): void; export declare function buildInput(name: string, fields: Record, description?: string): DtoMessage; export declare function buildOutput(name: string, fields: Record, description?: string): DtoMessage; export declare function buildQuery(name: string, fields: Record, description?: string): DtoMessage; export declare function buildPk(name: string, fields: Record, description?: string): DtoMessage; /** Field-collection source a DTO can project from: a DB table, another DTO * message (protocol fields keep their names), or an entity (which may carry * aggregate fields). */ export type DtoFieldSource = TableSchema | DtoMessage | EntitySchema; /** Project fields from a field-collection source (table, DTO message or * entity) and wrap them as DTO fields (aligned with dto.from). Shared Field * instances keep their original identity — the projection references them. */ export declare function from(source: DtoFieldSource, fields: (Field | DtoArrayFieldDef | DtoObjectFieldDef)[]): Record; /** Project fields from a TokenSchema (security/identity segments) as * server-injected DTO fields. Unlike from(), the projection does NOT share * the token's DtoField instance — each field is a NEW DtoField wrapping the * same underlying Field, referencing the token field via setRef() so the DTO * write-back (buildMessage) never mutates the token's own fields. Every * produced field is marked injectFrom (rendered inside a __inject base: * Optional in the wire schema, filled from the token at runtime). */ export declare function fromToken(token: TokenSchema, fields: DtoField[]): Record;