UNPKG

typia

Version:

Superfast runtime validators with only one line

212 lines (199 loc) • 6.01 kB
import ts from "typescript"; import { ExpressionFactory } from "../../factories/ExpressionFactory"; import { IdentifierFactory } from "../../factories/IdentifierFactory"; import { StatementFactory } from "../../factories/StatementFactory"; import { IProject } from "../../transformers/IProject"; import { FunctionImporter } from "../helpers/FunctionImporter"; import { IExpressionEntry } from "../helpers/IExpressionEntry"; import { check_dynamic_key } from "./check_dynamic_key"; import { check_everything } from "./check_everything"; import { check_object } from "./check_object"; /** * @internal */ export const check_dynamic_properties = (props: check_object.IProps) => (project: IProject) => (importer: FunctionImporter) => ( input: ts.Expression, regular: IExpressionEntry<ts.Expression>[], dynamic: IExpressionEntry<ts.Expression>[], ): ts.Expression => { const length = IdentifierFactory.access( ts.factory.createCallExpression( ts.factory.createIdentifier("Object.keys"), undefined, [input], ), )("length"); const left: ts.Expression | null = props.equals === true && dynamic.length === 0 ? props.undefined === true || regular.every((r) => r.meta.isRequired()) ? ts.factory.createStrictEquality( ExpressionFactory.number( regular.filter((r) => r.meta.isRequired()).length, ), length, ) : ts.factory.createCallExpression( importer.use("is_between"), [], [ length, ExpressionFactory.number( regular.filter((r) => r.meta.isRequired()).length, ), ExpressionFactory.number(regular.length), ], ) : null; if ( props.undefined === false && left !== null && regular.every((r) => r.meta.isRequired()) ) return left; const criteria = props.entries ? ts.factory.createCallExpression(props.entries, undefined, [ ts.factory.createCallExpression( ts.factory.createIdentifier("Object.keys"), undefined, [input], ), check_dynamic_property(props)(project)(importer)( input, regular, dynamic, ), ]) : ts.factory.createCallExpression( IdentifierFactory.access( ts.factory.createCallExpression( ts.factory.createIdentifier("Object.keys"), undefined, [input], ), )(props.assert ? "every" : "map"), undefined, [ check_dynamic_property(props)(project)(importer)( input, regular, dynamic, ), ], ); const right: ts.Expression = (props.halt || ((elem) => elem))( props.assert ? criteria : check_everything(criteria), ); return left ? (props.undefined ? ts.factory.createLogicalOr : ts.factory.createLogicalAnd)(left, right) : right; }; const check_dynamic_property = (props: check_object.IProps) => (project: IProject) => (importer: FunctionImporter) => ( input: ts.Expression, regular: IExpressionEntry<ts.Expression>[], dynamic: IExpressionEntry<ts.Expression>[], ) => { //---- // IF CONDITIONS //---- // PREPARE ASSETS const key = ts.factory.createIdentifier("key"); const value = ts.factory.createIdentifier("value"); const statements: ts.Statement[] = []; const add = (exp: ts.Expression, output: ts.Expression) => statements.push( ts.factory.createIfStatement( exp, ts.factory.createReturnStatement(output), ), ); const broken = { value: false }; // GATHER CONDITIONS if (regular.length) add(is_regular_property(regular), props.positive); statements.push( StatementFactory.constant( "value", ts.factory.createElementAccessExpression(input, key), ), ); if (props.undefined === true) add( ts.factory.createStrictEquality( ts.factory.createIdentifier("undefined"), value, ), props.positive, ); for (const entry of dynamic) { const condition: ts.Expression = check_dynamic_key(project)(importer)( key, entry.key, ); if (condition.kind === ts.SyntaxKind.TrueKeyword) { statements.push(ts.factory.createReturnStatement(entry.expression)); broken.value = true; break; } else add(condition, entry.expression); } //---- // FUNCTION BODY //---- // CLOSURE BLOCK const block: ts.Block = ts.factory.createBlock( [ ...statements, ...(broken.value ? [] : [ ts.factory.createReturnStatement( props.equals === true ? props.superfluous(value) : props.positive, ), ]), ], true, ); // RETURNS return ts.factory.createArrowFunction( undefined, undefined, [IdentifierFactory.parameter("key")], undefined, undefined, block, ); }; const is_regular_property = (regular: IExpressionEntry[]) => ts.factory.createCallExpression( IdentifierFactory.access( ts.factory.createArrayLiteralExpression( regular.map((entry) => ts.factory.createStringLiteral(entry.key.getSoleLiteral()!), ), ), )("some"), undefined, [ ts.factory.createArrowFunction( undefined, undefined, [IdentifierFactory.parameter("prop")], undefined, undefined, ts.factory.createStrictEquality( ts.factory.createIdentifier("key"), ts.factory.createIdentifier("prop"), ), ), ], );