@atscript/typescript 0.0.29 → 0.0.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +6 -6
- package/dist/index.cjs +7 -27
- package/dist/index.d.ts +1 -132
- package/dist/index.mjs +7 -20
- package/dist/utils.cjs +552 -0
- package/dist/utils.d.ts +132 -0
- package/dist/utils.mjs +546 -0
- package/package.json +26 -3
package/dist/utils.mjs
ADDED
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
|
|
2
|
+
//#region packages/typescript/src/validator.ts
|
|
3
|
+
function _define_property(obj, key, value) {
|
|
4
|
+
if (key in obj) Object.defineProperty(obj, key, {
|
|
5
|
+
value,
|
|
6
|
+
enumerable: true,
|
|
7
|
+
configurable: true,
|
|
8
|
+
writable: true
|
|
9
|
+
});
|
|
10
|
+
else obj[key] = value;
|
|
11
|
+
return obj;
|
|
12
|
+
}
|
|
13
|
+
const regexCache = new Map();
|
|
14
|
+
var Validator = class {
|
|
15
|
+
isLimitExceeded() {
|
|
16
|
+
if (this.stackErrors.length > 0) return this.stackErrors[this.stackErrors.length - 1].length >= this.opts.errorLimit;
|
|
17
|
+
return this.errors.length >= this.opts.errorLimit;
|
|
18
|
+
}
|
|
19
|
+
push(name) {
|
|
20
|
+
this.stackPath.push(name);
|
|
21
|
+
this.stackErrors.push([]);
|
|
22
|
+
}
|
|
23
|
+
pop(saveErrors) {
|
|
24
|
+
this.stackPath.pop();
|
|
25
|
+
const popped = this.stackErrors.pop();
|
|
26
|
+
if (saveErrors && popped?.length) popped.forEach((error) => {
|
|
27
|
+
this.error(error.message, error.path, error.details);
|
|
28
|
+
});
|
|
29
|
+
return popped;
|
|
30
|
+
}
|
|
31
|
+
clear() {
|
|
32
|
+
this.stackErrors[this.stackErrors.length - 1] = [];
|
|
33
|
+
}
|
|
34
|
+
error(message, path, details) {
|
|
35
|
+
const errors = this.stackErrors[this.stackErrors.length - 1] || this.errors;
|
|
36
|
+
const error = {
|
|
37
|
+
path: path || this.path,
|
|
38
|
+
message
|
|
39
|
+
};
|
|
40
|
+
if (details?.length) error.details = details;
|
|
41
|
+
errors.push(error);
|
|
42
|
+
}
|
|
43
|
+
throw() {
|
|
44
|
+
throw new ValidatorError(this.errors);
|
|
45
|
+
}
|
|
46
|
+
validate(value, safe) {
|
|
47
|
+
this.push("");
|
|
48
|
+
this.errors = [];
|
|
49
|
+
this.stackErrors = [];
|
|
50
|
+
const passed = this.validateSafe(this.def, value);
|
|
51
|
+
this.pop(!passed);
|
|
52
|
+
if (!passed) {
|
|
53
|
+
if (safe) return false;
|
|
54
|
+
this.throw();
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
validateSafe(def, value) {
|
|
59
|
+
if (this.isLimitExceeded()) return false;
|
|
60
|
+
if (!isAnnotatedType(def)) throw new Error("Can not validate not-annotated type");
|
|
61
|
+
if (typeof this.opts.replace === "function") def = this.opts.replace(def, this.path);
|
|
62
|
+
if (def.optional && value === undefined) return true;
|
|
63
|
+
for (const plugin of this.opts.plugins) {
|
|
64
|
+
const result = plugin(this, def, value);
|
|
65
|
+
if (result === false || result === true) return result;
|
|
66
|
+
}
|
|
67
|
+
return this.validateAnnotatedType(def, value);
|
|
68
|
+
}
|
|
69
|
+
get path() {
|
|
70
|
+
return this.stackPath.slice(1).join(".");
|
|
71
|
+
}
|
|
72
|
+
validateAnnotatedType(def, value) {
|
|
73
|
+
switch (def.type.kind) {
|
|
74
|
+
case "object": return this.validateObject(def, value);
|
|
75
|
+
case "union": return this.validateUnion(def, value);
|
|
76
|
+
case "intersection": return this.validateIntersection(def, value);
|
|
77
|
+
case "tuple": return this.validateTuple(def, value);
|
|
78
|
+
case "array": return this.validateArray(def, value);
|
|
79
|
+
case "": return this.validatePrimitive(def, value);
|
|
80
|
+
default: throw new Error(`Unknown type "${def.type.kind}"`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
validateUnion(def, value) {
|
|
84
|
+
let i = 0;
|
|
85
|
+
const popped = [];
|
|
86
|
+
for (const item of def.type.items) {
|
|
87
|
+
this.push(`[${item.type.kind || item.type.designType}(${i})]`);
|
|
88
|
+
if (this.validateSafe(item, value)) {
|
|
89
|
+
this.pop(false);
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
const errors = this.pop(false);
|
|
93
|
+
if (errors) popped.push(...errors);
|
|
94
|
+
i++;
|
|
95
|
+
}
|
|
96
|
+
this.clear();
|
|
97
|
+
const expected = def.type.items.map((item, i$1) => `[${item.type.kind || item.type.designType}(${i$1})]`).join(", ");
|
|
98
|
+
this.error(`Value does not match any of the allowed types: ${expected}`, undefined, popped);
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
validateIntersection(def, value) {
|
|
102
|
+
for (const item of def.type.items) if (!this.validateSafe(item, value)) return false;
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
validateTuple(def, value) {
|
|
106
|
+
if (!Array.isArray(value) || value.length !== def.type.items.length) {
|
|
107
|
+
this.error(`Expected array of length ${def.type.items.length}`);
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
let i = 0;
|
|
111
|
+
for (const item of def.type.items) {
|
|
112
|
+
this.push(`[${i}]`);
|
|
113
|
+
if (!this.validateSafe(item, value[i])) {
|
|
114
|
+
this.pop(true);
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
this.pop(false);
|
|
118
|
+
i++;
|
|
119
|
+
}
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
validateArray(def, value) {
|
|
123
|
+
if (!Array.isArray(value)) {
|
|
124
|
+
this.error("Expected array");
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
const minLength = def.metadata.get("expect.minLength");
|
|
128
|
+
if (typeof minLength === "number" && value.length < minLength) {
|
|
129
|
+
this.error(`Expected minimum length of ${minLength} items, got ${value.length} items`);
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
const maxLength = def.metadata.get("expect.maxLength");
|
|
133
|
+
if (typeof maxLength === "number" && value.length > maxLength) {
|
|
134
|
+
this.error(`Expected maximum length of ${maxLength} items, got ${value.length} items`);
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
let i = 0;
|
|
138
|
+
let passed = true;
|
|
139
|
+
for (const item of value) {
|
|
140
|
+
this.push(`[${i}]`);
|
|
141
|
+
if (!this.validateSafe(def.type.of, item)) {
|
|
142
|
+
passed = false;
|
|
143
|
+
this.pop(true);
|
|
144
|
+
if (this.isLimitExceeded()) return false;
|
|
145
|
+
} else this.pop(false);
|
|
146
|
+
i++;
|
|
147
|
+
}
|
|
148
|
+
return passed;
|
|
149
|
+
}
|
|
150
|
+
validateObject(def, value) {
|
|
151
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
152
|
+
this.error("Expected object");
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
let passed = true;
|
|
156
|
+
const valueKeys = new Set(Object.keys(value));
|
|
157
|
+
const typeKeys = new Set();
|
|
158
|
+
const skipList = new Set();
|
|
159
|
+
if (this.opts.skipList) {
|
|
160
|
+
const path = this.stackPath.length > 1 ? `${this.path}.` : "";
|
|
161
|
+
this.opts.skipList.forEach((item) => {
|
|
162
|
+
if (item.startsWith(path)) {
|
|
163
|
+
const key = item.slice(path.length);
|
|
164
|
+
skipList.add(key);
|
|
165
|
+
valueKeys.delete(key);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
let partialFunctionMatched = false;
|
|
170
|
+
if (typeof this.opts.partial === "function") partialFunctionMatched = this.opts.partial(def, this.path);
|
|
171
|
+
for (const [key, item] of def.type.props.entries()) {
|
|
172
|
+
if (skipList.has(key)) continue;
|
|
173
|
+
typeKeys.add(key);
|
|
174
|
+
if (value[key] === undefined) {
|
|
175
|
+
if (partialFunctionMatched || this.opts.partial === "deep" || this.opts.partial === true && this.stackPath.length <= 1) continue;
|
|
176
|
+
}
|
|
177
|
+
this.push(key);
|
|
178
|
+
if (this.validateSafe(item, value[key])) this.pop(false);
|
|
179
|
+
else {
|
|
180
|
+
passed = false;
|
|
181
|
+
this.pop(true);
|
|
182
|
+
if (this.isLimitExceeded()) return false;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
for (const key of valueKeys)
|
|
186
|
+
/** matched patterns for unknown keys */ if (!typeKeys.has(key)) {
|
|
187
|
+
const matched = [];
|
|
188
|
+
for (const { pattern, def: propDef } of def.type.propsPatterns) if (pattern.test(key)) matched.push({
|
|
189
|
+
pattern,
|
|
190
|
+
def: propDef
|
|
191
|
+
});
|
|
192
|
+
if (matched.length) {
|
|
193
|
+
let keyPassed = false;
|
|
194
|
+
for (const { def: def$1 } of matched) if (this.validateSafe(def$1, value[key])) {
|
|
195
|
+
this.pop(false);
|
|
196
|
+
keyPassed = true;
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
if (!keyPassed) {
|
|
200
|
+
this.push(key);
|
|
201
|
+
this.validateSafe(matched[0].def, value[key]);
|
|
202
|
+
this.pop(true);
|
|
203
|
+
passed = false;
|
|
204
|
+
if (this.isLimitExceeded()) return false;
|
|
205
|
+
}
|
|
206
|
+
} else if (this.opts.unknwonProps !== "ignore") {
|
|
207
|
+
if (this.opts.unknwonProps === "error") {
|
|
208
|
+
this.push(key);
|
|
209
|
+
this.error(`Unexpected property`);
|
|
210
|
+
this.pop(true);
|
|
211
|
+
if (this.isLimitExceeded()) return false;
|
|
212
|
+
passed = false;
|
|
213
|
+
} else if (this.opts.unknwonProps === "strip") delete value[key];
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return passed;
|
|
217
|
+
}
|
|
218
|
+
validatePrimitive(def, value) {
|
|
219
|
+
if (typeof def.type.value !== "undefined") {
|
|
220
|
+
if (value !== def.type.value) {
|
|
221
|
+
this.error(`Expected ${def.type.value}, got ${value}`);
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
226
|
+
const typeOfValue = Array.isArray(value) ? "array" : typeof value;
|
|
227
|
+
switch (def.type.designType) {
|
|
228
|
+
case "never":
|
|
229
|
+
this.error(`This type is impossible, must be an internal problem`);
|
|
230
|
+
return false;
|
|
231
|
+
case "any": return true;
|
|
232
|
+
case "string":
|
|
233
|
+
if (typeOfValue !== def.type.designType) {
|
|
234
|
+
this.error(`Expected ${def.type.designType}, got ${typeOfValue}`);
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
return this.validateString(def, value);
|
|
238
|
+
case "number":
|
|
239
|
+
if (typeOfValue !== def.type.designType) {
|
|
240
|
+
this.error(`Expected ${def.type.designType}, got ${typeOfValue}`);
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
return this.validateNumber(def, value);
|
|
244
|
+
case "boolean":
|
|
245
|
+
if (typeOfValue !== def.type.designType) {
|
|
246
|
+
this.error(`Expected ${def.type.designType}, got ${typeOfValue}`);
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
return true;
|
|
250
|
+
case "undefined":
|
|
251
|
+
if (value !== undefined) {
|
|
252
|
+
this.error(`Expected ${def.type.designType}, got ${typeOfValue}`);
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
return true;
|
|
256
|
+
case "null":
|
|
257
|
+
if (value !== null) {
|
|
258
|
+
this.error(`Expected ${def.type.designType}, got ${typeOfValue}`);
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
return true;
|
|
262
|
+
default: throw new Error(`Unknown type "${def.type.designType}"`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
validateString(def, value) {
|
|
266
|
+
const minLength = def.metadata.get("expect.minLength");
|
|
267
|
+
if (typeof minLength === "number" && value.length < minLength) {
|
|
268
|
+
this.error(`Expected minimum length of ${minLength} characters, got ${value.length} characters`);
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
const maxLength = def.metadata.get("expect.maxLength");
|
|
272
|
+
if (typeof maxLength === "number" && value.length > maxLength) {
|
|
273
|
+
this.error(`Expected maximum length of ${maxLength} characters, got ${value.length} characters`);
|
|
274
|
+
return false;
|
|
275
|
+
}
|
|
276
|
+
const patterns = def.metadata.get("expect.pattern");
|
|
277
|
+
for (const { pattern, flags, message } of patterns || []) {
|
|
278
|
+
if (!pattern) continue;
|
|
279
|
+
const cacheKey = `${pattern}//${flags || ""}`;
|
|
280
|
+
let regex = regexCache.get(cacheKey);
|
|
281
|
+
if (!regex) {
|
|
282
|
+
regex = new RegExp(pattern, flags);
|
|
283
|
+
regexCache.set(cacheKey, regex);
|
|
284
|
+
}
|
|
285
|
+
if (!regex.test(value)) {
|
|
286
|
+
this.error(message || `Value is expected to match pattern "${pattern}"`);
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
validateNumber(def, value) {
|
|
293
|
+
const int = def.metadata.get("expect.int");
|
|
294
|
+
if (typeof int === "boolean" && int && value % 1 !== 0) {
|
|
295
|
+
this.error(`Expected integer, got ${value}`);
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
const min = def.metadata.get("expect.min");
|
|
299
|
+
if (typeof min === "number" && value < min) {
|
|
300
|
+
this.error(`Expected minimum ${min}, got ${value}`);
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
const max = def.metadata.get("expect.max");
|
|
304
|
+
if (typeof max === "number" && value > max) {
|
|
305
|
+
this.error(`Expected maximum ${max}, got ${value}`);
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
return true;
|
|
309
|
+
}
|
|
310
|
+
constructor(def, opts) {
|
|
311
|
+
_define_property(this, "def", void 0);
|
|
312
|
+
_define_property(this, "opts", void 0);
|
|
313
|
+
_define_property(this, "errors", void 0);
|
|
314
|
+
_define_property(this, "stackErrors", void 0);
|
|
315
|
+
_define_property(this, "stackPath", void 0);
|
|
316
|
+
this.def = def;
|
|
317
|
+
this.errors = [];
|
|
318
|
+
this.stackErrors = [];
|
|
319
|
+
this.stackPath = [];
|
|
320
|
+
this.opts = {
|
|
321
|
+
partial: false,
|
|
322
|
+
unknwonProps: "error",
|
|
323
|
+
errorLimit: 10,
|
|
324
|
+
...opts,
|
|
325
|
+
plugins: opts?.plugins || []
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
var ValidatorError = class extends Error {
|
|
330
|
+
constructor(errors) {
|
|
331
|
+
super(`${errors[0].path ? errors[0].path + ": " : ""}${errors[0].message}`), _define_property(this, "errors", void 0), _define_property(this, "name", void 0), this.errors = errors, this.name = "Validation Error";
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
//#endregion
|
|
336
|
+
//#region packages/typescript/src/annotated-type.ts
|
|
337
|
+
function isAnnotatedType(type) {
|
|
338
|
+
return type && type.__is_atscript_annotated_type;
|
|
339
|
+
}
|
|
340
|
+
function defineAnnotatedType(_kind, base) {
|
|
341
|
+
const kind = _kind || "";
|
|
342
|
+
const type = base?.type || {};
|
|
343
|
+
type.kind = kind;
|
|
344
|
+
if ([
|
|
345
|
+
"union",
|
|
346
|
+
"intersection",
|
|
347
|
+
"tuple"
|
|
348
|
+
].includes(kind)) type.items = [];
|
|
349
|
+
if (kind === "object") {
|
|
350
|
+
type.props = new Map();
|
|
351
|
+
type.propsPatterns = [];
|
|
352
|
+
}
|
|
353
|
+
type.tags = new Set();
|
|
354
|
+
const metadata = base?.metadata || new Map();
|
|
355
|
+
if (base) Object.assign(base, {
|
|
356
|
+
__is_atscript_annotated_type: true,
|
|
357
|
+
metadata,
|
|
358
|
+
type,
|
|
359
|
+
validator(opts) {
|
|
360
|
+
return new Validator(this, opts);
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
else base = {
|
|
364
|
+
__is_atscript_annotated_type: true,
|
|
365
|
+
metadata,
|
|
366
|
+
type,
|
|
367
|
+
validator(opts) {
|
|
368
|
+
return new Validator(this, opts);
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
const handle = {
|
|
372
|
+
$type: base,
|
|
373
|
+
$def: type,
|
|
374
|
+
$metadata: metadata,
|
|
375
|
+
_existingObject: undefined,
|
|
376
|
+
tags(...tags) {
|
|
377
|
+
for (const tag of tags) this.$def.tags.add(tag);
|
|
378
|
+
return this;
|
|
379
|
+
},
|
|
380
|
+
designType(value) {
|
|
381
|
+
this.$def.designType = value;
|
|
382
|
+
return this;
|
|
383
|
+
},
|
|
384
|
+
value(value) {
|
|
385
|
+
this.$def.value = value;
|
|
386
|
+
return this;
|
|
387
|
+
},
|
|
388
|
+
of(value) {
|
|
389
|
+
this.$def.of = value;
|
|
390
|
+
return this;
|
|
391
|
+
},
|
|
392
|
+
item(value) {
|
|
393
|
+
this.$def.items.push(value);
|
|
394
|
+
return this;
|
|
395
|
+
},
|
|
396
|
+
prop(name, value) {
|
|
397
|
+
this.$def.props.set(name, value);
|
|
398
|
+
return this;
|
|
399
|
+
},
|
|
400
|
+
propPattern(pattern, def) {
|
|
401
|
+
this.$def.propsPatterns.push({
|
|
402
|
+
pattern,
|
|
403
|
+
def
|
|
404
|
+
});
|
|
405
|
+
return this;
|
|
406
|
+
},
|
|
407
|
+
optional(value = true) {
|
|
408
|
+
this.$type.optional = value;
|
|
409
|
+
return this;
|
|
410
|
+
},
|
|
411
|
+
copyMetadata(fromMetadata, ignore) {
|
|
412
|
+
for (const [key, value] of fromMetadata.entries()) if (!ignore || !ignore.has(key)) this.$metadata.set(key, value);
|
|
413
|
+
return this;
|
|
414
|
+
},
|
|
415
|
+
refTo(type$1, chain) {
|
|
416
|
+
let newBase = type$1;
|
|
417
|
+
const typeName = type$1.name || "Unknown";
|
|
418
|
+
if (isAnnotatedType(newBase)) {
|
|
419
|
+
let keys = "";
|
|
420
|
+
for (const c of chain || []) {
|
|
421
|
+
keys += `["${c}"]`;
|
|
422
|
+
if (newBase.type.kind === "object" && newBase.type.props.has(c)) newBase = newBase.type.props.get(c);
|
|
423
|
+
else throw new Error(`Can't find prop ${typeName}${keys}`);
|
|
424
|
+
}
|
|
425
|
+
if (!newBase && keys) throw new Error(`Can't find prop ${typeName}${keys}`);
|
|
426
|
+
else if (!newBase) throw new Error(`"${typeName}" is not annotated type`);
|
|
427
|
+
this.$type = {
|
|
428
|
+
__is_atscript_annotated_type: true,
|
|
429
|
+
type: newBase.type,
|
|
430
|
+
metadata,
|
|
431
|
+
validator(opts) {
|
|
432
|
+
return new Validator(this, opts);
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
} else throw new Error(`${type$1} is not annotated type`);
|
|
436
|
+
return this;
|
|
437
|
+
},
|
|
438
|
+
annotate(key, value, asArray) {
|
|
439
|
+
if (asArray) if (this.$metadata.has(key)) {
|
|
440
|
+
const a = this.$metadata.get(key);
|
|
441
|
+
if (Array.isArray(a)) a.push(value);
|
|
442
|
+
else this.$metadata.set(key, [a, value]);
|
|
443
|
+
} else this.$metadata.set(key, [value]);
|
|
444
|
+
else this.$metadata.set(key, value);
|
|
445
|
+
return this;
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
return handle;
|
|
449
|
+
}
|
|
450
|
+
function isAnnotatedTypeOfPrimitive(t) {
|
|
451
|
+
if (["array", "object"].includes(t.type.kind)) return false;
|
|
452
|
+
if (!t.type.kind) return true;
|
|
453
|
+
if ([
|
|
454
|
+
"union",
|
|
455
|
+
"tuple",
|
|
456
|
+
"intersection"
|
|
457
|
+
].includes(t.type.kind)) {
|
|
458
|
+
for (const item of t.type.items) if (!isAnnotatedTypeOfPrimitive(item)) return false;
|
|
459
|
+
return true;
|
|
460
|
+
}
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
//#endregion
|
|
465
|
+
//#region packages/typescript/src/json-schema.ts
|
|
466
|
+
function buildJsonSchema(type) {
|
|
467
|
+
const build = (def) => {
|
|
468
|
+
const t = def.type;
|
|
469
|
+
const meta = def.metadata;
|
|
470
|
+
switch (t.kind) {
|
|
471
|
+
case "object": {
|
|
472
|
+
const obj = t;
|
|
473
|
+
const properties = {};
|
|
474
|
+
const required = [];
|
|
475
|
+
for (const [key, val] of obj.props.entries()) {
|
|
476
|
+
properties[key] = build(val);
|
|
477
|
+
if (!val.optional) required.push(key);
|
|
478
|
+
}
|
|
479
|
+
const schema = {
|
|
480
|
+
type: "object",
|
|
481
|
+
properties
|
|
482
|
+
};
|
|
483
|
+
if (required.length) schema.required = required;
|
|
484
|
+
return schema;
|
|
485
|
+
}
|
|
486
|
+
case "array": {
|
|
487
|
+
const arr = t;
|
|
488
|
+
const schema = {
|
|
489
|
+
type: "array",
|
|
490
|
+
items: build(arr.of)
|
|
491
|
+
};
|
|
492
|
+
const minLength = meta.get("expect.minLength");
|
|
493
|
+
if (typeof minLength === "number") schema.minItems = minLength;
|
|
494
|
+
const maxLength = meta.get("expect.maxLength");
|
|
495
|
+
if (typeof maxLength === "number") schema.maxItems = maxLength;
|
|
496
|
+
return schema;
|
|
497
|
+
}
|
|
498
|
+
case "union": {
|
|
499
|
+
const grp = t;
|
|
500
|
+
return { anyOf: grp.items.map(build) };
|
|
501
|
+
}
|
|
502
|
+
case "intersection": {
|
|
503
|
+
const grp = t;
|
|
504
|
+
return { allOf: grp.items.map(build) };
|
|
505
|
+
}
|
|
506
|
+
case "tuple": {
|
|
507
|
+
const grp = t;
|
|
508
|
+
return {
|
|
509
|
+
type: "array",
|
|
510
|
+
items: grp.items.map(build),
|
|
511
|
+
additionalItems: false
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
case "": {
|
|
515
|
+
const fin = t;
|
|
516
|
+
const schema = {};
|
|
517
|
+
if (fin.value !== undefined) schema.const = fin.value;
|
|
518
|
+
if (fin.designType && fin.designType !== "any") {
|
|
519
|
+
schema.type = fin.designType === "undefined" ? "null" : fin.designType;
|
|
520
|
+
if (schema.type === "number" && meta.get("expect.int")) schema.type = "integer";
|
|
521
|
+
}
|
|
522
|
+
if (schema.type === "string") {
|
|
523
|
+
const minLength = meta.get("expect.minLength");
|
|
524
|
+
if (typeof minLength === "number") schema.minLength = minLength;
|
|
525
|
+
const maxLength = meta.get("expect.maxLength");
|
|
526
|
+
if (typeof maxLength === "number") schema.maxLength = maxLength;
|
|
527
|
+
const patterns = meta.get("expect.pattern");
|
|
528
|
+
if (patterns?.length) if (patterns.length === 1) schema.pattern = patterns[0].pattern;
|
|
529
|
+
else schema.allOf = (schema.allOf || []).concat(patterns.map((p) => ({ pattern: p.pattern })));
|
|
530
|
+
}
|
|
531
|
+
if (schema.type === "number" || schema.type === "integer") {
|
|
532
|
+
const min = meta.get("expect.min");
|
|
533
|
+
if (typeof min === "number") schema.minimum = min;
|
|
534
|
+
const max = meta.get("expect.max");
|
|
535
|
+
if (typeof max === "number") schema.maximum = max;
|
|
536
|
+
}
|
|
537
|
+
return schema;
|
|
538
|
+
}
|
|
539
|
+
default: return {};
|
|
540
|
+
}
|
|
541
|
+
};
|
|
542
|
+
return build(type);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
//#endregion
|
|
546
|
+
export { Validator, ValidatorError, buildJsonSchema, defineAnnotatedType, isAnnotatedType, isAnnotatedTypeOfPrimitive };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atscript/typescript",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.31",
|
|
4
4
|
"description": "Atscript: typescript-gen support.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -9,10 +9,27 @@
|
|
|
9
9
|
".": {
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
11
11
|
"import": "./dist/index.mjs",
|
|
12
|
-
"require": "./dist/index.cjs"
|
|
12
|
+
"require": "./dist/index.cjs",
|
|
13
|
+
"default": "./dist/index.mjs"
|
|
14
|
+
},
|
|
15
|
+
"./utils": {
|
|
16
|
+
"types": "./dist/utils.d.ts",
|
|
17
|
+
"import": "./dist/utils.mjs",
|
|
18
|
+
"require": "./dist/utils.cjs",
|
|
19
|
+
"default": "./dist/utils.mjs"
|
|
13
20
|
},
|
|
14
21
|
"./package.json": "./package.json"
|
|
15
22
|
},
|
|
23
|
+
"typesVersions": {
|
|
24
|
+
"*": {
|
|
25
|
+
"utils": [
|
|
26
|
+
"dist/utils.d.ts"
|
|
27
|
+
],
|
|
28
|
+
"": [
|
|
29
|
+
"dist/index.d.ts"
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
},
|
|
16
33
|
"files": [
|
|
17
34
|
"dist",
|
|
18
35
|
"cli.cjs"
|
|
@@ -22,6 +39,12 @@
|
|
|
22
39
|
},
|
|
23
40
|
"build": [
|
|
24
41
|
{},
|
|
42
|
+
{
|
|
43
|
+
"entries": [
|
|
44
|
+
"src/utils.ts"
|
|
45
|
+
],
|
|
46
|
+
"dts": true
|
|
47
|
+
},
|
|
25
48
|
{
|
|
26
49
|
"format": "cjs",
|
|
27
50
|
"entries": [
|
|
@@ -47,7 +70,7 @@
|
|
|
47
70
|
"homepage": "https://github.com/moostjs/atscript/tree/main/packages/typescript#readme",
|
|
48
71
|
"license": "ISC",
|
|
49
72
|
"peerDependencies": {
|
|
50
|
-
"@atscript/core": "^0.0.
|
|
73
|
+
"@atscript/core": "^0.0.31"
|
|
51
74
|
},
|
|
52
75
|
"dependencies": {
|
|
53
76
|
"@moostjs/event-cli": "^0.5.32",
|