UNPKG

typia

Version:

Superfast runtime validators with only one line

134 lines (123 loc) 4.57 kB
import { ILlmSchema } from "@samchon/openapi"; import { LlmSchemaComposer } from "@samchon/openapi/lib/composers/LlmSchemaComposer"; import ts from "typescript"; import { MetadataCollection } from "../../factories/MetadataCollection"; import { MetadataFactory } from "../../factories/MetadataFactory"; import { Metadata } from "../../schemas/metadata/Metadata"; import { MetadataObject } from "../../schemas/metadata/MetadataObject"; import { ITypiaContext } from "../../transformers/ITypiaContext"; import { TransformerError } from "../../transformers/TransformerError"; import { ValidationPipe } from "../../typings/ValidationPipe"; export namespace LlmModelPredicator { export const getConfig = (props: { context: ITypiaContext; method: string; model: ILlmSchema.Model; node: ts.TypeNode | undefined; }): | Partial< ILlmSchema.ModelConfig[ILlmSchema.Model] & { equals: boolean; } > | undefined => { if (props.node === undefined) return undefined; const type: ts.Type = props.context.checker.getTypeFromTypeNode(props.node); const collection: MetadataCollection = new MetadataCollection(); const result: ValidationPipe<Metadata, MetadataFactory.IError> = MetadataFactory.analyze({ checker: props.context.checker, transformer: props.context.transformer, options: { absorb: true, escape: false, constant: true, functional: false, }, collection, type, }); if (result.success === false) throw new TransformerError({ code: `typia.llm.${props.method}`, message: `Failed to analyze generic argument "Config".`, }); const meta: Metadata = result.data; if ( meta.size() !== 1 || meta.objects.length !== 1 || meta.nullable === true || meta.isRequired() === false ) throw new TransformerError({ code: `typia.llm.${props.method}`, message: `Invalid generic argument "Config". It must be a literal object type.`, }); const obj: MetadataObject = meta.objects[0]!; if (obj.type.properties.some((p) => p.key.isSoleLiteral() === false)) throw new TransformerError({ code: `typia.llm.${props.method}`, message: `Invalid generic argument "Config". It must be a literal object type. Do not allow dynamic properties.`, }); else if ( obj.type.properties.some( (p) => p.value.size() !== 1 || p.value.constants.length !== 1 || p.value.nullable === true || p.value.isRequired() === false, ) ) throw new TransformerError({ code: `typia.llm.${props.method}`, message: `Invalid generic argument "Config". It must be a literal object type. Do not allow variable type.`, }); const config: Partial<ILlmSchema.ModelConfig[ILlmSchema.Model]> = {}; for (const prop of obj.type.properties) { const key: string = prop.key.getSoleLiteral()!; const value: boolean | bigint | number | string = prop.value.constants[0]!.values[0]!.value; if (typeof value === "bigint") throw new TransformerError({ code: `typia.llm.${props.method}`, message: `Invalid generic argument "Config". It must be a literal object type. Do not allow bigint.`, }); (config as any)[key] = value; } return config; }; export const getModel = (props: { checker: ts.TypeChecker; method: string; node: ts.TypeNode | undefined; }): ILlmSchema.Model => { if (props.node === undefined) throw new TransformerError({ code: `typia.llm.${props.method}`, message: `generic argument "Model" must be specified.`, }); // CHECK LITERAL TYPE const type: ts.Type = props.checker.getTypeFromTypeNode(props.node); if ( !type.isLiteral() && (type.getFlags() & ts.TypeFlags.BooleanLiteral) === 0 ) throw new TransformerError({ code: `typia.llm.${props.method}`, message: `generic argument "Model" must be constant.`, }); // GET VALUE AND VALIDATE IT const value = type.isLiteral() ? type.value : props.checker.typeToString(type); if ( typeof value !== "string" || LlmSchemaComposer.defaultConfig(value as "3.0") === undefined ) throw new TransformerError({ code: "typia.llm.schema", message: `invalid value on generic argument "Model".`, }); return value as ILlmSchema.Model; }; }