Skip to content

Commit 6f279f5

Browse files
committed
New type tag Default.
A special type tag for only json schema generation.
1 parent 19af539 commit 6f279f5

File tree

261 files changed

+23835
-7852
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

261 files changed

+23835
-7852
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "typia",
3-
"version": "5.1.2",
3+
"version": "5.1.3",
44
"description": "Superfast runtime validators with only one line",
55
"main": "lib/index.js",
66
"typings": "lib/index.d.ts",

packages/typescript-json/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "typescript-json",
3-
"version": "5.1.2",
3+
"version": "5.1.3",
44
"description": "Superfast runtime validators with only one line",
55
"main": "lib/index.js",
66
"typings": "lib/index.d.ts",
@@ -72,7 +72,7 @@
7272
},
7373
"homepage": "https://typia.io",
7474
"dependencies": {
75-
"typia": "5.1.2"
75+
"typia": "5.1.3"
7676
},
7777
"peerDependencies": {
7878
"typescript": ">= 4.8.0"

src/factories/MetadataTypeTagFactory.ts

+24-12
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { MetadataFactory } from "./MetadataFactory";
88
export namespace MetadataTypeTagFactory {
99
export const analyze =
1010
(errors: MetadataFactory.IError[]) =>
11-
(type: "bigint" | "number" | "string" | "array") =>
11+
(type: "boolean" | "bigint" | "number" | "string" | "array") =>
1212
(
1313
objects: MetadataObject[],
1414
explore: MetadataFactory.IExplore,
@@ -50,9 +50,9 @@ export namespace MetadataTypeTagFactory {
5050
const statics: string[] = tag.properties
5151
.map((p) => p.key.getSoleLiteral()!)
5252
.filter((str) => str !== null);
53-
if (FIELDS.some((f) => !statics.includes(f)))
53+
if (ESSENTIAL_FIELDS.some((f) => !statics.includes(f)))
5454
return report(null)(
55-
`must have four properties - ${FIELDS.map(
55+
`must have at least three properties - ${ESSENTIAL_FIELDS.map(
5656
(str) => `'${str}'`,
5757
).join(", ")}`,
5858
);
@@ -103,7 +103,7 @@ export namespace MetadataTypeTagFactory {
103103

104104
export const validate =
105105
(report: (property: string | null) => (msg: string) => false) =>
106-
(type: "bigint" | "number" | "string" | "array") =>
106+
(type: "boolean" | "bigint" | "number" | "string" | "array") =>
107107
(tagList: IMetadataTypeTag[]): boolean => {
108108
let success: boolean = true;
109109
for (const tag of tagList)
@@ -149,14 +149,15 @@ export namespace MetadataTypeTagFactory {
149149
value.constants[0]!.values.length !== value.size() ||
150150
value.constants[0]!.values.some(
151151
(v) =>
152+
v !== "boolean" &&
152153
v !== "bigint" &&
153154
v !== "number" &&
154155
v !== "string" &&
155156
v !== "array",
156157
))
157158
)
158159
return report(key)(
159-
`must be one of 'bigint', 'number', 'string', 'array'`,
160+
`must be one of 'boolean', 'bigint', 'number', 'string', 'array'`,
160161
);
161162
else if (
162163
// KIND
@@ -184,13 +185,22 @@ export namespace MetadataTypeTagFactory {
184185
//----
185186
// VALIDATE
186187
//----
188+
// UNDEFINED CASE
189+
if (
190+
value.size() === 0 &&
191+
value.isRequired() === false &&
192+
value.nullable === false
193+
)
194+
return true;
195+
187196
// STRING CASE
188-
const single: boolean =
197+
if (
189198
value.size() === 1 &&
190199
value.constants.length === 1 &&
191200
value.constants[0]!.type === "string" &&
192-
value.constants[0]!.values.length === 1;
193-
if (single === true) return true;
201+
(value.constants[0]!.values.length === 1) === true
202+
)
203+
return true;
194204

195205
// RECORD<TARGET, STRING>
196206
const target: string[] | undefined =
@@ -199,7 +209,7 @@ export namespace MetadataTypeTagFactory {
199209
.filter((str) => str !== null) as string[] | undefined;
200210
if (target === undefined)
201211
return report("target")(
202-
`must be one of 'bigint', 'number', 'string', 'array'`,
212+
`must be one of 'boolean', 'bigint', 'number', 'string', 'array'`,
203213
);
204214
const variadic: boolean =
205215
value.size() === 1 &&
@@ -242,8 +252,9 @@ export namespace MetadataTypeTagFactory {
242252
if (exclusive === null) return null;
243253

244254
const validate: Record<string, string> = (() => {
245-
const validate = find("validate")!.value;
246-
if (validate.constants.length)
255+
const validate = find("validate")?.value;
256+
if (!validate || validate.size() === 0) return {};
257+
else if (validate.constants.length)
247258
return Object.fromEntries(
248259
target.map((t) => [
249260
t,
@@ -310,4 +321,5 @@ interface ITypeTag {
310321
exclusive: boolean | string[];
311322
}
312323

313-
const FIELDS = ["target", "kind", "value", "validate"];
324+
const ESSENTIAL_FIELDS = ["target", "kind", "value"];
325+
const FIELDS = [...ESSENTIAL_FIELDS, "validate", "exclusive"];

src/factories/internal/metadata/emend_metadata_atomics.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,17 @@ export const emend_metadata_atomics = (meta: Metadata) => {
1818
(c) => c.type === "boolean",
1919
);
2020
if (index !== -1 && meta.constants[index]!.values.length === 2) {
21-
meta.constants.splice(index, 1);
21+
const temp = meta.constants.splice(index, 1)[0]!;
2222
ArrayUtil.take(
2323
meta.atomics,
2424
(a) => a.type === "boolean",
2525
() =>
2626
MetadataAtomic.create({
2727
type: "boolean" as const,
28-
tags: [],
28+
tags: temp.tags ?? [],
2929
}),
3030
);
31+
temp.tags = undefined;
3132
}
3233
}
3334

src/factories/internal/metadata/iterate_metadata_intersection.ts

+79-17
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import ts from "typescript";
22

3+
import { IMetadataConstant } from "../../../schemas/metadata/IMetadataConstant";
34
import { IMetadataTypeTag } from "../../../schemas/metadata/IMetadataTypeTag";
45
import { Metadata } from "../../../schemas/metadata/Metadata";
56
import { MetadataAtomic } from "../../../schemas/metadata/MetadataAtomic";
@@ -70,21 +71,53 @@ export const iterate_metadata_intersection =
7071
)
7172
return false;
7273

74+
// CONSIDER BOOLEAN TYPE CASE
75+
const booleanLiteral: boolean | null = (() => {
76+
const found = children.find(
77+
(c) =>
78+
c.size() === 1 &&
79+
c.constants.length === 1 &&
80+
c.constants[0]!.type === "boolean",
81+
)?.constants[0]?.values[0];
82+
if (found === undefined) return null;
83+
return children.every(
84+
(c) =>
85+
c.atomics.length === 0 ||
86+
c.atomics.every((a) => a.type !== "boolean"),
87+
)
88+
? (found as boolean)
89+
: null;
90+
})();
91+
if (
92+
booleanLiteral !== null &&
93+
meta.boolean_literal_intersected_ === true
94+
) {
95+
(
96+
meta.constants.find((c) => c.type === "boolean")!
97+
.values as boolean[]
98+
).push(booleanLiteral);
99+
return true;
100+
}
101+
73102
// VALIDATE EACH TYPES
74103
const individuals: (readonly [Metadata, number])[] = children
75104
.map((child, i) => [child, i] as const)
76105
.filter(
77106
([c]) =>
78107
c.size() === 1 &&
79-
(c.atomics.length === 1 || c.arrays.length === 1),
108+
(c.atomics.length === 1 ||
109+
(c.constants.length === 1 &&
110+
c.constants[0]!.type === "boolean") ||
111+
c.arrays.length === 1),
80112
);
81113
const constants: Metadata[] = children.filter(
82114
(m) =>
83115
m.size() ===
84-
m.constants
85-
.map((c) => c.values.length)
86-
.reduce((a, b) => a + b, 0) +
87-
m.templates.length,
116+
m.constants
117+
.map((c) => c.values.length)
118+
.reduce((a, b) => a + b, 0) +
119+
m.templates.length &&
120+
!(m.size() === 1 && m.constants[0]!.type === "boolean"),
88121
);
89122
const objects: Metadata[] = children.filter(
90123
(c) =>
@@ -98,7 +131,14 @@ export const iterate_metadata_intersection =
98131
);
99132
const atomics: Set<"boolean" | "bigint" | "number" | "string"> =
100133
new Set(
101-
individuals.map(([c]) => c.atomics.map((a) => a.type)).flat(),
134+
individuals
135+
.map(([c]) => [
136+
...c.atomics.map((a) => a.type),
137+
...c.constants
138+
.filter((l) => l.type === "boolean")
139+
.map((l) => l.type),
140+
])
141+
.flat(),
102142
);
103143
const arrays: Set<string> = new Set(
104144
individuals.map(([c]) => c.arrays.map((a) => a.type.name)).flat(),
@@ -149,21 +189,35 @@ export const iterate_metadata_intersection =
149189

150190
// RE-GENERATE TYPE
151191
const target: "boolean" | "bigint" | "number" | "string" | "array" =
152-
atomics.size ? atomics.values().next().value : "array";
192+
booleanLiteral
193+
? "boolean"
194+
: atomics.size
195+
? atomics.values().next().value
196+
: "array";
153197
if (
154198
target === "boolean" ||
155199
target === "bigint" ||
156200
target === "number" ||
157201
target === "string"
158202
)
159-
ArrayUtil.add(
160-
meta.atomics,
161-
MetadataAtomic.create({
162-
type: atomics.values().next().value as "string",
163-
tags: [],
164-
}),
165-
(a, b) => a.type === b.type,
166-
);
203+
if (booleanLiteral === null)
204+
ArrayUtil.add(
205+
meta.atomics,
206+
MetadataAtomic.create({
207+
type: atomics.values().next().value as "string",
208+
tags: [],
209+
}),
210+
(a, b) => a.type === b.type,
211+
);
212+
else
213+
ArrayUtil.take<IMetadataConstant>(
214+
meta.constants,
215+
(x) => x.type === "boolean",
216+
() => ({
217+
type: "boolean",
218+
values: [booleanLiteral],
219+
}),
220+
);
167221
else if (target === "array") {
168222
const name: string = arrays.values().next().value;
169223
if (!meta.arrays.some((a) => a.type.name === name)) {
@@ -182,16 +236,24 @@ export const iterate_metadata_intersection =
182236
}
183237

184238
// ASSIGN TAGS
185-
if (objects.length && target !== "boolean") {
239+
if (objects.length) {
186240
const tags: IMetadataTypeTag[] = MetadataTypeTagFactory.analyze(
187241
errors,
188242
)(target)(objects.map((om) => om.objects).flat(), explore);
189243
if (tags.length)
190244
if (target === "array") meta.arrays.at(-1)!.tags.push(tags);
191-
else
245+
else if (booleanLiteral === null)
192246
meta.atomics
193247
.find((a) => a.type === target)!
194248
.tags.push(tags);
249+
else {
250+
const constant: IMetadataConstant = meta.constants.find(
251+
(c) => c.type === "boolean",
252+
)!;
253+
constant.tags ??= [];
254+
constant.tags.push(tags);
255+
}
195256
}
257+
if (booleanLiteral !== null) meta.boolean_literal_intersected_ = true;
196258
return true;
197259
};
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,30 @@
1+
import { IMetadataTypeTag } from "../../schemas/metadata/IMetadataTypeTag";
2+
import { MetadataAtomic } from "../../schemas/metadata/MetadataAtomic";
3+
14
import { IJsonSchema } from "../../module";
25
import { application_default } from "./application_default";
36

47
/**
58
* @internal
69
*/
7-
export const application_boolean = (
8-
attribute: IJsonSchema.IAttribute,
9-
): IJsonSchema.IBoolean => ({
10-
...attribute,
11-
default: application_default(attribute)(
12-
(alias) => alias === "true" || alias === "false",
13-
)((str) => Boolean(str)),
14-
type: "boolean",
15-
});
10+
export const application_boolean =
11+
(atomic: MetadataAtomic) =>
12+
(attribute: IJsonSchema.IAttribute): IJsonSchema.IBoolean[] => {
13+
const base: IJsonSchema.IBoolean = {
14+
...attribute,
15+
default: application_default(attribute)(
16+
(alias) => alias === "true" || alias === "false",
17+
)((str) => Boolean(str)),
18+
type: "boolean",
19+
};
20+
const defaultTags: IMetadataTypeTag[] = atomic.tags
21+
.filter((row) => row.some((tag) => tag.kind === "default"))
22+
.map((row) => row.filter((tag) => tag.kind === "default"))
23+
.flat();
24+
if (defaultTags.length === 0) return [base];
25+
return defaultTags.map((tag) => ({
26+
...base,
27+
default: tag.value,
28+
"x-typia-typeTags": defaultTags,
29+
}));
30+
};

src/programmers/internal/application_number.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export const application_number =
1818
type: "number",
1919
};
2020
const out = (schema: Schema) => {
21-
schema.default = application_default(attribute)((str) => {
21+
schema.default ??= application_default(attribute)((str) => {
2222
const value: number = Number(str);
2323
const conditions: boolean[] = [!Number.isNaN(value)];
2424
if (schema.minimum !== undefined)
@@ -82,6 +82,8 @@ const application_number_tags =
8282
typeof tag.value === "number"
8383
)
8484
base.multipleOf = tag.value;
85+
else if (tag.kind === "default" && typeof tag.value === "number")
86+
base.default = tag.value;
8587
}
8688
base["x-typia-typeTags"] = row;
8789
return base;

src/programmers/internal/application_schema.ts

+11-6
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,11 @@ export const application_schema =
8080
for (const a of meta.atomics)
8181
if (a.type === "bigint") throw new TypeError(NO_BIGINT);
8282
else if (a.type === "boolean")
83-
insert(application_boolean(attribute));
83+
application_boolean(a)(attribute).forEach(insert);
8484
else if (a.type === "number")
85-
application_number(a)(attribute).forEach((s) => insert(s));
85+
application_number(a)(attribute).forEach(insert);
8686
else if (a.type === "string")
87-
application_string(meta)(a)(attribute).forEach((s) =>
88-
insert(s),
89-
);
87+
application_string(meta)(a)(attribute).forEach(insert);
9088

9189
// ARRAY
9290
for (const array of meta.arrays)
@@ -105,7 +103,14 @@ export const application_schema =
105103
if (meta.atomics.some((a) => a.type === type)) continue;
106104
else if (type === "bigint") throw new TypeError(NO_BIGINT);
107105
else if (type === "boolean")
108-
insert(application_boolean(attribute));
106+
insert(
107+
application_boolean(
108+
MetadataAtomic.create({
109+
type: "boolean",
110+
tags: [],
111+
}),
112+
)(attribute)[0]!,
113+
);
109114
else if (type === "number")
110115
insert(
111116
application_number(

0 commit comments

Comments
 (0)