@atscript/typescript 0.1.33 → 0.1.35

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/utils.cjs CHANGED
@@ -1,915 +1,6 @@
1
1
  "use strict";
2
+ const require_json_schema = require('./json-schema-S5-XAOrR.cjs');
2
3
 
3
- //#region packages/typescript/src/validator.ts
4
- function _define_property(obj, key, value) {
5
- if (key in obj) Object.defineProperty(obj, key, {
6
- value,
7
- enumerable: true,
8
- configurable: true,
9
- writable: true
10
- });
11
- else obj[key] = value;
12
- return obj;
13
- }
14
- const regexCache = new Map();
15
- var Validator = class {
16
- isLimitExceeded() {
17
- if (this.stackErrors.length > 0) {
18
- const top = this.stackErrors[this.stackErrors.length - 1];
19
- return top !== null && top.length >= this.opts.errorLimit;
20
- }
21
- return this.errors.length >= this.opts.errorLimit;
22
- }
23
- push(name) {
24
- this.stackPath.push(name);
25
- this.stackErrors.push(null);
26
- this.cachedPath = this.stackPath.length <= 1 ? "" : this.stackPath[1] + (this.stackPath.length > 2 ? "." + this.stackPath.slice(2).join(".") : "");
27
- }
28
- pop(saveErrors) {
29
- this.stackPath.pop();
30
- const popped = this.stackErrors.pop();
31
- if (saveErrors && popped !== null && popped !== undefined && popped.length > 0) for (const err of popped) this.error(err.message, err.path, err.details);
32
- this.cachedPath = this.stackPath.length <= 1 ? "" : this.stackPath[1] + (this.stackPath.length > 2 ? "." + this.stackPath.slice(2).join(".") : "");
33
- return popped;
34
- }
35
- clear() {
36
- this.stackErrors[this.stackErrors.length - 1] = null;
37
- }
38
- error(message, path, details) {
39
- let errors = this.stackErrors[this.stackErrors.length - 1];
40
- if (!errors) if (this.stackErrors.length > 0) {
41
- errors = [];
42
- this.stackErrors[this.stackErrors.length - 1] = errors;
43
- } else errors = this.errors;
44
- const error = {
45
- path: path || this.cachedPath,
46
- message
47
- };
48
- if (details?.length) error.details = details;
49
- errors.push(error);
50
- }
51
- throw() {
52
- throw new ValidatorError(this.errors);
53
- }
54
- /**
55
- * Validates a value against the type definition.
56
- *
57
- * Acts as a TypeScript type guard — when it returns `true`, the value
58
- * is narrowed to `DataType`.
59
- *
60
- * @param value - The value to validate.
61
- * @param safe - If `true`, returns `false` on failure instead of throwing.
62
- * @returns `true` if the value matches the type definition.
63
- * @throws {ValidatorError} When validation fails and `safe` is not `true`.
64
- */ validate(value, safe, context) {
65
- this.errors = [];
66
- this.stackErrors = [];
67
- this.stackPath = [""];
68
- this.cachedPath = "";
69
- this.context = context;
70
- const passed = this.validateSafe(this.def, value);
71
- this.pop(!passed);
72
- this.context = undefined;
73
- if (!passed) {
74
- if (safe) return false;
75
- this.throw();
76
- }
77
- return true;
78
- }
79
- validateSafe(def, value) {
80
- if (this.isLimitExceeded()) return false;
81
- if (!isAnnotatedType(def)) throw new Error("Can not validate not-annotated type");
82
- if (typeof this.opts.replace === "function") def = this.opts.replace(def, this.cachedPath);
83
- if (def.optional && value === undefined) return true;
84
- for (const plugin of this.opts.plugins) {
85
- const result = plugin(this, def, value);
86
- if (result === false || result === true) return result;
87
- }
88
- return this.validateAnnotatedType(def, value);
89
- }
90
- get path() {
91
- return this.cachedPath;
92
- }
93
- validateAnnotatedType(def, value) {
94
- switch (def.type.kind) {
95
- case "": {
96
- if (def.type.designType === "phantom") return true;
97
- return this.validatePrimitive(def, value);
98
- }
99
- case "object": return this.validateObject(def, value);
100
- case "array": return this.validateArray(def, value);
101
- case "union": return this.validateUnion(def, value);
102
- case "intersection": return this.validateIntersection(def, value);
103
- case "tuple": return this.validateTuple(def, value);
104
- default: throw new Error(`Unknown type kind "${def.type.kind}"`);
105
- }
106
- }
107
- validateUnion(def, value) {
108
- let i = 0;
109
- const popped = [];
110
- for (const item of def.type.items) {
111
- this.push(`[${item.type.kind || item.type.designType}(${i})]`);
112
- if (this.validateSafe(item, value)) {
113
- this.pop(false);
114
- return true;
115
- }
116
- const errors = this.pop(false);
117
- if (errors) popped.push(...errors);
118
- i++;
119
- }
120
- this.clear();
121
- const expected = def.type.items.map((item, i$1) => `[${item.type.kind || item.type.designType}(${i$1})]`).join(", ");
122
- this.error(`Value does not match any of the allowed types: ${expected}`, undefined, popped);
123
- return false;
124
- }
125
- validateIntersection(def, value) {
126
- for (const item of def.type.items) if (!this.validateSafe(item, value)) return false;
127
- return true;
128
- }
129
- validateTuple(def, value) {
130
- if (!Array.isArray(value) || value.length !== def.type.items.length) {
131
- this.error(`Expected array of length ${def.type.items.length}`);
132
- return false;
133
- }
134
- let i = 0;
135
- for (const item of def.type.items) {
136
- this.push(String(i));
137
- if (!this.validateSafe(item, value[i])) {
138
- this.pop(true);
139
- return false;
140
- }
141
- this.pop(false);
142
- i++;
143
- }
144
- return true;
145
- }
146
- validateArray(def, value) {
147
- if (!Array.isArray(value)) {
148
- this.error("Expected array");
149
- return false;
150
- }
151
- const minLength = def.metadata.get("expect.minLength");
152
- if (minLength) {
153
- const length = typeof minLength === "number" ? minLength : minLength.length;
154
- if (value.length < length) {
155
- const message = typeof minLength === "object" && minLength.message ? minLength.message : `Expected minimum length of ${length} items, got ${value.length} items`;
156
- this.error(message);
157
- return false;
158
- }
159
- }
160
- const maxLength = def.metadata.get("expect.maxLength");
161
- if (maxLength) {
162
- const length = typeof maxLength === "number" ? maxLength : maxLength.length;
163
- if (value.length > length) {
164
- const message = typeof maxLength === "object" && maxLength.message ? maxLength.message : `Expected maximum length of ${length} items, got ${value.length} items`;
165
- this.error(message);
166
- return false;
167
- }
168
- }
169
- const uniqueItems = def.metadata.get("expect.array.uniqueItems");
170
- if (uniqueItems) {
171
- const separator = "▼↩";
172
- const seen = new Set();
173
- const keyProps = new Set();
174
- if (def.type.of.type.kind === "object") {
175
- for (const [key, val] of def.type.of.type.props.entries()) if (val.metadata.get("expect.array.key")) keyProps.add(key);
176
- }
177
- for (let idx = 0; idx < value.length; idx++) {
178
- const item = value[idx];
179
- let key;
180
- if (keyProps.size > 0) {
181
- key = "";
182
- for (const prop of keyProps) key += JSON.stringify(item[prop]) + separator;
183
- } else key = JSON.stringify(item);
184
- if (seen.has(key)) {
185
- this.push(String(idx));
186
- this.error(uniqueItems.message || "Duplicate items are not allowed");
187
- this.pop(true);
188
- return false;
189
- }
190
- seen.add(key);
191
- }
192
- }
193
- let i = 0;
194
- let passed = true;
195
- for (const item of value) {
196
- this.push(String(i));
197
- if (!this.validateSafe(def.type.of, item)) {
198
- passed = false;
199
- this.pop(true);
200
- if (this.isLimitExceeded()) return false;
201
- } else this.pop(false);
202
- i++;
203
- }
204
- return passed;
205
- }
206
- validateObject(def, value) {
207
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
208
- this.error("Expected object");
209
- return false;
210
- }
211
- let passed = true;
212
- const valueKeys = new Set(Object.keys(value));
213
- const typeKeys = new Set();
214
- let skipList;
215
- if (this.opts.skipList) {
216
- const path = this.stackPath.length > 1 ? `${this.cachedPath}.` : "";
217
- for (const item of this.opts.skipList) if (item.startsWith(path)) {
218
- const key = item.slice(path.length);
219
- if (!skipList) skipList = new Set();
220
- skipList.add(key);
221
- valueKeys.delete(key);
222
- }
223
- }
224
- let partialFunctionMatched = false;
225
- if (typeof this.opts.partial === "function") partialFunctionMatched = this.opts.partial(def, this.cachedPath);
226
- for (const [key, item] of def.type.props.entries()) {
227
- if (skipList && skipList.has(key) || isPhantomType(item)) continue;
228
- typeKeys.add(key);
229
- if (value[key] === undefined) {
230
- if (partialFunctionMatched || this.opts.partial === "deep" || this.opts.partial === true && this.stackPath.length <= 1) continue;
231
- }
232
- this.push(key);
233
- if (this.validateSafe(item, value[key])) this.pop(false);
234
- else {
235
- passed = false;
236
- this.pop(true);
237
- if (this.isLimitExceeded()) return false;
238
- }
239
- }
240
- for (const key of valueKeys)
241
- /** matched patterns for unknown keys */ if (!typeKeys.has(key)) {
242
- const matched = [];
243
- for (const { pattern, def: propDef } of def.type.propsPatterns) if (pattern.test(key)) matched.push({
244
- pattern,
245
- def: propDef
246
- });
247
- if (matched.length > 0) {
248
- this.push(key);
249
- let keyPassed = false;
250
- for (const { def: propDef } of matched) {
251
- if (this.validateSafe(propDef, value[key])) {
252
- keyPassed = true;
253
- break;
254
- }
255
- this.clear();
256
- }
257
- if (!keyPassed) {
258
- this.validateSafe(matched[0].def, value[key]);
259
- this.pop(true);
260
- passed = false;
261
- if (this.isLimitExceeded()) return false;
262
- } else this.pop(false);
263
- } else if (this.opts.unknownProps !== "ignore") {
264
- if (this.opts.unknownProps === "error") {
265
- this.push(key);
266
- this.error(`Unexpected property`);
267
- this.pop(true);
268
- if (this.isLimitExceeded()) return false;
269
- passed = false;
270
- } else if (this.opts.unknownProps === "strip") delete value[key];
271
- }
272
- }
273
- return passed;
274
- }
275
- validatePrimitive(def, value) {
276
- if (def.type.value !== undefined) {
277
- if (value !== def.type.value) {
278
- this.error(`Expected ${def.type.value}, got ${value}`);
279
- return false;
280
- }
281
- return true;
282
- }
283
- const typeOfValue = Array.isArray(value) ? "array" : typeof value;
284
- switch (def.type.designType) {
285
- case "never": {
286
- this.error(`This type is impossible, must be an internal problem`);
287
- return false;
288
- }
289
- case "any": return true;
290
- case "string": {
291
- if (typeOfValue !== def.type.designType) {
292
- this.error(`Expected ${def.type.designType}, got ${typeOfValue}`);
293
- return false;
294
- }
295
- return this.validateString(def, value);
296
- }
297
- case "number": {
298
- if (typeOfValue !== def.type.designType) {
299
- this.error(`Expected ${def.type.designType}, got ${typeOfValue}`);
300
- return false;
301
- }
302
- return this.validateNumber(def, value);
303
- }
304
- case "boolean": {
305
- if (typeOfValue !== def.type.designType) {
306
- this.error(`Expected ${def.type.designType}, got ${typeOfValue}`);
307
- return false;
308
- }
309
- return this.validateBoolean(def, value);
310
- }
311
- case "undefined": {
312
- if (value !== undefined) {
313
- this.error(`Expected ${def.type.designType}, got ${typeOfValue}`);
314
- return false;
315
- }
316
- return true;
317
- }
318
- case "null": {
319
- if (value !== null) {
320
- this.error(`Expected ${def.type.designType}, got ${typeOfValue}`);
321
- return false;
322
- }
323
- return true;
324
- }
325
- default: throw new Error(`Unknown type "${def.type.designType}"`);
326
- }
327
- }
328
- validateString(def, value) {
329
- const filled = def.metadata.get("meta.required");
330
- if (filled) {
331
- if (value.trim().length === 0) {
332
- const message = typeof filled === "object" && filled.message ? filled.message : `Must not be empty`;
333
- this.error(message);
334
- return false;
335
- }
336
- }
337
- const minLength = def.metadata.get("expect.minLength");
338
- if (minLength) {
339
- const length = typeof minLength === "number" ? minLength : minLength.length;
340
- if (value.length < length) {
341
- const message = typeof minLength === "object" && minLength.message ? minLength.message : `Expected minimum length of ${length} characters, got ${value.length} characters`;
342
- this.error(message);
343
- return false;
344
- }
345
- }
346
- const maxLength = def.metadata.get("expect.maxLength");
347
- if (maxLength) {
348
- const length = typeof maxLength === "number" ? maxLength : maxLength.length;
349
- if (value.length > length) {
350
- const message = typeof maxLength === "object" && maxLength.message ? maxLength.message : `Expected maximum length of ${length} characters, got ${value.length} characters`;
351
- this.error(message);
352
- return false;
353
- }
354
- }
355
- const patterns = def.metadata.get("expect.pattern");
356
- for (const { pattern, flags, message } of patterns || []) {
357
- if (!pattern) continue;
358
- const cacheKey = `${pattern}//${flags || ""}`;
359
- let regex = regexCache.get(cacheKey);
360
- if (!regex) {
361
- regex = new RegExp(pattern, flags);
362
- regexCache.set(cacheKey, regex);
363
- }
364
- if (!regex.test(value)) {
365
- this.error(message || `Value is expected to match pattern "${pattern}"`);
366
- return false;
367
- }
368
- }
369
- return true;
370
- }
371
- validateNumber(def, value) {
372
- const int = def.metadata.get("expect.int");
373
- if (int && value % 1 !== 0) {
374
- const message = typeof int === "object" && int.message ? int.message : `Expected integer, got ${value}`;
375
- this.error(message);
376
- return false;
377
- }
378
- const min = def.metadata.get("expect.min");
379
- if (min) {
380
- const minValue = typeof min === "number" ? min : min.minValue;
381
- if (value < minValue) {
382
- const message = typeof min === "object" && min.message ? min.message : `Expected minimum ${minValue}, got ${value}`;
383
- this.error(message);
384
- return false;
385
- }
386
- }
387
- const max = def.metadata.get("expect.max");
388
- if (max) {
389
- const maxValue = typeof max === "number" ? max : max.maxValue;
390
- if (value > maxValue) {
391
- const message = typeof max === "object" && max.message ? max.message : `Expected maximum ${maxValue}, got ${value}`;
392
- this.error(message);
393
- return false;
394
- }
395
- }
396
- return true;
397
- }
398
- validateBoolean(def, value) {
399
- const filled = def.metadata.get("meta.required");
400
- if (filled) {
401
- if (value !== true) {
402
- const message = typeof filled === "object" && filled.message ? filled.message : `Must be checked`;
403
- this.error(message);
404
- return false;
405
- }
406
- }
407
- return true;
408
- }
409
- constructor(def, opts) {
410
- _define_property(this, "def", void 0);
411
- _define_property(this, "opts", void 0);
412
- /** Validation errors collected during the last {@link validate} call. */ _define_property(this, "errors", void 0);
413
- _define_property(this, "stackErrors", void 0);
414
- _define_property(this, "stackPath", void 0);
415
- _define_property(this, "cachedPath", void 0);
416
- _define_property(this, "context", void 0);
417
- this.def = def;
418
- this.errors = [];
419
- this.stackErrors = [];
420
- this.stackPath = [];
421
- this.cachedPath = "";
422
- this.opts = {
423
- partial: false,
424
- unknownProps: "error",
425
- errorLimit: 10,
426
- ...opts,
427
- plugins: opts?.plugins || []
428
- };
429
- }
430
- };
431
- var ValidatorError = class extends Error {
432
- constructor(errors) {
433
- 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";
434
- }
435
- };
436
-
437
- //#endregion
438
- //#region packages/typescript/src/annotated-type.ts
439
- const COMPLEX_KINDS = new Set([
440
- "union",
441
- "intersection",
442
- "tuple"
443
- ]);
444
- const NON_PRIMITIVE_KINDS = new Set(["array", "object"]);
445
- /** Shared validator method reused by all annotated type nodes. */ function validatorMethod(opts) {
446
- return new Validator(this, opts);
447
- }
448
- function createAnnotatedTypeNode(type, metadata, opts) {
449
- return {
450
- __is_atscript_annotated_type: true,
451
- type,
452
- metadata,
453
- validator: validatorMethod,
454
- id: opts?.id,
455
- optional: opts?.optional
456
- };
457
- }
458
- function isAnnotatedType(type) {
459
- return type && type.__is_atscript_annotated_type;
460
- }
461
- function annotate(metadata, key, value, asArray) {
462
- if (!metadata) return;
463
- if (asArray) if (metadata.has(key)) {
464
- const a = metadata.get(key);
465
- if (Array.isArray(a)) a.push(value);
466
- else metadata.set(key, [a, value]);
467
- } else metadata.set(key, [value]);
468
- else metadata.set(key, value);
469
- }
470
- function cloneRefProp(parentType, propName) {
471
- if (parentType.kind !== "object") return;
472
- const objType = parentType;
473
- const existing = objType.props.get(propName);
474
- if (!existing) return;
475
- const clonedType = cloneTypeDef(existing.type);
476
- objType.props.set(propName, createAnnotatedTypeNode(clonedType, new Map(existing.metadata), {
477
- id: existing.id,
478
- optional: existing.optional
479
- }));
480
- }
481
- function cloneTypeDef(type) {
482
- if (type.kind === "object") {
483
- const obj = type;
484
- const props = new Map();
485
- for (const [k, v] of obj.props) props.set(k, createAnnotatedTypeNode(v.type, new Map(v.metadata), {
486
- id: v.id,
487
- optional: v.optional
488
- }));
489
- return {
490
- kind: "object",
491
- props,
492
- propsPatterns: [...obj.propsPatterns],
493
- tags: new Set(obj.tags)
494
- };
495
- }
496
- if (type.kind === "array") {
497
- const arr = type;
498
- return {
499
- kind: "array",
500
- of: arr.of,
501
- tags: new Set(arr.tags)
502
- };
503
- }
504
- if (type.kind === "union" || type.kind === "intersection" || type.kind === "tuple") {
505
- const complex = type;
506
- return {
507
- kind: type.kind,
508
- items: [...complex.items],
509
- tags: new Set(complex.tags)
510
- };
511
- }
512
- return {
513
- ...type,
514
- tags: new Set(type.tags)
515
- };
516
- }
517
- function defineAnnotatedType(_kind, base) {
518
- const kind = _kind || "";
519
- const type = base?.type || {};
520
- type.kind = kind;
521
- if (COMPLEX_KINDS.has(kind)) type.items = [];
522
- if (kind === "object") {
523
- type.props = new Map();
524
- type.propsPatterns = [];
525
- }
526
- type.tags = new Set();
527
- const metadata = base?.metadata || new Map();
528
- const payload = {
529
- __is_atscript_annotated_type: true,
530
- metadata,
531
- type,
532
- validator: validatorMethod
533
- };
534
- base = base ? Object.assign(base, payload) : payload;
535
- const handle = {
536
- $type: base,
537
- $def: type,
538
- $metadata: metadata,
539
- tags(...tags) {
540
- for (const tag of tags) this.$def.tags.add(tag);
541
- return this;
542
- },
543
- designType(value) {
544
- this.$def.designType = value;
545
- return this;
546
- },
547
- value(value) {
548
- this.$def.value = value;
549
- return this;
550
- },
551
- of(value) {
552
- this.$def.of = value;
553
- return this;
554
- },
555
- item(value) {
556
- this.$def.items.push(value);
557
- return this;
558
- },
559
- prop(name, value) {
560
- this.$def.props.set(name, value);
561
- return this;
562
- },
563
- propPattern(pattern, def) {
564
- this.$def.propsPatterns.push({
565
- pattern,
566
- def
567
- });
568
- return this;
569
- },
570
- optional(value = true) {
571
- this.$type.optional = value;
572
- return this;
573
- },
574
- copyMetadata(fromMetadata, ignore) {
575
- for (const [key, value] of fromMetadata.entries()) if (!ignore || !ignore.has(key)) this.$metadata.set(key, value);
576
- return this;
577
- },
578
- refTo(type$1, chain) {
579
- if (!isAnnotatedType(type$1)) throw new Error(`${type$1} is not annotated type`);
580
- let newBase = type$1;
581
- const typeName = type$1.name || "Unknown";
582
- if (chain) for (let i = 0; i < chain.length; i++) {
583
- const c = chain[i];
584
- if (newBase.type.kind === "object" && newBase.type.props.has(c)) newBase = newBase.type.props.get(c);
585
- else {
586
- const keys = chain.slice(0, i + 1).map((k) => `["${k}"]`).join("");
587
- throw new Error(`Can't find prop ${typeName}${keys}`);
588
- }
589
- }
590
- this.$type = createAnnotatedTypeNode(newBase.type, metadata, { id: newBase.id });
591
- return this;
592
- },
593
- annotate(key, value, asArray) {
594
- annotate(this.$metadata, key, value, asArray);
595
- return this;
596
- },
597
- id(value) {
598
- this.$type.id = value;
599
- return this;
600
- }
601
- };
602
- return handle;
603
- }
604
- function isPhantomType(def) {
605
- return def.type.kind === "" && def.type.designType === "phantom";
606
- }
607
- function isAnnotatedTypeOfPrimitive(t) {
608
- if (NON_PRIMITIVE_KINDS.has(t.type.kind)) return false;
609
- if (!t.type.kind) return true;
610
- if (COMPLEX_KINDS.has(t.type.kind)) {
611
- for (const item of t.type.items) if (!isAnnotatedTypeOfPrimitive(item)) return false;
612
- return true;
613
- }
614
- return false;
615
- }
616
-
617
- //#endregion
618
- //#region packages/typescript/src/traverse.ts
619
- function forAnnotatedType(def, handlers) {
620
- switch (def.type.kind) {
621
- case "": {
622
- const typed = def;
623
- if (handlers.phantom && typed.type.designType === "phantom") return handlers.phantom(typed);
624
- return handlers.final(typed);
625
- }
626
- case "object": return handlers.object(def);
627
- case "array": return handlers.array(def);
628
- case "union": return handlers.union(def);
629
- case "intersection": return handlers.intersection(def);
630
- case "tuple": return handlers.tuple(def);
631
- default: throw new Error(`Unknown type kind "${def.type.kind}"`);
632
- }
633
- }
634
-
635
- //#endregion
636
- //#region packages/typescript/src/json-schema.ts
637
- /**
638
- * Detects a discriminator property across union items.
639
- *
640
- * Scans all items for object-typed members that share a common property
641
- * with distinct const/literal values. If exactly one such property exists,
642
- * it is returned as the discriminator.
643
- */ function detectDiscriminator(items) {
644
- if (items.length < 2) return null;
645
- for (const item of items) if (item.type.kind !== "object") return null;
646
- const firstObj = items[0].type;
647
- const candidates = [];
648
- for (const [propName, propType] of firstObj.props.entries()) if (propType.type.kind === "" && propType.type.value !== undefined) candidates.push(propName);
649
- let result = null;
650
- for (const candidate of candidates) {
651
- const values = new Set();
652
- const indexMapping = {};
653
- let valid = true;
654
- for (let i = 0; i < items.length; i++) {
655
- const obj = items[i].type;
656
- const prop = obj.props.get(candidate);
657
- if (!prop || prop.type.kind !== "" || prop.type.value === undefined) {
658
- valid = false;
659
- break;
660
- }
661
- const val = prop.type.value;
662
- if (values.has(val)) {
663
- valid = false;
664
- break;
665
- }
666
- values.add(val);
667
- indexMapping[String(val)] = i;
668
- }
669
- if (valid) {
670
- if (result) return null;
671
- result = {
672
- propertyName: candidate,
673
- indexMapping
674
- };
675
- }
676
- }
677
- return result;
678
- }
679
- function buildJsonSchema(type) {
680
- const defs = {};
681
- let hasDefs = false;
682
- const buildObject = (d) => {
683
- const properties = {};
684
- const required = [];
685
- for (const [key, val] of d.type.props.entries()) {
686
- if (isPhantomType(val)) continue;
687
- properties[key] = build$1(val);
688
- if (!val.optional) required.push(key);
689
- }
690
- const schema$1 = {
691
- type: "object",
692
- properties
693
- };
694
- if (required.length > 0) schema$1.required = required;
695
- return schema$1;
696
- };
697
- const build$1 = (def) => {
698
- if (def.id && def.type.kind === "object" && def !== type) {
699
- const name = def.id;
700
- if (!defs[name]) {
701
- hasDefs = true;
702
- defs[name] = {};
703
- defs[name] = buildObject(def);
704
- }
705
- return { $ref: `#/$defs/${name}` };
706
- }
707
- const meta = def.metadata;
708
- return forAnnotatedType(def, {
709
- phantom() {
710
- return {};
711
- },
712
- object(d) {
713
- return buildObject(d);
714
- },
715
- array(d) {
716
- const schema$1 = {
717
- type: "array",
718
- items: build$1(d.type.of)
719
- };
720
- const minLength = meta.get("expect.minLength");
721
- if (minLength) schema$1.minItems = typeof minLength === "number" ? minLength : minLength.length;
722
- const maxLength = meta.get("expect.maxLength");
723
- if (maxLength) schema$1.maxItems = typeof maxLength === "number" ? maxLength : maxLength.length;
724
- return schema$1;
725
- },
726
- union(d) {
727
- const disc = detectDiscriminator(d.type.items);
728
- if (disc) {
729
- const oneOf = d.type.items.map(build$1);
730
- const mapping = {};
731
- for (const [val, idx] of Object.entries(disc.indexMapping)) {
732
- const item = d.type.items[idx];
733
- mapping[val] = item.id && defs[item.id] ? `#/$defs/${item.id}` : `#/oneOf/${idx}`;
734
- }
735
- return {
736
- oneOf,
737
- discriminator: {
738
- propertyName: disc.propertyName,
739
- mapping
740
- }
741
- };
742
- }
743
- return { anyOf: d.type.items.map(build$1) };
744
- },
745
- intersection(d) {
746
- return { allOf: d.type.items.map(build$1) };
747
- },
748
- tuple(d) {
749
- return {
750
- type: "array",
751
- items: d.type.items.map(build$1),
752
- additionalItems: false
753
- };
754
- },
755
- final(d) {
756
- const schema$1 = {};
757
- if (d.type.value !== undefined) schema$1.const = d.type.value;
758
- if (d.type.designType && d.type.designType !== "any") {
759
- schema$1.type = d.type.designType === "undefined" ? "null" : d.type.designType;
760
- if (schema$1.type === "number" && meta.get("expect.int")) schema$1.type = "integer";
761
- }
762
- if (schema$1.type === "string") {
763
- if (meta.get("meta.required")) schema$1.minLength = 1;
764
- const minLength = meta.get("expect.minLength");
765
- if (minLength) schema$1.minLength = typeof minLength === "number" ? minLength : minLength.length;
766
- const maxLength = meta.get("expect.maxLength");
767
- if (maxLength) schema$1.maxLength = typeof maxLength === "number" ? maxLength : maxLength.length;
768
- const patterns = meta.get("expect.pattern");
769
- if (patterns?.length) if (patterns.length === 1) schema$1.pattern = patterns[0].pattern;
770
- else schema$1.allOf = (schema$1.allOf || []).concat(patterns.map((p) => ({ pattern: p.pattern })));
771
- }
772
- if (schema$1.type === "number" || schema$1.type === "integer") {
773
- const min = meta.get("expect.min");
774
- if (min) schema$1.minimum = typeof min === "number" ? min : min.minValue;
775
- const max = meta.get("expect.max");
776
- if (max) schema$1.maximum = typeof max === "number" ? max : max.maxValue;
777
- }
778
- return schema$1;
779
- }
780
- });
781
- };
782
- const schema = build$1(type);
783
- if (hasDefs) return {
784
- ...schema,
785
- $defs: defs
786
- };
787
- return schema;
788
- }
789
- function fromJsonSchema(schema) {
790
- const defsSource = schema.$defs || schema.definitions || {};
791
- const resolved = new Map();
792
- const convert = (s) => {
793
- if (!s || Object.keys(s).length === 0) return defineAnnotatedType().designType("any").$type;
794
- if (s.$ref) {
795
- const refName = s.$ref.replace(/^#\/(\$defs|definitions)\//, "");
796
- if (resolved.has(refName)) return resolved.get(refName);
797
- if (defsSource[refName]) {
798
- const placeholder = defineAnnotatedType().designType("any").$type;
799
- resolved.set(refName, placeholder);
800
- const type = convert(defsSource[refName]);
801
- resolved.set(refName, type);
802
- return type;
803
- }
804
- throw new Error(`Unresolvable $ref: ${s.$ref}`);
805
- }
806
- if ("const" in s) {
807
- const val = s.const;
808
- const dt = val === null ? "null" : typeof val;
809
- return defineAnnotatedType().designType(dt).value(val).$type;
810
- }
811
- if (s.enum) {
812
- const handle = defineAnnotatedType("union");
813
- for (const val of s.enum) {
814
- const dt = val === null ? "null" : typeof val;
815
- handle.item(defineAnnotatedType().designType(dt).value(val).$type);
816
- }
817
- return handle.$type;
818
- }
819
- if (s.anyOf) {
820
- const handle = defineAnnotatedType("union");
821
- for (const item of s.anyOf) handle.item(convert(item));
822
- return handle.$type;
823
- }
824
- if (s.oneOf) {
825
- const handle = defineAnnotatedType("union");
826
- for (const item of s.oneOf) handle.item(convert(item));
827
- return handle.$type;
828
- }
829
- if (s.allOf && !s.type) {
830
- const handle = defineAnnotatedType("intersection");
831
- for (const item of s.allOf) handle.item(convert(item));
832
- return handle.$type;
833
- }
834
- if (Array.isArray(s.type)) {
835
- const handle = defineAnnotatedType("union");
836
- for (const t of s.type) handle.item(convert({
837
- ...s,
838
- type: t
839
- }));
840
- return handle.$type;
841
- }
842
- if (s.type === "object") {
843
- const handle = defineAnnotatedType("object");
844
- const required = new Set(s.required || []);
845
- if (s.properties) for (const [key, propSchema] of Object.entries(s.properties)) {
846
- const propType = convert(propSchema);
847
- if (!required.has(key)) propType.optional = true;
848
- handle.prop(key, propType);
849
- }
850
- return handle.$type;
851
- }
852
- if (s.type === "array") {
853
- if (Array.isArray(s.items)) {
854
- const handle$1 = defineAnnotatedType("tuple");
855
- for (const item of s.items) handle$1.item(convert(item));
856
- return handle$1.$type;
857
- }
858
- const itemType = s.items ? convert(s.items) : defineAnnotatedType().designType("any").$type;
859
- const handle = defineAnnotatedType("array").of(itemType);
860
- if (typeof s.minItems === "number") handle.annotate("expect.minLength", { length: s.minItems });
861
- if (typeof s.maxItems === "number") handle.annotate("expect.maxLength", { length: s.maxItems });
862
- return handle.$type;
863
- }
864
- if (s.type === "string") {
865
- const handle = defineAnnotatedType().designType("string").tags("string");
866
- if (typeof s.minLength === "number") handle.annotate("expect.minLength", { length: s.minLength });
867
- if (typeof s.maxLength === "number") handle.annotate("expect.maxLength", { length: s.maxLength });
868
- if (s.pattern) handle.annotate("expect.pattern", { pattern: s.pattern }, true);
869
- if (s.allOf) {
870
- for (const item of s.allOf) if (item.pattern) handle.annotate("expect.pattern", { pattern: item.pattern }, true);
871
- }
872
- return handle.$type;
873
- }
874
- if (s.type === "integer") {
875
- const handle = defineAnnotatedType().designType("number").tags("number");
876
- handle.annotate("expect.int", true);
877
- if (typeof s.minimum === "number") handle.annotate("expect.min", { minValue: s.minimum });
878
- if (typeof s.maximum === "number") handle.annotate("expect.max", { maxValue: s.maximum });
879
- return handle.$type;
880
- }
881
- if (s.type === "number") {
882
- const handle = defineAnnotatedType().designType("number").tags("number");
883
- if (typeof s.minimum === "number") handle.annotate("expect.min", { minValue: s.minimum });
884
- if (typeof s.maximum === "number") handle.annotate("expect.max", { maxValue: s.maximum });
885
- return handle.$type;
886
- }
887
- if (s.type === "boolean") return defineAnnotatedType().designType("boolean").tags("boolean").$type;
888
- if (s.type === "null") return defineAnnotatedType().designType("null").tags("null").$type;
889
- return defineAnnotatedType().designType("any").$type;
890
- };
891
- return convert(schema);
892
- }
893
- function mergeJsonSchemas(types) {
894
- const mergedDefs = {};
895
- const schemas = {};
896
- for (const type of types) {
897
- const name = type.id;
898
- if (!name) throw new Error("mergeJsonSchemas: all types must have an id");
899
- const schema = buildJsonSchema(type);
900
- if (schema.$defs) {
901
- for (const [defName, defSchema] of Object.entries(schema.$defs)) if (!mergedDefs[defName]) mergedDefs[defName] = defSchema;
902
- const { $defs: _,...rest } = schema;
903
- schemas[name] = rest;
904
- } else schemas[name] = schema;
905
- }
906
- return {
907
- schemas,
908
- $defs: mergedDefs
909
- };
910
- }
911
-
912
- //#endregion
913
4
  //#region packages/typescript/src/default-value.ts
914
5
  /**
915
6
  * Attempts to resolve a value from the mode for the given annotated type.
@@ -924,7 +15,7 @@ function mergeJsonSchemas(types) {
924
15
  return undefined;
925
16
  }
926
17
  if (mode === "db") {
927
- const dbValue = prop.metadata.get("db.default.value");
18
+ const dbValue = prop.metadata.get("db.default");
928
19
  if (dbValue !== undefined) {
929
20
  const parsed$1 = parseRawValue(dbValue, prop);
930
21
  if (parsed$1 !== undefined && prop.validator({ unknownProps: "ignore" }).validate(parsed$1, true)) return { value: parsed$1 };
@@ -970,13 +61,13 @@ function createDataFromAnnotatedType(type, opts) {
970
61
  function build(def, path, mode) {
971
62
  const resolved = resolveValue(def, path, mode);
972
63
  if (resolved !== undefined) return resolved.value;
973
- return forAnnotatedType(def, {
64
+ return require_json_schema.forAnnotatedType(def, {
974
65
  phantom: () => undefined,
975
66
  final: (d) => finalDefault(d),
976
67
  object: (d) => {
977
68
  const data = {};
978
69
  for (const [key, prop] of d.type.props.entries()) {
979
- if (isPhantomType(prop)) continue;
70
+ if (require_json_schema.isPhantomType(prop)) continue;
980
71
  const childPath = path ? `${path}.${key}` : key;
981
72
  if (prop.optional) {
982
73
  if (mode === "example") data[key] = build(prop, childPath, mode);
@@ -1020,10 +111,11 @@ function throwFeatureDisabled(feature, option, annotation) {
1020
111
  function flattenAnnotatedType(type, options) {
1021
112
  const flatMap = new Map();
1022
113
  const skipPhantom = !!options?.excludePhantomTypes;
114
+ const visitedIds = new Set();
1023
115
  function addFieldToFlatMap(name, def) {
1024
116
  const existing = flatMap.get(name);
1025
117
  if (existing) {
1026
- const flatUnion = defineAnnotatedType("union").copyMetadata(existing.metadata).copyMetadata(def.metadata);
118
+ const flatUnion = require_json_schema.defineAnnotatedType("union").copyMetadata(existing.metadata).copyMetadata(def.metadata);
1027
119
  if (existing.__flat_union) existing.type.items.forEach((item) => flatUnion.item(item));
1028
120
  else flatUnion.item(existing);
1029
121
  flatUnion.item(def);
@@ -1033,11 +125,20 @@ else flatUnion.item(existing);
1033
125
  } else flatMap.set(name, def);
1034
126
  }
1035
127
  function flattenArray(def, name) {
128
+ const resolvedId = def.id;
129
+ if (resolvedId) {
130
+ if (visitedIds.has(resolvedId)) return;
131
+ visitedIds.add(resolvedId);
132
+ }
1036
133
  switch (def.type.kind) {
1037
134
  case "object": {
135
+ if (!resolvedId && def.id) {
136
+ if (visitedIds.has(def.id)) return;
137
+ visitedIds.add(def.id);
138
+ }
1038
139
  const items = Array.from(def.type.props.entries());
1039
140
  for (const [key, value] of items) {
1040
- if (skipPhantom && isPhantomType(value)) continue;
141
+ if (skipPhantom && require_json_schema.isPhantomType(value)) continue;
1041
142
  flattenType(value, name ? `${name}.${key}` : key, true);
1042
143
  }
1043
144
  break;
@@ -1056,11 +157,28 @@ else flatUnion.item(existing);
1056
157
  }
1057
158
  }
1058
159
  function flattenType(def, prefix = "", inComplexTypeOrArray = false) {
1059
- switch (def.type.kind) {
160
+ let typeId = def.id;
161
+ if (typeId && visitedIds.has(typeId)) {
162
+ addFieldToFlatMap(prefix || "", def);
163
+ if (prefix) options?.onField?.(prefix, def, def.metadata);
164
+ return;
165
+ }
166
+ if (typeId) visitedIds.add(typeId);
167
+ const kind = def.type.kind;
168
+ if (!typeId && def.id) {
169
+ typeId = def.id;
170
+ if (visitedIds.has(typeId)) {
171
+ addFieldToFlatMap(prefix || "", def);
172
+ if (prefix) options?.onField?.(prefix, def, def.metadata);
173
+ return;
174
+ }
175
+ visitedIds.add(typeId);
176
+ }
177
+ switch (kind) {
1060
178
  case "object": {
1061
179
  addFieldToFlatMap(prefix || "", def);
1062
180
  for (const [key, value] of def.type.props.entries()) {
1063
- if (skipPhantom && isPhantomType(value)) continue;
181
+ if (skipPhantom && require_json_schema.isPhantomType(value)) continue;
1064
182
  flattenType(value, prefix ? `${prefix}.${key}` : key, inComplexTypeOrArray);
1065
183
  }
1066
184
  break;
@@ -1068,12 +186,12 @@ else flatUnion.item(existing);
1068
186
  case "array": {
1069
187
  let typeArray = def;
1070
188
  if (!inComplexTypeOrArray) {
1071
- typeArray = defineAnnotatedType().refTo(def).copyMetadata(def.metadata).$type;
189
+ typeArray = require_json_schema.defineAnnotatedType().refTo(def).copyMetadata(def.metadata).$type;
1072
190
  if (def.optional) typeArray.optional = def.optional;
1073
191
  if (options?.topLevelArrayTag) typeArray.metadata.set(options.topLevelArrayTag, true);
1074
192
  }
1075
193
  addFieldToFlatMap(prefix || "", typeArray);
1076
- if (!isAnnotatedTypeOfPrimitive(typeArray.type.of)) flattenArray(typeArray.type.of, prefix);
194
+ if (!require_json_schema.isAnnotatedTypeOfPrimitive(typeArray.type.of)) flattenArray(typeArray.type.of, prefix);
1077
195
  break;
1078
196
  }
1079
197
  case "intersection":
@@ -1102,21 +220,32 @@ else flatUnion.item(existing);
1102
220
  //#region packages/typescript/src/serialize.ts
1103
221
  const SERIALIZE_VERSION = 1;
1104
222
  function serializeAnnotatedType(type, options) {
1105
- const result = serializeNode(type, [], options);
223
+ const visited = new Set();
224
+ const result = serializeNode(type, [], options, visited);
1106
225
  result.$v = SERIALIZE_VERSION;
1107
226
  return result;
1108
227
  }
1109
- function serializeNode(def, path, options) {
228
+ function serializeNode(def, path, options, visited) {
229
+ if (def.id && visited.has(def.id)) return {
230
+ type: {
231
+ kind: "$ref",
232
+ id: def.id
233
+ },
234
+ metadata: {},
235
+ ...def.optional ? { optional: true } : {},
236
+ id: def.id
237
+ };
238
+ if (def.id) visited.add(def.id);
1110
239
  const result = {
1111
- type: serializeTypeDef(def, path, options),
240
+ type: serializeTypeDef(def, path, options, visited),
1112
241
  metadata: serializeMetadata(def.metadata, path, def.type.kind, options)
1113
242
  };
1114
243
  if (def.optional) result.optional = true;
1115
244
  if (def.id) result.id = def.id;
1116
245
  return result;
1117
246
  }
1118
- function serializeTypeDef(def, path, options) {
1119
- return forAnnotatedType(def, {
247
+ function serializeTypeDef(def, path, options, visited) {
248
+ return require_json_schema.forAnnotatedType(def, {
1120
249
  phantom(d) {
1121
250
  return {
1122
251
  kind: "",
@@ -1135,13 +264,13 @@ function serializeTypeDef(def, path, options) {
1135
264
  },
1136
265
  object(d) {
1137
266
  const props = {};
1138
- for (const [key, val] of d.type.props.entries()) props[key] = serializeNode(val, [...path, key], options);
267
+ for (const [key, val] of d.type.props.entries()) props[key] = serializeNode(val, [...path, key], options, visited);
1139
268
  const propsPatterns = d.type.propsPatterns.map((pp) => ({
1140
269
  pattern: {
1141
270
  source: pp.pattern.source,
1142
271
  flags: pp.pattern.flags
1143
272
  },
1144
- def: serializeNode(pp.def, path, options)
273
+ def: serializeNode(pp.def, path, options, visited)
1145
274
  }));
1146
275
  return {
1147
276
  kind: "object",
@@ -1153,28 +282,28 @@ function serializeTypeDef(def, path, options) {
1153
282
  array(d) {
1154
283
  return {
1155
284
  kind: "array",
1156
- of: serializeNode(d.type.of, path, options),
285
+ of: serializeNode(d.type.of, path, options, visited),
1157
286
  tags: Array.from(d.type.tags)
1158
287
  };
1159
288
  },
1160
289
  union(d) {
1161
290
  return {
1162
291
  kind: "union",
1163
- items: d.type.items.map((item) => serializeNode(item, path, options)),
292
+ items: d.type.items.map((item) => serializeNode(item, path, options, visited)),
1164
293
  tags: Array.from(d.type.tags)
1165
294
  };
1166
295
  },
1167
296
  intersection(d) {
1168
297
  return {
1169
298
  kind: "intersection",
1170
- items: d.type.items.map((item) => serializeNode(item, path, options)),
299
+ items: d.type.items.map((item) => serializeNode(item, path, options, visited)),
1171
300
  tags: Array.from(d.type.tags)
1172
301
  };
1173
302
  },
1174
303
  tuple(d) {
1175
304
  return {
1176
305
  kind: "tuple",
1177
- items: d.type.items.map((item) => serializeNode(item, path, options)),
306
+ items: d.type.items.map((item) => serializeNode(item, path, options, visited)),
1178
307
  tags: Array.from(d.type.tags)
1179
308
  };
1180
309
  }
@@ -1207,14 +336,14 @@ function deserializeAnnotatedType(data) {
1207
336
  function deserializeNode(data) {
1208
337
  const metadata = new Map(Object.entries(data.metadata));
1209
338
  const type = deserializeTypeDef(data.type);
1210
- const result = createAnnotatedTypeNode(type, metadata, {
339
+ const result = require_json_schema.createAnnotatedTypeNode(type, metadata, {
1211
340
  optional: data.optional || undefined,
1212
341
  id: data.id || undefined
1213
342
  });
1214
343
  return result;
1215
344
  }
1216
345
  function deserializeTypeDef(t) {
1217
- const tags = new Set(t.tags);
346
+ const tags = "tags" in t ? new Set(t.tags) : new Set();
1218
347
  switch (t.kind) {
1219
348
  case "": {
1220
349
  const result = {
@@ -1251,27 +380,33 @@ function deserializeTypeDef(t) {
1251
380
  items: t.items.map((item) => deserializeNode(item)),
1252
381
  tags
1253
382
  };
383
+ case "$ref": return {
384
+ kind: "object",
385
+ props: new Map(),
386
+ propsPatterns: [],
387
+ tags
388
+ };
1254
389
  default: throw new Error(`Unknown serialized type kind "${t.kind}"`);
1255
390
  }
1256
391
  }
1257
392
 
1258
393
  //#endregion
1259
394
  exports.SERIALIZE_VERSION = SERIALIZE_VERSION
1260
- exports.Validator = Validator
1261
- exports.ValidatorError = ValidatorError
1262
- exports.annotate = annotate
1263
- exports.buildJsonSchema = buildJsonSchema
1264
- exports.cloneRefProp = cloneRefProp
1265
- exports.createAnnotatedTypeNode = createAnnotatedTypeNode
395
+ exports.Validator = require_json_schema.Validator
396
+ exports.ValidatorError = require_json_schema.ValidatorError
397
+ exports.annotate = require_json_schema.annotate
398
+ exports.buildJsonSchema = require_json_schema.buildJsonSchema
399
+ exports.cloneRefProp = require_json_schema.cloneRefProp
400
+ exports.createAnnotatedTypeNode = require_json_schema.createAnnotatedTypeNode
1266
401
  exports.createDataFromAnnotatedType = createDataFromAnnotatedType
1267
- exports.defineAnnotatedType = defineAnnotatedType
402
+ exports.defineAnnotatedType = require_json_schema.defineAnnotatedType
1268
403
  exports.deserializeAnnotatedType = deserializeAnnotatedType
1269
404
  exports.flattenAnnotatedType = flattenAnnotatedType
1270
- exports.forAnnotatedType = forAnnotatedType
1271
- exports.fromJsonSchema = fromJsonSchema
1272
- exports.isAnnotatedType = isAnnotatedType
1273
- exports.isAnnotatedTypeOfPrimitive = isAnnotatedTypeOfPrimitive
1274
- exports.isPhantomType = isPhantomType
1275
- exports.mergeJsonSchemas = mergeJsonSchemas
405
+ exports.forAnnotatedType = require_json_schema.forAnnotatedType
406
+ exports.fromJsonSchema = require_json_schema.fromJsonSchema
407
+ exports.isAnnotatedType = require_json_schema.isAnnotatedType
408
+ exports.isAnnotatedTypeOfPrimitive = require_json_schema.isAnnotatedTypeOfPrimitive
409
+ exports.isPhantomType = require_json_schema.isPhantomType
410
+ exports.mergeJsonSchemas = require_json_schema.mergeJsonSchemas
1276
411
  exports.serializeAnnotatedType = serializeAnnotatedType
1277
412
  exports.throwFeatureDisabled = throwFeatureDisabled