typia
Version:
Superfast runtime validators with only one line
142 lines (134 loc) • 4.69 kB
text/typescript
import ts from "typescript";
import { ExpressionFactory } from "../../factories/ExpressionFactory";
import { IdentifierFactory } from "../../factories/IdentifierFactory";
import { TypeFactory } from "../../factories/TypeFactory";
import { IProject } from "../../transformers/IProject";
import { StringUtil } from "../../utils/StringUtil";
import { AssertProgrammer } from "../AssertProgrammer";
import { FunctionalAssertParametersProgrammer } from "./FunctionalAssertParametersProgrammer";
import { FunctionAssertReturnProgrammer } from "./FunctionalAssertReturnProgrammer";
export namespace FunctionalAssertFunctionProgrammer {
export const write =
(project: IProject) =>
(modulo: ts.LeftHandSideExpression) =>
(equals: boolean) =>
(
expression: ts.Expression,
declaration: ts.FunctionDeclaration,
init?: ts.Expression,
): ts.CallExpression => {
const wrapper = errorFactoryWrapper(modulo)(declaration.parameters)(init);
const p = FunctionalAssertParametersProgrammer.decompose(project)(modulo)(
equals,
)(declaration.parameters, wrapper.name);
const r = FunctionAssertReturnProgrammer.decompose(project)(modulo)(
equals,
)(expression, declaration, 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,
declaration.parameters,
declaration.type,
undefined,
ts.factory.createBlock([
...p.expressions.map(ts.factory.createExpressionStatement),
ts.factory.createReturnStatement(r.value),
]),
),
),
],
true,
),
);
};
export const errorFactoryWrapper =
(modulo: ts.LeftHandSideExpression) =>
(paramters: readonly ts.ParameterDeclaration[]) =>
(
init: ts.Expression | undefined,
): {
name: string;
variable: ts.VariableStatement;
} => {
const name: string = StringUtil.escapeDuplicate(
paramters.map((p) => p.name.getText()),
)("errorFactoryWrapper");
const variable: ts.VariableStatement = ts.factory.createVariableStatement(
undefined,
ts.factory.createVariableDeclarationList(
[
ts.factory.createVariableDeclaration(
name,
undefined,
AssertProgrammer.Guardian.type(),
init ??
ts.factory.createPropertyAccessExpression(
ts.factory.createAsExpression(
modulo,
TypeFactory.keyword("any"),
),
"errorFactory",
),
),
],
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"),
),
),
]),
],
),
);
}