UNPKG

typia

Version:

Superfast runtime validators with only one line

98 lines (86 loc) 3.32 kB
import ts from "typescript"; import { IdentifierFactory } from "../../factories/IdentifierFactory"; import { MetadataCollection } from "../../factories/MetadataCollection"; import { MetadataFactory } from "../../factories/MetadataFactory"; import { StatementFactory } from "../../factories/StatementFactory"; import { TypeFactory } from "../../factories/TypeFactory"; import { Metadata } from "../../schemas/metadata/Metadata"; import { IProject } from "../../transformers/IProject"; import { TransformerError } from "../../transformers/TransformerError"; import { AssertProgrammer } from "../AssertProgrammer"; import { FunctionImporter } from "../helpers/FunctionImporter"; import { HttpMetadataUtil } from "../helpers/HttpMetadataUtil"; export namespace HttpParameterProgrammer { export const write = (project: IProject) => (modulo: ts.LeftHandSideExpression) => (type: ts.Type, name?: string): ts.ArrowFunction => { const result = MetadataFactory.analyze( project.checker, project.context, )({ escape: false, constant: true, absorb: true, validate, })(new MetadataCollection())(type); if (result.success === false) throw TransformerError.from(modulo.getText())(result.errors); const atomic = [...HttpMetadataUtil.atomics(result.data)][0]!; const importer: FunctionImporter = new FunctionImporter(modulo.getText()); const block: ts.Statement[] = [ StatementFactory.constant( "assert", AssertProgrammer.write({ ...project, options: { numeric: true, }, })(modulo)(false)(type, name), ), StatementFactory.constant( "value", ts.factory.createCallExpression(importer.use(atomic), undefined, [ ts.factory.createIdentifier("input"), ]), ), ts.factory.createReturnStatement( ts.factory.createCallExpression( ts.factory.createIdentifier("assert"), undefined, [ts.factory.createIdentifier("value")], ), ), ]; return ts.factory.createArrowFunction( undefined, undefined, [ IdentifierFactory.parameter( "input", ts.factory.createTypeReferenceNode("string"), ), ], ts.factory.createTypeReferenceNode( name ?? TypeFactory.getFullName(project.checker)(type), ), undefined, ts.factory.createBlock([...importer.declare(modulo), ...block], true), ); }; export const validate = (meta: Metadata): string[] => { const errors: string[] = []; const insert = (msg: string) => errors.push(msg); if (meta.any) insert("do not allow any type"); if (meta.isRequired() === false) insert("do not allow undefindable type"); const atomics = HttpMetadataUtil.atomics(meta); const expected: number = meta.atomics.length + meta.templates.length + meta.constants.map((c) => c.values.length).reduce((a, b) => a + b, 0); if (meta.size() !== expected || atomics.size === 0) insert("only atomic or constant types are allowed"); if (atomics.size > 1) insert("do not allow union type"); return errors; }; }