typia
Version:
Superfast runtime validators with only one line
108 lines (99 loc) • 3.33 kB
text/typescript
import ts from "typescript";
import { ExpressionFactory } from "../../factories/ExpressionFactory";
import { MetadataAtomic } from "../../schemas/metadata/MetadataAtomic";
import { IProject } from "../../transformers/IProject";
import { ICheckEntry } from "../helpers/ICheckEntry";
import { OptionPredicator } from "../helpers/OptionPredicator";
/**
* @internal
*/
export const check_number =
(project: IProject, numeric: boolean) =>
(atomic: MetadataAtomic) =>
(input: ts.Expression): ICheckEntry => {
const base = ts.factory.createStrictEquality(
ts.factory.createStringLiteral("number"),
ts.factory.createTypeOfExpression(input),
);
const addition: ts.Expression | null =
numeric === true
? OptionPredicator.finite(project.options)
? ts.factory.createCallExpression(
ts.factory.createIdentifier("Number.isFinite"),
undefined,
[input],
)
: OptionPredicator.numeric(project.options)
? ts.factory.createLogicalNot(
ts.factory.createCallExpression(
ts.factory.createIdentifier("Number.isNaN"),
undefined,
[input],
),
)
: null
: null;
const conditions: ICheckEntry.ICondition[][] =
check_numeric_type_tags(project)(atomic)(addition)(input);
return {
expected: atomic.getName(),
expression:
addition !== null && conditions.length === 0
? ts.factory.createLogicalAnd(base, addition)
: base,
conditions,
};
};
/**
* @internal
*/
const check_numeric_type_tags =
(project: IProject) =>
(atomic: MetadataAtomic) =>
(addition: ts.Expression | null) =>
(input: ts.Expression): ICheckEntry.ICondition[][] =>
atomic.tags
.map((row) => row.filter((tag) => !!tag.validate))
.filter((row) => !!row.length)
.map((row) => [
...(addition === null
? []
: row.some(
(tag) =>
tag.kind === "type" &&
(tag.value === "int32" ||
tag.value === "uint32" ||
tag.value === "int64" ||
tag.value === "uint64" ||
tag.value === "float"),
) ||
row.some(
(tag) =>
tag.kind === "multipleOf" && typeof tag.value === "number",
) ||
(row.some(
(tag) =>
(tag.kind === "minimum" || tag.kind === "exclusiveMinimum") &&
typeof tag.value === "number",
) &&
row.some(
(tag) =>
(tag.kind === "maximum" ||
tag.kind === "exclusiveMaximum") &&
typeof tag.value === "number",
))
? []
: [
{
expected: "number",
expression: addition!,
},
]),
...row.map((tag) => ({
expected: `number & ${tag.name}`,
expression: (
tag.predicate ??
ExpressionFactory.transpile(project.context)(tag.validate!)
)(input),
})),
]);