Skip to content

Commit

Permalink
Merge pull request #145 from samchon/v3.0
Browse files Browse the repository at this point in the history
Close #142, Close #143 and Fix #144
  • Loading branch information
samchon authored Jul 5, 2022
2 parents 89c94b5 + c790c9f commit 520b042
Show file tree
Hide file tree
Showing 40 changed files with 509 additions and 138 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "typescript-json",
"version": "3.0.9",
"version": "3.0.10",
"description": "Runtime type checkers and 5x faster JSON.stringify() function",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion src/TypeGuardError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export class TypeGuardError extends Error {
// MESSAGE CONSTRUCTION
super(
props.message ||
`Error on TSON.${props.method}(): invalid type${
`Error on ${props.method}(): invalid type${
props.path ? ` on ${props.path}` : ""
}, expect to be ${props.expected}`,
);
Expand Down
33 changes: 20 additions & 13 deletions src/factories/ExpressionFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,26 @@ export namespace ExpressionFactory {
export function isObject(
input: ts.Expression,
nullChecked: boolean,
checkArray?: boolean,
): ts.Expression {
const equality = ts.factory.createStrictEquality(
ts.factory.createStringLiteral("object"),
ts.factory.createTypeOfExpression(input),
);
return nullChecked === true
? equality
: ts.factory.createLogicalAnd(
ts.factory.createStrictInequality(
ts.factory.createNull(),
input,
),
equality,
);
const conditions: ts.Expression[] = [
ts.factory.createStrictEquality(
ts.factory.createStringLiteral("object"),
ts.factory.createTypeOfExpression(input),
),
];
if (nullChecked === true)
conditions.push(
ts.factory.createStrictInequality(
ts.factory.createNull(),
input,
),
);
if (checkArray === true)
conditions.push(ts.factory.createLogicalNot(isArray(input)));

return conditions.length === 1
? conditions[0]!
: conditions.reduce((x, y) => ts.factory.createLogicalAnd(x, y));
}
}
2 changes: 1 addition & 1 deletion src/factories/IdentifierFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ export namespace IdentifierFactory {
export function postfix(str: string): string {
return Escaper.variable(str)
? `".${str}"`
: `"[${str.split('"').join('\\"')}]"`;
: `"[${JSON.stringify(str).split('"').join('\\"')}]"`;
}
}
4 changes: 2 additions & 2 deletions src/functional/$number.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { TypeGuardError } from "../TypeGuardError";
export function $number(value: number): number {
if (!isFinite(value))
throw new TypeGuardError({
method: "stringify",
method: "TSON.stringify",
expected: "number",
value,
message: "Error on TSON.stringify(): infinite number.",
});
else if (isNaN(value))
throw new TypeGuardError({
method: "stringify",
method: "TSON.stringify",
expected: "number",
value,
message: "Error on TSON.stringify(): not a valid number.",
Expand Down
4 changes: 2 additions & 2 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export namespace assertType {
): boolean {
if (matched === false && exceptionable === true)
throw new TypeGuardError({
method: "assertType",
method: "TSON.assertType",
...closure(),
});
return matched;
Expand Down Expand Up @@ -145,7 +145,7 @@ export module stringify {
): void {
throw new TypeGuardError({
...props,
method: "stringify",
method: "TSON.stringify",
});
}
}
Expand Down
178 changes: 89 additions & 89 deletions src/programmers/AssertProgrammer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,100 +7,100 @@ import { IProject } from "../transformers/IProject";
import { IdentifierFactory } from "../factories/IdentifierFactory";

export namespace AssertProgrammer {
export function generate(
project: IProject,
modulo: ts.LeftHandSideExpression,
type: ts.Type,
) {
return ts.factory.createArrowFunction(
undefined,
undefined,
[
ts.factory.createParameterDeclaration(
undefined,
undefined,
undefined,
ValueFactory.INPUT(),
),
],
undefined,
undefined,
ts.factory.createBlock([
ts.factory.createExpressionStatement(
ts.factory.createCallExpression(
CheckerProgrammer.generate(
project,
{
functors: "$ao",
unioners: "$au",
trace: true,
combiner: combine(),
},
() => [
StatementFactory.variable(
ts.NodeFlags.Const,
"$pred",
IdentifierFactory.join(modulo, "predicate"),
),
],
)(type),
export const generate =
(project: IProject, modulo: ts.LeftHandSideExpression) =>
(type: ts.Type) =>
ts.factory.createArrowFunction(
undefined,
undefined,
[
ts.factory.createParameterDeclaration(
undefined,
undefined,
[ValueFactory.INPUT()],
undefined,
ValueFactory.INPUT(),
),
),
ts.factory.createReturnStatement(ValueFactory.INPUT()),
]),
);
}

function combine(): CheckerProgrammer.IConfig.Combiner {
return (explore: CheckerProgrammer.IExplore) => {
const combiner = IsProgrammer.CONFIG().combiner;
if (explore.tracable === false && explore.from !== "top")
return combiner(explore);
],
undefined,
undefined,
ts.factory.createBlock([
ts.factory.createExpressionStatement(
ts.factory.createCallExpression(
CheckerProgrammer.generate(
project,
{
functors: "$ao",
unioners: "$au",
trace: true,
combiner: combine(),
},
() => [
StatementFactory.variable(
ts.NodeFlags.Const,
"$pred",
IdentifierFactory.join(
modulo,
"predicate",
),
),
],
)(type),
undefined,
[ValueFactory.INPUT()],
),
),
ts.factory.createReturnStatement(ValueFactory.INPUT()),
]),
);
}

const path = explore.postfix ? `path + ${explore.postfix}` : "path";
function combine(): CheckerProgrammer.IConfig.Combiner {
return (explore: CheckerProgrammer.IExplore) => {
const combiner = IsProgrammer.CONFIG().combiner;
if (explore.tracable === false && explore.from !== "top")
return combiner(explore);

return (logic) => (input, expressions, expected) =>
ts.factory.createCallExpression(
ts.factory.createIdentifier("$pred"),
[],
[
combiner(explore)(logic)(input, expressions, expected),
explore.source === "top"
? ts.factory.createTrue()
: ts.factory.createIdentifier("exceptionable"),
create_throw_function(path, expected, input),
],
);
};
}
const path = explore.postfix ? `path + ${explore.postfix}` : "path";

function create_throw_function(
path: string,
expected: string,
value: ts.Expression,
): ts.ArrowFunction {
return ts.factory.createArrowFunction(
undefined,
undefined,
[],
undefined,
undefined,
ts.factory.createObjectLiteralExpression(
return (logic) => (input, expressions, expected) =>
ts.factory.createCallExpression(
ts.factory.createIdentifier("$pred"),
[],
[
ts.factory.createPropertyAssignment(
"path",
ts.factory.createIdentifier(path),
),
ts.factory.createPropertyAssignment(
"expected",
ts.factory.createStringLiteral(expected),
),
ts.factory.createPropertyAssignment("value", value),
combiner(explore)(logic)(input, expressions, expected),
explore.source === "top"
? ts.factory.createTrue()
: ts.factory.createIdentifier("exceptionable"),
create_throw_function(path, expected, input),
],
true,
),
);
}
);
};
}

function create_throw_function(
path: string,
expected: string,
value: ts.Expression,
): ts.ArrowFunction {
return ts.factory.createArrowFunction(
undefined,
undefined,
[],
undefined,
undefined,
ts.factory.createObjectLiteralExpression(
[
ts.factory.createPropertyAssignment(
"path",
ts.factory.createIdentifier(path),
),
ts.factory.createPropertyAssignment(
"expected",
ts.factory.createStringLiteral(expected),
),
ts.factory.createPropertyAssignment("value", value),
],
true,
),
);
}
6 changes: 5 additions & 1 deletion src/programmers/CheckerProgrammer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,11 @@ export namespace CheckerProgrammer {
if (meta.objects.length > 0)
binaries.push(
ts.factory.createLogicalAnd(
ExpressionFactory.isObject(input, true),
ExpressionFactory.isObject(
input,
true,
meta.arrays.length === 0,
),
explore_objects(config)(input, meta, {
...explore,
from: "object",
Expand Down
2 changes: 1 addition & 1 deletion src/transformers/features/AssertTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export namespace AssertTransformer {

// DO TRANSFORM
return ts.factory.createCallExpression(
AssertProgrammer.generate(project, modulo, type),
AssertProgrammer.generate(project, modulo)(type),
undefined,
[expression.arguments[0]!],
);
Expand Down
2 changes: 1 addition & 1 deletion test/features/assert/test_assert_array_recursive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const test_assert_array_recursive = _test_assert(
},
(input) => {
input.created_at = [] as any;
return "$input.created_at.time";
return "$input.created_at";
},
(input) => {
input.children[0].children[0].sequence = "number" as any;
Expand Down
32 changes: 14 additions & 18 deletions test/features/assert/test_assert_functional_array_union.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,18 @@ export const test_assert_functional_array_union = _test_assert_for_of(
"functional union array",
FunctionalArrayUnion.generate,
(input) => TSON.assertType(input),
// [
// (input) => {
// input[0]![0] = null!;
// return "$input[0]";
// },
// (input) => {
// input[0]![0] = undefined!;
// return "$input[0]";
// },
// (input) => {
// input[0]![0] = {} as any;
// return "$input[0]";
// },
// (input) => {
// input[0]![0] = [] as any;
// return "$input[0]";
// },
// ],
[
(input) => {
input[0] = undefined!;
return "$input";
},
(input) => {
input[0] = {} as any;
return "$input";
},
(input) => {
input[0] = [] as any;
return "$input";
},
],
);
10 changes: 10 additions & 0 deletions test/features/assert/test_assert_functional_object_union.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,14 @@ export const test_assert_functional_object_union = _test_assert_for_of(
"functional union object",
FunctionalObjectUnion.generate,
(input) => TSON.assertType(input),
[
(input) => {
if ((input as any).length) {
(input as any).length = {} as any;
return "$input";
}
(input as any).distance = [] as any;
return "$input";
},
],
);
Loading

0 comments on commit 520b042

Please sign in to comment.