UNPKG

typia

Version:

Superfast runtime validators with only one line

154 lines (145 loc) 4.81 kB
import ts from "typescript"; import { ExpressionFactory } from "../../factories/ExpressionFactory"; import { IdentifierFactory } from "../../factories/IdentifierFactory"; import { ITypiaContext } from "../../transformers/ITypiaContext"; import { StringUtil } from "../../utils/StringUtil"; import { AssertProgrammer } from "../AssertProgrammer"; import { FunctionalAssertParametersProgrammer } from "./FunctionalAssertParametersProgrammer"; import { FunctionAssertReturnProgrammer } from "./FunctionalAssertReturnProgrammer"; export namespace FunctionalAssertFunctionProgrammer { export interface IConfig { equals: boolean; } export interface IProps { context: ITypiaContext; modulo: ts.LeftHandSideExpression; config: IConfig; declaration: ts.FunctionDeclaration; expression: ts.Expression; init?: ts.Expression | undefined; } export const write = (props: IProps): ts.CallExpression => { const wrapper = errorFactoryWrapper({ context: props.context, parameters: props.declaration.parameters, init: props.init, }); const p = FunctionalAssertParametersProgrammer.decompose({ context: props.context, modulo: props.modulo, config: props.config, parameters: props.declaration.parameters, wrapper: wrapper.name, }); const r = FunctionAssertReturnProgrammer.decompose({ context: props.context, modulo: props.modulo, config: props.config, expression: props.expression, declaration: props.declaration, wrapper: wrapper.name, }); return ExpressionFactory.selfCall( ts.factory.createBlock( [ wrapper.variable, ...p.functions, ...r.functions, ts.factory.createReturnStatement( ts.factory.createArrowFunction( r.async ? [ts.factory.createModifier(ts.SyntaxKind.AsyncKeyword)] : undefined, undefined, props.declaration.parameters, props.declaration.type, undefined, ts.factory.createBlock([ ...p.expressions.map(ts.factory.createExpressionStatement), ts.factory.createReturnStatement(r.value), ]), ), ), ], true, ), ); }; export const errorFactoryWrapper = (props: { context: ITypiaContext; parameters: readonly ts.ParameterDeclaration[]; init: ts.Expression | undefined; }): { name: string; variable: ts.VariableStatement; } => { const name: string = StringUtil.escapeDuplicate({ keep: props.parameters.map((p) => p.name.getText()), input: "errorFactoryWrapper", }); const variable: ts.VariableStatement = ts.factory.createVariableStatement( undefined, ts.factory.createVariableDeclarationList( [ ts.factory.createVariableDeclaration( name, undefined, AssertProgrammer.Guardian.type(props.context), props.init ?? props.context.importer.internal( "functionalTypeGuardErrorFactory", ), ), ], ts.NodeFlags.Const, ), ); return { name, variable }; }; export const hookPath = (props: { wrapper: string; replacer: string; }): ts.ArrowFunction => ts.factory.createArrowFunction( undefined, undefined, [IdentifierFactory.parameter("p")], undefined, undefined, ts.factory.createCallExpression( ts.factory.createIdentifier(props.wrapper), undefined, [ ts.factory.createObjectLiteralExpression([ ts.factory.createSpreadAssignment(ts.factory.createIdentifier("p")), ts.factory.createPropertyAssignment( "path", ts.factory.createConditionalExpression( ts.factory.createPropertyAccessExpression( ts.factory.createIdentifier("p"), "path", ), undefined, ts.factory.createCallExpression( ts.factory.createPropertyAccessExpression( ts.factory.createPropertyAccessExpression( ts.factory.createIdentifier("p"), "path", ), "replace", ), undefined, [ ts.factory.createStringLiteral("$input"), ts.factory.createStringLiteral(props.replacer), ], ), undefined, ts.factory.createIdentifier("undefined"), ), ), ]), ], ), ); }