Skip to content

Commit

Permalink
Merge pull request #223 from samchon/v3.3
Browse files Browse the repository at this point in the history
Enhance template to pattern converter
  • Loading branch information
samchon authored Oct 3, 2022
2 parents 67d50e5 + c97e3e4 commit a93fed5
Show file tree
Hide file tree
Showing 14 changed files with 87 additions and 61 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.3.3",
"version": "3.3.4",
"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/programmers/internal/application_object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export const application_object =
properties[key] = value();
if (property.value.required === true) required.push(key);
} else {
const pattern: string = metadata_to_pattern(property.key);
const pattern: string = metadata_to_pattern(true)(property.key);
patternProperties[pattern] = value();
}
}
Expand Down
12 changes: 2 additions & 10 deletions src/programmers/internal/application_templates.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Metadata } from "../../metadata/Metadata";
import { MetadataConstant } from "../../metadata/MetadataConstant";
import { IJsonSchema } from "../../schemas/IJsonSchema";

import { application_default_string } from "./application_default_string";
import { template_to_pattern } from "./template_to_pattern";
import { metadata_to_pattern } from "./metadata_to_pattern";

/**
* @internal
Expand All @@ -18,14 +17,7 @@ export const application_templates = (
nullable: meta.nullable,
...attribute,
};
const patterns = meta.templates.map((tpl) => template_to_pattern(tpl));

// CONSIDER CONSTANT STRING
const constant: MetadataConstant | undefined = meta.constants.find(
(c) => c.type === "string",
);
if (constant) patterns.push(...(constant.values as string[]));
output.pattern = patterns.map((str) => `(${str})`).join("|");
output.pattern = metadata_to_pattern(true)(meta);

// DEFAULT VALUE
output.default = application_default_string(meta, attribute)(output);
Expand Down
7 changes: 4 additions & 3 deletions src/programmers/internal/check_dynamic_properties.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,18 +57,19 @@ const check_dynamic_property =
// GATHER CONDITIONS
if (equals === true)
add(is_regular_property(regular), ts.factory.createTrue());
for (const entry of dynamic) {
for (const entry of dynamic)
add(
ts.factory.createCallExpression(
ts.factory.createIdentifier(
`RegExp(/^${metadata_to_pattern(entry.key)}$/).test`,
`RegExp(/${metadata_to_pattern(true)(
entry.key,
)}/).test`,
),
undefined,
[key],
),
entry.expression,
);
}

//----
// FUNCTION BODY
Expand Down
2 changes: 1 addition & 1 deletion src/programmers/internal/check_template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const check_template =
ts.factory.createTrue(),
ts.factory.createCallExpression(
ts.factory.createIdentifier(
`RegExp(/^${template_to_pattern(tpl)}$/).test`,
`RegExp(/${template_to_pattern(true)(tpl)}/).test`,
),
undefined,
[input],
Expand Down
39 changes: 22 additions & 17 deletions src/programmers/internal/metadata_to_pattern.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,27 @@ import { PatternUtil } from "../../utils/PatternUtil";

import { template_to_pattern } from "./template_to_pattern";

export function metadata_to_pattern(meta: Metadata): string {
if (meta.atomics.find((type) => type === "string") !== undefined)
return "(.*)";
export const metadata_to_pattern =
(top: boolean) =>
(meta: Metadata): string => {
if (meta.atomics.find((type) => type === "string") !== undefined)
return "(.*)";

const values: string[] = ArrayUtil.flat(
meta.constants.map((c) => {
if (c.type !== "string") return c.values.map((v) => v.toString());
return c.values.map((str) => PatternUtil.escape(str));
}),
);
for (const type of meta.atomics)
if (type === "number" || type === "bigint")
values.push(PatternUtil.NUMBER);
else if (type === "boolean") values.push(PatternUtil.BOOLEAN);
for (const childTpl of meta.templates)
values.push("(" + template_to_pattern(childTpl) + ")");
const values: string[] = ArrayUtil.flat(
meta.constants.map((c) => {
if (c.type !== "string")
return c.values.map((v) => v.toString());
return c.values.map((str) => PatternUtil.escape(str));
}),
);
for (const type of meta.atomics)
if (type === "number" || type === "bigint")
values.push(PatternUtil.NUMBER);
else if (type === "boolean") values.push(PatternUtil.BOOLEAN);
for (const childTpl of meta.templates)
values.push("(" + template_to_pattern(false)(childTpl) + ")");

return values.length === 1 ? values[0]! : "(" + values.join("|") + ")";
}
const pattern: string =
values.length === 1 ? values[0]! : "(" + values.join("|") + ")";
return top ? PatternUtil.fix(pattern) : pattern;
};
10 changes: 8 additions & 2 deletions src/programmers/internal/template_to_pattern.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import { Metadata } from "../../metadata/Metadata";

import { PatternUtil } from "../../utils/PatternUtil";

import { metadata_to_pattern } from "./metadata_to_pattern";

/**
* @internal
*/
export const template_to_pattern = (template: Metadata[]) =>
template.map((meta) => metadata_to_pattern(meta)).join("");
export const template_to_pattern = (top: boolean) => (template: Metadata[]) => {
const pattern: string = template
.map((meta) => metadata_to_pattern(false)(meta))
.join("");
return top ? PatternUtil.fix(pattern) : pattern;
};
19 changes: 19 additions & 0 deletions src/utils/PatternUtil.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
export namespace PatternUtil {
export function fix(str: string): string {
const first: number = str.indexOf(STRING);
const last: number = str.lastIndexOf(STRING);
return [
first === -1 || none("(")(str.slice(0, first)) ? "^" : "",
str,
last === -1 || none(")")(str.slice(last + STRING.length))
? "$"
: "",
].join("");
}

export function escape(str: string): string {
return str
.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&")
Expand All @@ -9,3 +21,10 @@ export namespace PatternUtil {
export const BOOLEAN = "true|false";
export const STRING = "(.*)";
}

const none =
(parenthesis: string) =>
(str: string): boolean => {
for (const ch of str) if (ch !== parenthesis) return true;
return false;
};
10 changes: 5 additions & 5 deletions test/features/application/test_application_dynamic_composite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,19 @@ export const test_application_dynamic_composite = _test_application(
},
},
patternProperties: {
"-?\\d+\\.?\\d*": {
"^-?\\d+\\.?\\d*$": {
type: "number",
nullable: false,
},
"(prefix_(.*))": {
"^(prefix_(.*))": {
type: "string",
nullable: false,
},
"((.*)_postfix)": {
"((.*)_postfix)$": {
type: "string",
nullable: false,
},
"(value_-?\\d+\\.?\\d*)": {
"^(value_-?\\d+\\.?\\d*)$": {
oneOf: [
{
type: "string",
Expand All @@ -54,7 +54,7 @@ export const test_application_dynamic_composite = _test_application(
},
],
},
"(between_(.*)_and_-?\\d+\\.?\\d*)": {
"^(between_(.*)_and_-?\\d+\\.?\\d*)$": {
type: "boolean",
nullable: false,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@ export const test_application_dynamic_template = _test_application(
type: "object",
properties: {},
patternProperties: {
"(prefix_(.*))": {
"^(prefix_(.*))": {
type: "string",
nullable: false,
},
"((.*)_postfix)": {
"((.*)_postfix)$": {
type: "string",
nullable: false,
},
"(value_-?\\d+\\.?\\d*)": {
"^(value_-?\\d+\\.?\\d*)$": {
type: "number",
nullable: false,
},
"(between_(.*)_and_-?\\d+\\.?\\d*)": {
"^(between_(.*)_and_-?\\d+\\.?\\d*)$": {
type: "boolean",
nullable: false,
},
Expand Down
8 changes: 4 additions & 4 deletions test/features/application/test_application_dynamic_union.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@ export const test_application_dynamic_union = _test_application(
type: "object",
properties: {},
patternProperties: {
"-?\\d+\\.?\\d*": {
"^-?\\d+\\.?\\d*$": {
type: "string",
nullable: false,
},
"(prefix_(.*))": {
"^(prefix_(.*))": {
type: "string",
nullable: false,
},
"((.*)_postfix)": {
"((.*)_postfix)$": {
type: "string",
nullable: false,
},
"(value_between_-?\\d+\\.?\\d*_and_-?\\d+\\.?\\d*)": {
"^(value_between_-?\\d+\\.?\\d*_and_-?\\d+\\.?\\d*)$": {
type: "number",
nullable: false,
},
Expand Down
7 changes: 4 additions & 3 deletions test/features/application/test_application_tag_default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export const test_application_tag_format = _test_application(
],
},
],
pattern: "(prefix_(.*))",
pattern: "^(prefix_(.*))",
default: "prefix_A",
},
boolean_and_number_and_string: {
Expand Down Expand Up @@ -474,7 +474,7 @@ export const test_application_tag_format = _test_application(
],
},
],
pattern: "(prefix_(.*))",
pattern: "^(prefix_(.*))",
},
boolean_and_number_and_template: {
oneOf: [
Expand Down Expand Up @@ -510,7 +510,8 @@ export const test_application_tag_format = _test_application(
],
},
],
pattern: "(prefix_(.*))",
pattern:
"^(-?\\d+\\.?\\d*|true|false|(prefix_(.*)))",
default: "prefix_B",
},
{
Expand Down
12 changes: 6 additions & 6 deletions test/features/application/test_application_template_atomic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,27 @@ export const test_application_template_atomic = _test_application(
prefix: {
type: "string",
nullable: false,
pattern: "(prefix_(.*))",
pattern: "^(prefix_(.*))",
},
postfix: {
type: "string",
nullable: false,
pattern: "((.*)_postfix)",
pattern: "((.*)_postfix)$",
},
middle_string: {
type: "string",
nullable: false,
pattern: "(the_(.*)_value)",
pattern: "^(the_(.*)_value)$",
},
middle_string_empty: {
type: "string",
nullable: false,
pattern: "(the_(.*)_value)",
pattern: "^(the_(.*)_value)$",
},
middle_numeric: {
type: "string",
nullable: false,
pattern: "(the_-?\\d+\\.?\\d*_value)",
pattern: "^(the_-?\\d+\\.?\\d*_value)$",
},
middle_boolean: {
type: "string",
Expand All @@ -50,7 +50,7 @@ export const test_application_template_atomic = _test_application(
type: "string",
nullable: false,
pattern:
"(-?\\d+\\.?\\d*\\.-?\\d+\\.?\\d*\\.-?\\d+\\.?\\d*\\.-?\\d+\\.?\\d*)",
"^(-?\\d+\\.?\\d*\\.-?\\d+\\.?\\d*\\.-?\\d+\\.?\\d*\\.-?\\d+\\.?\\d*)$",
},
email: {
type: "string",
Expand Down
10 changes: 6 additions & 4 deletions test/features/application/test_application_template_union.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,28 @@ export const test_application_template_union = _test_application(
prefix: {
type: "string",
nullable: false,
pattern: "(prefix_(.*))|(prefix_-?\\d+\\.?\\d*)",
pattern:
"^((prefix_(.*))|(prefix_-?\\d+\\.?\\d*))$",
},
postfix: {
type: "string",
nullable: false,
pattern: "((.*)_postfix)|(-?\\d+\\.?\\d*_postfix)",
pattern:
"(((.*)_postfix)|(-?\\d+\\.?\\d*_postfix))$",
},
middle: {
type: "string",
nullable: false,
pattern:
"(the_-?\\d+\\.?\\d*_value)|(the_false_value)|(the_true_value)",
"^(the_false_value|the_true_value|(the_-?\\d+\\.?\\d*_value))$",
},
mixed: {
oneOf: [
{
type: "string",
nullable: false,
pattern:
"(the_-?\\d+\\.?\\d*_value)|(the_A_value)|(the_B_value)",
"^(the_A_value|the_B_value|-?\\d+\\.?\\d*|true|false|(the_-?\\d+\\.?\\d*_value))$",
},
{
type: "number",
Expand Down

0 comments on commit a93fed5

Please sign in to comment.