@atscript/typescript 0.1.1 → 0.1.3
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 +252 -133
- package/dist/index.cjs +252 -133
- package/dist/index.d.ts +8 -2
- package/dist/index.mjs +252 -133
- package/dist/utils.cjs +317 -47
- package/dist/utils.d.ts +280 -12
- package/dist/utils.mjs +311 -47
- package/package.json +2 -2
package/dist/utils.cjs
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
+
//#region packages/typescript/src/traverse.ts
|
|
4
|
+
function forAnnotatedType(def, handlers) {
|
|
5
|
+
switch (def.type.kind) {
|
|
6
|
+
case "": return handlers.final(def);
|
|
7
|
+
case "object": return handlers.object(def);
|
|
8
|
+
case "array": return handlers.array(def);
|
|
9
|
+
case "union": return handlers.union(def);
|
|
10
|
+
case "intersection": return handlers.intersection(def);
|
|
11
|
+
case "tuple": return handlers.tuple(def);
|
|
12
|
+
default: throw new Error(`Unknown type kind "${def.type.kind}"`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
3
17
|
//#region packages/typescript/src/validator.ts
|
|
4
18
|
function _define_property(obj, key, value) {
|
|
5
19
|
if (key in obj) Object.defineProperty(obj, key, {
|
|
@@ -44,7 +58,17 @@ var Validator = class {
|
|
|
44
58
|
throw() {
|
|
45
59
|
throw new ValidatorError(this.errors);
|
|
46
60
|
}
|
|
47
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Validates a value against the type definition.
|
|
63
|
+
*
|
|
64
|
+
* Acts as a TypeScript type guard — when it returns `true`, the value
|
|
65
|
+
* is narrowed to `DataType`.
|
|
66
|
+
*
|
|
67
|
+
* @param value - The value to validate.
|
|
68
|
+
* @param safe - If `true`, returns `false` on failure instead of throwing.
|
|
69
|
+
* @returns `true` if the value matches the type definition.
|
|
70
|
+
* @throws {ValidatorError} When validation fails and `safe` is not `true`.
|
|
71
|
+
*/ validate(value, safe) {
|
|
48
72
|
this.push("");
|
|
49
73
|
this.errors = [];
|
|
50
74
|
this.stackErrors = [];
|
|
@@ -71,15 +95,14 @@ var Validator = class {
|
|
|
71
95
|
return this.stackPath.slice(1).join(".");
|
|
72
96
|
}
|
|
73
97
|
validateAnnotatedType(def, value) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
98
|
+
return forAnnotatedType(def, {
|
|
99
|
+
final: (d) => this.validatePrimitive(d, value),
|
|
100
|
+
object: (d) => this.validateObject(d, value),
|
|
101
|
+
array: (d) => this.validateArray(d, value),
|
|
102
|
+
union: (d) => this.validateUnion(d, value),
|
|
103
|
+
intersection: (d) => this.validateIntersection(d, value),
|
|
104
|
+
tuple: (d) => this.validateTuple(d, value)
|
|
105
|
+
});
|
|
83
106
|
}
|
|
84
107
|
validateUnion(def, value) {
|
|
85
108
|
let i = 0;
|
|
@@ -311,7 +334,7 @@ else {
|
|
|
311
334
|
constructor(def, opts) {
|
|
312
335
|
_define_property(this, "def", void 0);
|
|
313
336
|
_define_property(this, "opts", void 0);
|
|
314
|
-
_define_property(this, "errors", void 0);
|
|
337
|
+
/** Validation errors collected during the last {@link validate} call. */ _define_property(this, "errors", void 0);
|
|
315
338
|
_define_property(this, "stackErrors", void 0);
|
|
316
339
|
_define_property(this, "stackPath", void 0);
|
|
317
340
|
this.def = def;
|
|
@@ -338,6 +361,15 @@ var ValidatorError = class extends Error {
|
|
|
338
361
|
function isAnnotatedType(type) {
|
|
339
362
|
return type && type.__is_atscript_annotated_type;
|
|
340
363
|
}
|
|
364
|
+
function annotate(metadata, key, value, asArray) {
|
|
365
|
+
if (!metadata) return;
|
|
366
|
+
if (asArray) if (metadata.has(key)) {
|
|
367
|
+
const a = metadata.get(key);
|
|
368
|
+
if (Array.isArray(a)) a.push(value);
|
|
369
|
+
else metadata.set(key, [a, value]);
|
|
370
|
+
} else metadata.set(key, [value]);
|
|
371
|
+
else metadata.set(key, value);
|
|
372
|
+
}
|
|
341
373
|
function defineAnnotatedType(_kind, base) {
|
|
342
374
|
const kind = _kind || "";
|
|
343
375
|
const type = base?.type || {};
|
|
@@ -437,12 +469,7 @@ else if (!newBase) throw new Error(`"${typeName}" is not annotated type`);
|
|
|
437
469
|
return this;
|
|
438
470
|
},
|
|
439
471
|
annotate(key, value, asArray) {
|
|
440
|
-
|
|
441
|
-
const a = this.$metadata.get(key);
|
|
442
|
-
if (Array.isArray(a)) a.push(value);
|
|
443
|
-
else this.$metadata.set(key, [a, value]);
|
|
444
|
-
} else this.$metadata.set(key, [value]);
|
|
445
|
-
else this.$metadata.set(key, value);
|
|
472
|
+
annotate(this.$metadata, key, value, asArray);
|
|
446
473
|
return this;
|
|
447
474
|
}
|
|
448
475
|
};
|
|
@@ -466,14 +493,12 @@ function isAnnotatedTypeOfPrimitive(t) {
|
|
|
466
493
|
//#region packages/typescript/src/json-schema.ts
|
|
467
494
|
function buildJsonSchema(type) {
|
|
468
495
|
const build = (def) => {
|
|
469
|
-
const t = def.type;
|
|
470
496
|
const meta = def.metadata;
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
const obj = t;
|
|
497
|
+
return forAnnotatedType(def, {
|
|
498
|
+
object(d) {
|
|
474
499
|
const properties = {};
|
|
475
500
|
const required = [];
|
|
476
|
-
for (const [key, val] of
|
|
501
|
+
for (const [key, val] of d.type.props.entries()) {
|
|
477
502
|
properties[key] = build(val);
|
|
478
503
|
if (!val.optional) required.push(key);
|
|
479
504
|
}
|
|
@@ -483,41 +508,36 @@ function buildJsonSchema(type) {
|
|
|
483
508
|
};
|
|
484
509
|
if (required.length) schema.required = required;
|
|
485
510
|
return schema;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
const arr = t;
|
|
511
|
+
},
|
|
512
|
+
array(d) {
|
|
489
513
|
const schema = {
|
|
490
514
|
type: "array",
|
|
491
|
-
items: build(
|
|
515
|
+
items: build(d.type.of)
|
|
492
516
|
};
|
|
493
517
|
const minLength = meta.get("expect.minLength");
|
|
494
518
|
if (typeof minLength === "number") schema.minItems = minLength;
|
|
495
519
|
const maxLength = meta.get("expect.maxLength");
|
|
496
520
|
if (typeof maxLength === "number") schema.maxItems = maxLength;
|
|
497
521
|
return schema;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
}
|
|
507
|
-
case "tuple": {
|
|
508
|
-
const grp = t;
|
|
522
|
+
},
|
|
523
|
+
union(d) {
|
|
524
|
+
return { anyOf: d.type.items.map(build) };
|
|
525
|
+
},
|
|
526
|
+
intersection(d) {
|
|
527
|
+
return { allOf: d.type.items.map(build) };
|
|
528
|
+
},
|
|
529
|
+
tuple(d) {
|
|
509
530
|
return {
|
|
510
531
|
type: "array",
|
|
511
|
-
items:
|
|
532
|
+
items: d.type.items.map(build),
|
|
512
533
|
additionalItems: false
|
|
513
534
|
};
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
const fin = t;
|
|
535
|
+
},
|
|
536
|
+
final(d) {
|
|
517
537
|
const schema = {};
|
|
518
|
-
if (
|
|
519
|
-
if (
|
|
520
|
-
schema.type =
|
|
538
|
+
if (d.type.value !== undefined) schema.const = d.type.value;
|
|
539
|
+
if (d.type.designType && d.type.designType !== "any") {
|
|
540
|
+
schema.type = d.type.designType === "undefined" ? "null" : d.type.designType;
|
|
521
541
|
if (schema.type === "number" && meta.get("expect.int")) schema.type = "integer";
|
|
522
542
|
}
|
|
523
543
|
if (schema.type === "string") {
|
|
@@ -537,16 +557,266 @@ else schema.allOf = (schema.allOf || []).concat(patterns.map((p) => ({ pattern:
|
|
|
537
557
|
}
|
|
538
558
|
return schema;
|
|
539
559
|
}
|
|
540
|
-
|
|
541
|
-
}
|
|
560
|
+
});
|
|
542
561
|
};
|
|
543
562
|
return build(type);
|
|
544
563
|
}
|
|
564
|
+
function fromJsonSchema(schema) {
|
|
565
|
+
const convert = (s) => {
|
|
566
|
+
if (!s || Object.keys(s).length === 0) return defineAnnotatedType().designType("any").$type;
|
|
567
|
+
if (s.$ref) throw new Error("$ref is not supported by fromJsonSchema. Dereference the schema first.");
|
|
568
|
+
if ("const" in s) {
|
|
569
|
+
const val = s.const;
|
|
570
|
+
const dt = val === null ? "null" : typeof val;
|
|
571
|
+
return defineAnnotatedType().designType(dt).value(val).$type;
|
|
572
|
+
}
|
|
573
|
+
if (s.enum) {
|
|
574
|
+
const handle = defineAnnotatedType("union");
|
|
575
|
+
for (const val of s.enum) {
|
|
576
|
+
const dt = val === null ? "null" : typeof val;
|
|
577
|
+
handle.item(defineAnnotatedType().designType(dt).value(val).$type);
|
|
578
|
+
}
|
|
579
|
+
return handle.$type;
|
|
580
|
+
}
|
|
581
|
+
if (s.anyOf) {
|
|
582
|
+
const handle = defineAnnotatedType("union");
|
|
583
|
+
for (const item of s.anyOf) handle.item(convert(item));
|
|
584
|
+
return handle.$type;
|
|
585
|
+
}
|
|
586
|
+
if (s.oneOf) {
|
|
587
|
+
const handle = defineAnnotatedType("union");
|
|
588
|
+
for (const item of s.oneOf) handle.item(convert(item));
|
|
589
|
+
return handle.$type;
|
|
590
|
+
}
|
|
591
|
+
if (s.allOf && !s.type) {
|
|
592
|
+
const handle = defineAnnotatedType("intersection");
|
|
593
|
+
for (const item of s.allOf) handle.item(convert(item));
|
|
594
|
+
return handle.$type;
|
|
595
|
+
}
|
|
596
|
+
if (Array.isArray(s.type)) {
|
|
597
|
+
const handle = defineAnnotatedType("union");
|
|
598
|
+
for (const t of s.type) handle.item(convert({
|
|
599
|
+
...s,
|
|
600
|
+
type: t
|
|
601
|
+
}));
|
|
602
|
+
return handle.$type;
|
|
603
|
+
}
|
|
604
|
+
if (s.type === "object") {
|
|
605
|
+
const handle = defineAnnotatedType("object");
|
|
606
|
+
const required = new Set(s.required || []);
|
|
607
|
+
if (s.properties) for (const [key, propSchema] of Object.entries(s.properties)) {
|
|
608
|
+
const propType = convert(propSchema);
|
|
609
|
+
if (!required.has(key)) propType.optional = true;
|
|
610
|
+
handle.prop(key, propType);
|
|
611
|
+
}
|
|
612
|
+
return handle.$type;
|
|
613
|
+
}
|
|
614
|
+
if (s.type === "array") {
|
|
615
|
+
if (Array.isArray(s.items)) {
|
|
616
|
+
const handle$1 = defineAnnotatedType("tuple");
|
|
617
|
+
for (const item of s.items) handle$1.item(convert(item));
|
|
618
|
+
return handle$1.$type;
|
|
619
|
+
}
|
|
620
|
+
const itemType = s.items ? convert(s.items) : defineAnnotatedType().designType("any").$type;
|
|
621
|
+
const handle = defineAnnotatedType("array").of(itemType);
|
|
622
|
+
if (typeof s.minItems === "number") handle.annotate("expect.minLength", s.minItems);
|
|
623
|
+
if (typeof s.maxItems === "number") handle.annotate("expect.maxLength", s.maxItems);
|
|
624
|
+
return handle.$type;
|
|
625
|
+
}
|
|
626
|
+
if (s.type === "string") {
|
|
627
|
+
const handle = defineAnnotatedType().designType("string").tags("string");
|
|
628
|
+
if (typeof s.minLength === "number") handle.annotate("expect.minLength", s.minLength);
|
|
629
|
+
if (typeof s.maxLength === "number") handle.annotate("expect.maxLength", s.maxLength);
|
|
630
|
+
if (s.pattern) handle.annotate("expect.pattern", { pattern: s.pattern }, true);
|
|
631
|
+
if (s.allOf) {
|
|
632
|
+
for (const item of s.allOf) if (item.pattern) handle.annotate("expect.pattern", { pattern: item.pattern }, true);
|
|
633
|
+
}
|
|
634
|
+
return handle.$type;
|
|
635
|
+
}
|
|
636
|
+
if (s.type === "integer") {
|
|
637
|
+
const handle = defineAnnotatedType().designType("number").tags("number");
|
|
638
|
+
handle.annotate("expect.int", true);
|
|
639
|
+
if (typeof s.minimum === "number") handle.annotate("expect.min", s.minimum);
|
|
640
|
+
if (typeof s.maximum === "number") handle.annotate("expect.max", s.maximum);
|
|
641
|
+
return handle.$type;
|
|
642
|
+
}
|
|
643
|
+
if (s.type === "number") {
|
|
644
|
+
const handle = defineAnnotatedType().designType("number").tags("number");
|
|
645
|
+
if (typeof s.minimum === "number") handle.annotate("expect.min", s.minimum);
|
|
646
|
+
if (typeof s.maximum === "number") handle.annotate("expect.max", s.maximum);
|
|
647
|
+
return handle.$type;
|
|
648
|
+
}
|
|
649
|
+
if (s.type === "boolean") return defineAnnotatedType().designType("boolean").tags("boolean").$type;
|
|
650
|
+
if (s.type === "null") return defineAnnotatedType().designType("null").tags("null").$type;
|
|
651
|
+
return defineAnnotatedType().designType("any").$type;
|
|
652
|
+
};
|
|
653
|
+
return convert(schema);
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
//#endregion
|
|
657
|
+
//#region packages/typescript/src/serialize.ts
|
|
658
|
+
const SERIALIZE_VERSION = 1;
|
|
659
|
+
function serializeAnnotatedType(type, options) {
|
|
660
|
+
const result = serializeNode(type, [], options);
|
|
661
|
+
result.$v = SERIALIZE_VERSION;
|
|
662
|
+
return result;
|
|
663
|
+
}
|
|
664
|
+
function serializeNode(def, path, options) {
|
|
665
|
+
const result = {
|
|
666
|
+
type: serializeTypeDef(def, path, options),
|
|
667
|
+
metadata: serializeMetadata(def.metadata, path, def.type.kind, options)
|
|
668
|
+
};
|
|
669
|
+
if (def.optional) result.optional = true;
|
|
670
|
+
return result;
|
|
671
|
+
}
|
|
672
|
+
function serializeTypeDef(def, path, options) {
|
|
673
|
+
return forAnnotatedType(def, {
|
|
674
|
+
final(d) {
|
|
675
|
+
const result = {
|
|
676
|
+
kind: "",
|
|
677
|
+
designType: d.type.designType,
|
|
678
|
+
tags: Array.from(d.type.tags)
|
|
679
|
+
};
|
|
680
|
+
if (d.type.value !== undefined) result.value = d.type.value;
|
|
681
|
+
return result;
|
|
682
|
+
},
|
|
683
|
+
object(d) {
|
|
684
|
+
const props = {};
|
|
685
|
+
for (const [key, val] of d.type.props.entries()) props[key] = serializeNode(val, [...path, key], options);
|
|
686
|
+
const propsPatterns = d.type.propsPatterns.map((pp) => ({
|
|
687
|
+
pattern: {
|
|
688
|
+
source: pp.pattern.source,
|
|
689
|
+
flags: pp.pattern.flags
|
|
690
|
+
},
|
|
691
|
+
def: serializeNode(pp.def, path, options)
|
|
692
|
+
}));
|
|
693
|
+
return {
|
|
694
|
+
kind: "object",
|
|
695
|
+
props,
|
|
696
|
+
propsPatterns,
|
|
697
|
+
tags: Array.from(d.type.tags)
|
|
698
|
+
};
|
|
699
|
+
},
|
|
700
|
+
array(d) {
|
|
701
|
+
return {
|
|
702
|
+
kind: "array",
|
|
703
|
+
of: serializeNode(d.type.of, path, options),
|
|
704
|
+
tags: Array.from(d.type.tags)
|
|
705
|
+
};
|
|
706
|
+
},
|
|
707
|
+
union(d) {
|
|
708
|
+
return {
|
|
709
|
+
kind: "union",
|
|
710
|
+
items: d.type.items.map((item) => serializeNode(item, path, options)),
|
|
711
|
+
tags: Array.from(d.type.tags)
|
|
712
|
+
};
|
|
713
|
+
},
|
|
714
|
+
intersection(d) {
|
|
715
|
+
return {
|
|
716
|
+
kind: "intersection",
|
|
717
|
+
items: d.type.items.map((item) => serializeNode(item, path, options)),
|
|
718
|
+
tags: Array.from(d.type.tags)
|
|
719
|
+
};
|
|
720
|
+
},
|
|
721
|
+
tuple(d) {
|
|
722
|
+
return {
|
|
723
|
+
kind: "tuple",
|
|
724
|
+
items: d.type.items.map((item) => serializeNode(item, path, options)),
|
|
725
|
+
tags: Array.from(d.type.tags)
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
function serializeMetadata(metadata, path, kind, options) {
|
|
731
|
+
const result = {};
|
|
732
|
+
const ignoreSet = options?.ignoreAnnotations ? new Set(options.ignoreAnnotations) : undefined;
|
|
733
|
+
for (const [key, value] of metadata.entries()) {
|
|
734
|
+
if (ignoreSet?.has(key)) continue;
|
|
735
|
+
if (options?.processAnnotation) {
|
|
736
|
+
const processed = options.processAnnotation({
|
|
737
|
+
key,
|
|
738
|
+
value,
|
|
739
|
+
path,
|
|
740
|
+
kind
|
|
741
|
+
});
|
|
742
|
+
if (processed === undefined || processed === null) continue;
|
|
743
|
+
result[processed.key] = processed.value;
|
|
744
|
+
continue;
|
|
745
|
+
}
|
|
746
|
+
result[key] = value;
|
|
747
|
+
}
|
|
748
|
+
return result;
|
|
749
|
+
}
|
|
750
|
+
function deserializeAnnotatedType(data) {
|
|
751
|
+
if (data.$v !== SERIALIZE_VERSION) throw new Error(`Unsupported serialized type version: ${data.$v} (expected ${SERIALIZE_VERSION})`);
|
|
752
|
+
return deserializeNode(data);
|
|
753
|
+
}
|
|
754
|
+
function deserializeNode(data) {
|
|
755
|
+
const metadata = new Map(Object.entries(data.metadata));
|
|
756
|
+
const type = deserializeTypeDef(data.type);
|
|
757
|
+
const result = {
|
|
758
|
+
__is_atscript_annotated_type: true,
|
|
759
|
+
type,
|
|
760
|
+
metadata,
|
|
761
|
+
validator(opts) {
|
|
762
|
+
return new Validator(this, opts);
|
|
763
|
+
}
|
|
764
|
+
};
|
|
765
|
+
if (data.optional) result.optional = true;
|
|
766
|
+
return result;
|
|
767
|
+
}
|
|
768
|
+
function deserializeTypeDef(t) {
|
|
769
|
+
const tags = new Set(t.tags);
|
|
770
|
+
switch (t.kind) {
|
|
771
|
+
case "": {
|
|
772
|
+
const result = {
|
|
773
|
+
kind: "",
|
|
774
|
+
designType: t.designType,
|
|
775
|
+
tags
|
|
776
|
+
};
|
|
777
|
+
if (t.value !== undefined) result.value = t.value;
|
|
778
|
+
return result;
|
|
779
|
+
}
|
|
780
|
+
case "object": {
|
|
781
|
+
const props = new Map();
|
|
782
|
+
for (const [key, val] of Object.entries(t.props)) props.set(key, deserializeNode(val));
|
|
783
|
+
const propsPatterns = t.propsPatterns.map((pp) => ({
|
|
784
|
+
pattern: new RegExp(pp.pattern.source, pp.pattern.flags),
|
|
785
|
+
def: deserializeNode(pp.def)
|
|
786
|
+
}));
|
|
787
|
+
return {
|
|
788
|
+
kind: "object",
|
|
789
|
+
props,
|
|
790
|
+
propsPatterns,
|
|
791
|
+
tags
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
case "array": return {
|
|
795
|
+
kind: "array",
|
|
796
|
+
of: deserializeNode(t.of),
|
|
797
|
+
tags
|
|
798
|
+
};
|
|
799
|
+
case "union":
|
|
800
|
+
case "intersection":
|
|
801
|
+
case "tuple": return {
|
|
802
|
+
kind: t.kind,
|
|
803
|
+
items: t.items.map((item) => deserializeNode(item)),
|
|
804
|
+
tags
|
|
805
|
+
};
|
|
806
|
+
default: throw new Error(`Unknown serialized type kind "${t.kind}"`);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
545
809
|
|
|
546
810
|
//#endregion
|
|
811
|
+
exports.SERIALIZE_VERSION = SERIALIZE_VERSION
|
|
547
812
|
exports.Validator = Validator
|
|
548
813
|
exports.ValidatorError = ValidatorError
|
|
814
|
+
exports.annotate = annotate
|
|
549
815
|
exports.buildJsonSchema = buildJsonSchema
|
|
550
816
|
exports.defineAnnotatedType = defineAnnotatedType
|
|
817
|
+
exports.deserializeAnnotatedType = deserializeAnnotatedType
|
|
818
|
+
exports.forAnnotatedType = forAnnotatedType
|
|
819
|
+
exports.fromJsonSchema = fromJsonSchema
|
|
551
820
|
exports.isAnnotatedType = isAnnotatedType
|
|
552
|
-
exports.isAnnotatedTypeOfPrimitive = isAnnotatedTypeOfPrimitive
|
|
821
|
+
exports.isAnnotatedTypeOfPrimitive = isAnnotatedTypeOfPrimitive
|
|
822
|
+
exports.serializeAnnotatedType = serializeAnnotatedType
|