Skip to content
This repository was archived by the owner on Feb 23, 2026. It is now read-only.

Commit e7679b2

Browse files
committed
v1.0.7
1 parent e17dd9b commit e7679b2

5 files changed

Lines changed: 44 additions & 29 deletions

File tree

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@
2020
"json-schema-to-typescript": "^15.0.4",
2121
"lodash.merge": "^4.6.2",
2222
"slugify": "^1.6.6",
23-
"sort-keys": "^6.0.0",
24-
"typof": "^1.0.16"
23+
"sort-keys": "^6.0.0"
2524
},
2625
"devDependencies": {
2726
"prettier": "latest",

src/types/Schema.type.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
/* eslint-disable @typescript-eslint/array-type */
2-
31
export type String = {
42
type: 'string';
53
enum?: string[];
@@ -51,7 +49,7 @@ export type Object = {
5149
required: boolean;
5250
};
5351

54-
export type Array = {
52+
export type _Array = {
5553
type: 'array';
5654
min?: number;
5755
max?: number;
@@ -61,7 +59,7 @@ export type Array = {
6159
required: boolean;
6260
};
6361

64-
export type TypeSingle = String | Number | Boolean | Date | Object | Array;
62+
export type TypeSingle = String | Number | Boolean | Date | Object | _Array;
6563

6664
export type TypeUnion = [TypeSingle, TypeSingle, ...TypeSingle[]];
6765

src/utils/Engine.util.ts

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ const getRegex = (pattern: string) => {
2020
};
2121

2222
const findMatchedType = (type_union: TypeUnion, property: unknown) => {
23+
if (property === undefined) {
24+
const schema_with_default = type_union.find((schema) => schema.default !== undefined);
25+
26+
if (schema_with_default) return schema_with_default;
27+
28+
return type_union[0];
29+
}
30+
2331
const matched = type_union.find((schema) => {
2432
if (property === null) return schema.nullable;
2533

@@ -34,25 +42,35 @@ const findMatchedType = (type_union: TypeUnion, property: unknown) => {
3442
};
3543

3644
const findMatchedSchema = (schema_union: SchemaUnion, properties: Record<string, unknown>) => {
37-
const matched = schema_union.find((schemaRecord) => {
38-
const first_key = Object.keys(schemaRecord)[0];
39-
40-
if (!first_key) return false;
41-
42-
const first_type = schemaRecord[first_key];
43-
const target_type = Array.isArray(first_type) ? first_type[0] : first_type;
44-
const property = properties[first_key];
45+
let best_match = schema_union[0];
46+
let max_score = -1;
4547

46-
if (property === null) return target_type.nullable;
48+
for (const schema_record of schema_union) {
49+
let score = 0;
4750

48-
if (target_type.type === 'date') return typeof property === 'string' || property instanceof Date;
49-
if (target_type.type === 'array') return Array.isArray(property);
50-
if (target_type.type === 'object') return typeof property === 'object' && !Array.isArray(property);
51+
for (const key of Object.keys(schema_record)) {
52+
const property = properties[key];
53+
const schema_def = schema_record[key];
54+
const target_type = Array.isArray(schema_def) ? findMatchedType(schema_def, property) : schema_def;
55+
56+
if (property === null) {
57+
if (target_type.nullable) {
58+
score++;
59+
} else score -= 2;
60+
} else if (property !== undefined) {
61+
if ((target_type.type === 'string' && typeof property === 'string') || (target_type.type === 'number' && typeof property === 'number') || (target_type.type === 'boolean' && typeof property === 'boolean') || (target_type.type === 'object' && typeof property === 'object' && !Array.isArray(property)) || (target_type.type === 'array' && Array.isArray(property))) {
62+
score++;
63+
} else score -= 2;
64+
} else if (target_type.required && target_type.default === undefined) score -= 1;
65+
}
5166

52-
return typeof property === target_type.type;
53-
});
67+
if (score > max_score) {
68+
max_score = score;
69+
best_match = schema_record;
70+
}
71+
}
5472

55-
return matched ?? schema_union[0];
73+
return best_match;
5674
};
5775

5876
export const validate = async <const _Schema extends Schema>(schema: _Schema, properties: Record<string, unknown>, options: TeyitOptions): Promise<InferSchema<_Schema>> => {
@@ -82,7 +100,7 @@ export const validate = async <const _Schema extends Schema>(schema: _Schema, pr
82100
} else throw new ValidationError({ errors: [error] });
83101
};
84102

85-
const processProperty = (equivalent: TypeSingle, property: unknown, path: string): unknown => {
103+
const processProperty = async (equivalent: TypeSingle, property: unknown, path: string): Promise<unknown> => {
86104
if (property === undefined) {
87105
if (equivalent.default !== undefined) {
88106
return equivalent.default;
@@ -150,7 +168,7 @@ export const validate = async <const _Schema extends Schema>(schema: _Schema, pr
150168

151169
return value;
152170
} else if (equivalent.type === 'number') {
153-
if (typeof property !== 'number') {
171+
if (typeof property !== 'number' || !Number.isFinite(property)) {
154172
reportError({ message: (options.error_messages?.number?.type ?? '').replaceAll('{path}', path), parts: { path } });
155173

156174
return property;
@@ -166,7 +184,7 @@ export const validate = async <const _Schema extends Schema>(schema: _Schema, pr
166184

167185
if (equivalent.positive === true && property < 0) reportError({ message: (options.error_messages?.number?.positive ?? '').replaceAll('{path}', path), parts: { path } });
168186

169-
if (equivalent.negative === true && property >= 0) reportError({ message: (options.error_messages?.number?.negative ?? '').replaceAll('{path}', path), parts: { path } });
187+
if (equivalent.negative === true && property > 0) reportError({ message: (options.error_messages?.number?.negative ?? '').replaceAll('{path}', path), parts: { path } });
170188

171189
return property;
172190
} else if (equivalent.type === 'boolean') {
@@ -220,7 +238,7 @@ export const validate = async <const _Schema extends Schema>(schema: _Schema, pr
220238
const target_schema = Array.isArray(schema_property) ? findMatchedType(schema_property, property_record[key]) : schema_property;
221239

222240
const next_path = path === 'root' ? key : `${path}.${key}`;
223-
const property_processed = processProperty(target_schema, property_record[key], next_path);
241+
const property_processed = await processProperty(target_schema, property_record[key], next_path);
224242

225243
if (property_processed !== undefined) result_record[key] = property_processed;
226244
}
@@ -247,7 +265,7 @@ export const validate = async <const _Schema extends Schema>(schema: _Schema, pr
247265
const base_path = path === 'root' ? '' : path;
248266
const next_path = `${base_path}[${String(i)}]`;
249267

250-
results_array[i] = processProperty(target_schema, property[i], next_path);
268+
results_array[i] = await processProperty(target_schema, property[i], next_path);
251269
}
252270

253271
return results_array;
@@ -267,7 +285,7 @@ export const validate = async <const _Schema extends Schema>(schema: _Schema, pr
267285
const schema_property = schema_record[key];
268286
const target_schema = Array.isArray(schema_property) ? findMatchedType(schema_property, properties[key]) : schema_property;
269287

270-
const property_processed = processProperty(target_schema, properties[key], key);
288+
const property_processed = await processProperty(target_schema, properties[key], key);
271289

272290
if (property_processed !== undefined) result_record[key] = property_processed;
273291
}

tests/SchemaUnion.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Teyit, type Schema, type ValidationError } from '../src/main';
22

3-
const teyit = new Teyit({ output_dir: './tests/generated/teyit' });
3+
const teyit = new Teyit();
44

55
const schema = [
66
{

tests/TypeUnion.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Teyit, type Schema, type ValidationError } from '../src/main';
22

3-
const teyit = new Teyit({ output_dir: './tests/generated/teyit' });
3+
const teyit = new Teyit();
44

55
const schema = {
66
field: [

0 commit comments

Comments
 (0)