@atscript/typescript 0.1.2 → 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/index.mjs CHANGED
@@ -207,7 +207,7 @@ var TypeRenderer = class TypeRenderer extends BaseRenderer {
207
207
  this.writeln(" * Do not edit this file!");
208
208
  this.writeln(" */");
209
209
  this.writeln();
210
- this.writeln("import type { TAtscriptTypeObject, TAtscriptTypeComplex, TAtscriptTypeFinal, TAtscriptTypeArray, TMetadataMap, Validator, TAtscriptAnnotatedTypeConstructor, TValidatorOptions } from \"@atscript/typescript/utils\"");
210
+ this.writeln("import type { TAtscriptTypeObject, TAtscriptTypeComplex, TAtscriptTypeFinal, TAtscriptTypeArray, TAtscriptAnnotatedType, TMetadataMap, Validator, TValidatorOptions } from \"@atscript/typescript/utils\"");
211
211
  }
212
212
  post() {
213
213
  this.writeln("// prettier-ignore-end");
@@ -296,9 +296,10 @@ var TypeRenderer = class TypeRenderer extends BaseRenderer {
296
296
  }
297
297
  if (asClass) {
298
298
  this.writeln("static __is_atscript_annotated_type: true");
299
- this.writeln(`static type: TAtscriptTypeObject<keyof ${asClass}>`);
299
+ this.writeln(`static type: TAtscriptTypeObject<keyof ${asClass}, ${asClass}>`);
300
300
  this.writeln(`static metadata: TMetadataMap<AtscriptMetadata>`);
301
- this.writeln(`static validator: <TT extends TAtscriptAnnotatedTypeConstructor = typeof ${asClass}>(opts?: Partial<TValidatorOptions>) => Validator<TT>`);
301
+ this.writeln(`static validator: (opts?: Partial<TValidatorOptions>) => Validator<typeof ${asClass}>`);
302
+ if (resolveJsonSchemaMode(this.opts) === false) this.writeln("/** @deprecated JSON Schema support is disabled. Calling this method will throw a runtime error. To enable, set `jsonSchema: 'lazy'` or `jsonSchema: 'bundle'` in tsPlugin options, or add `@emit.jsonSchema` annotation to individual interfaces. */");
302
303
  this.writeln("static toJsonSchema: () => any");
303
304
  }
304
305
  this.pop();
@@ -313,6 +314,12 @@ var TypeRenderer = class TypeRenderer extends BaseRenderer {
313
314
  if (struct?.entity === "structure") this.renderStructure(struct, node.id);
314
315
  else this.writeln("{}");
315
316
  this.writeln();
317
+ const nsPrefix = exported ? "export declare" : "declare";
318
+ this.write(`${nsPrefix} namespace ${node.id} `);
319
+ this.blockln("{}");
320
+ this.writeln(`type DataType = ${node.id}`);
321
+ this.popln();
322
+ this.writeln();
316
323
  }
317
324
  renderType(node) {
318
325
  this.writeln();
@@ -339,6 +346,11 @@ else this.writeln("{}");
339
346
  } else {
340
347
  this.write(exported ? "export declare " : "declare ");
341
348
  this.writeln(`class ${node.id} extends ${targetName} {}`);
349
+ const nsPrefix = exported ? "export declare" : "declare";
350
+ this.write(`${nsPrefix} namespace ${node.id} `);
351
+ this.blockln("{}");
352
+ this.writeln(`type DataType = ${node.id}`);
353
+ this.popln();
342
354
  this.writeln();
343
355
  }
344
356
  }
@@ -353,15 +365,17 @@ else this.writeln("{}");
353
365
  let realDef = inputDef;
354
366
  if (isRef(inputDef)) realDef = this.doc.unwindType(inputDef.id, inputDef.chain)?.def || realDef;
355
367
  realDef = this.doc.mergeIntersection(realDef);
356
- if (isStructure(realDef) || isInterface(realDef)) typeDef = `TAtscriptTypeObject<keyof ${name}>`;
357
- else if (isGroup(realDef)) typeDef = "TAtscriptTypeComplex";
358
- else if (isArray(realDef)) typeDef = "TAtscriptTypeArray";
359
- else if (isPrimitive(realDef)) typeDef = "TAtscriptTypeFinal";
368
+ if (isStructure(realDef) || isInterface(realDef)) typeDef = `TAtscriptTypeObject<keyof ${name}, ${name}>`;
369
+ else if (isGroup(realDef)) typeDef = `TAtscriptTypeComplex<${name}>`;
370
+ else if (isArray(realDef)) typeDef = `TAtscriptTypeArray<${name}>`;
371
+ else if (isPrimitive(realDef)) typeDef = `TAtscriptTypeFinal<${name}>`;
360
372
  }
373
+ this.writeln(`type DataType = ${name}`);
361
374
  this.writeln(`const __is_atscript_annotated_type: true`);
362
375
  this.writeln(`const type: ${typeDef}`);
363
376
  this.writeln(`const metadata: TMetadataMap<AtscriptMetadata>`);
364
- this.writeln(`const validator: (opts?: Partial<TValidatorOptions>) => Validator<TAtscriptAnnotatedTypeConstructor, ${name}>`);
377
+ this.writeln(`const validator: (opts?: Partial<TValidatorOptions>) => Validator<TAtscriptAnnotatedType, ${name}>`);
378
+ if (resolveJsonSchemaMode(this.opts) === false) this.writeln("/** @deprecated JSON Schema support is disabled. Calling this method will throw a runtime error. To enable, set `jsonSchema: 'lazy'` or `jsonSchema: 'bundle'` in tsPlugin options, or add `@emit.jsonSchema` annotation to individual interfaces. */");
365
379
  this.writeln("const toJsonSchema: () => any");
366
380
  this.popln();
367
381
  }
@@ -403,6 +417,20 @@ function renderPrimitiveTypeDef(def) {
403
417
  }
404
418
  }
405
419
 
420
+ //#endregion
421
+ //#region packages/typescript/src/traverse.ts
422
+ function forAnnotatedType(def, handlers) {
423
+ switch (def.type.kind) {
424
+ case "": return handlers.final(def);
425
+ case "object": return handlers.object(def);
426
+ case "array": return handlers.array(def);
427
+ case "union": return handlers.union(def);
428
+ case "intersection": return handlers.intersection(def);
429
+ case "tuple": return handlers.tuple(def);
430
+ default: throw new Error(`Unknown type kind "${def.type.kind}"`);
431
+ }
432
+ }
433
+
406
434
  //#endregion
407
435
  //#region packages/typescript/src/validator.ts
408
436
  function _define_property$1(obj, key, value) {
@@ -448,7 +476,17 @@ var Validator = class {
448
476
  throw() {
449
477
  throw new ValidatorError(this.errors);
450
478
  }
451
- validate(value, safe) {
479
+ /**
480
+ * Validates a value against the type definition.
481
+ *
482
+ * Acts as a TypeScript type guard — when it returns `true`, the value
483
+ * is narrowed to `DataType`.
484
+ *
485
+ * @param value - The value to validate.
486
+ * @param safe - If `true`, returns `false` on failure instead of throwing.
487
+ * @returns `true` if the value matches the type definition.
488
+ * @throws {ValidatorError} When validation fails and `safe` is not `true`.
489
+ */ validate(value, safe) {
452
490
  this.push("");
453
491
  this.errors = [];
454
492
  this.stackErrors = [];
@@ -475,15 +513,14 @@ var Validator = class {
475
513
  return this.stackPath.slice(1).join(".");
476
514
  }
477
515
  validateAnnotatedType(def, value) {
478
- switch (def.type.kind) {
479
- case "object": return this.validateObject(def, value);
480
- case "union": return this.validateUnion(def, value);
481
- case "intersection": return this.validateIntersection(def, value);
482
- case "tuple": return this.validateTuple(def, value);
483
- case "array": return this.validateArray(def, value);
484
- case "": return this.validatePrimitive(def, value);
485
- default: throw new Error(`Unknown type "${def.type.kind}"`);
486
- }
516
+ return forAnnotatedType(def, {
517
+ final: (d) => this.validatePrimitive(d, value),
518
+ object: (d) => this.validateObject(d, value),
519
+ array: (d) => this.validateArray(d, value),
520
+ union: (d) => this.validateUnion(d, value),
521
+ intersection: (d) => this.validateIntersection(d, value),
522
+ tuple: (d) => this.validateTuple(d, value)
523
+ });
487
524
  }
488
525
  validateUnion(def, value) {
489
526
  let i = 0;
@@ -715,7 +752,7 @@ else {
715
752
  constructor(def, opts) {
716
753
  _define_property$1(this, "def", void 0);
717
754
  _define_property$1(this, "opts", void 0);
718
- _define_property$1(this, "errors", void 0);
755
+ /** Validation errors collected during the last {@link validate} call. */ _define_property$1(this, "errors", void 0);
719
756
  _define_property$1(this, "stackErrors", void 0);
720
757
  _define_property$1(this, "stackPath", void 0);
721
758
  this.def = def;
@@ -861,14 +898,12 @@ else if (!newBase) throw new Error(`"${typeName}" is not annotated type`);
861
898
  //#region packages/typescript/src/json-schema.ts
862
899
  function buildJsonSchema(type) {
863
900
  const build = (def) => {
864
- const t = def.type;
865
901
  const meta = def.metadata;
866
- switch (t.kind) {
867
- case "object": {
868
- const obj = t;
902
+ return forAnnotatedType(def, {
903
+ object(d) {
869
904
  const properties = {};
870
905
  const required = [];
871
- for (const [key, val] of obj.props.entries()) {
906
+ for (const [key, val] of d.type.props.entries()) {
872
907
  properties[key] = build(val);
873
908
  if (!val.optional) required.push(key);
874
909
  }
@@ -878,41 +913,36 @@ function buildJsonSchema(type) {
878
913
  };
879
914
  if (required.length) schema.required = required;
880
915
  return schema;
881
- }
882
- case "array": {
883
- const arr = t;
916
+ },
917
+ array(d) {
884
918
  const schema = {
885
919
  type: "array",
886
- items: build(arr.of)
920
+ items: build(d.type.of)
887
921
  };
888
922
  const minLength = meta.get("expect.minLength");
889
923
  if (typeof minLength === "number") schema.minItems = minLength;
890
924
  const maxLength = meta.get("expect.maxLength");
891
925
  if (typeof maxLength === "number") schema.maxItems = maxLength;
892
926
  return schema;
893
- }
894
- case "union": {
895
- const grp = t;
896
- return { anyOf: grp.items.map(build) };
897
- }
898
- case "intersection": {
899
- const grp = t;
900
- return { allOf: grp.items.map(build) };
901
- }
902
- case "tuple": {
903
- const grp = t;
927
+ },
928
+ union(d) {
929
+ return { anyOf: d.type.items.map(build) };
930
+ },
931
+ intersection(d) {
932
+ return { allOf: d.type.items.map(build) };
933
+ },
934
+ tuple(d) {
904
935
  return {
905
936
  type: "array",
906
- items: grp.items.map(build),
937
+ items: d.type.items.map(build),
907
938
  additionalItems: false
908
939
  };
909
- }
910
- case "": {
911
- const fin = t;
940
+ },
941
+ final(d) {
912
942
  const schema = {};
913
- if (fin.value !== undefined) schema.const = fin.value;
914
- if (fin.designType && fin.designType !== "any") {
915
- schema.type = fin.designType === "undefined" ? "null" : fin.designType;
943
+ if (d.type.value !== undefined) schema.const = d.type.value;
944
+ if (d.type.designType && d.type.designType !== "any") {
945
+ schema.type = d.type.designType === "undefined" ? "null" : d.type.designType;
916
946
  if (schema.type === "number" && meta.get("expect.int")) schema.type = "integer";
917
947
  }
918
948
  if (schema.type === "string") {
@@ -932,8 +962,7 @@ else schema.allOf = (schema.allOf || []).concat(patterns.map((p) => ({ pattern:
932
962
  }
933
963
  return schema;
934
964
  }
935
- default: return {};
936
- }
965
+ });
937
966
  };
938
967
  return build(type);
939
968
  }
@@ -955,7 +984,7 @@ var JsRenderer = class extends BaseRenderer {
955
984
  this.writeln("// prettier-ignore-start");
956
985
  this.writeln("/* eslint-disable */");
957
986
  const imports = ["defineAnnotatedType as $", "annotate as $a"];
958
- if (!this.opts?.preRenderJsonSchema) imports.push("buildJsonSchema as $$");
987
+ if (resolveJsonSchemaMode(this.opts) === "lazy") imports.push("buildJsonSchema as $$");
959
988
  this.writeln(`import { ${imports.join(", ")} } from "@atscript/typescript/utils"`);
960
989
  }
961
990
  buildAdHocMap(annotateNodes) {
@@ -1043,15 +1072,21 @@ else {
1043
1072
  this.writeln();
1044
1073
  }
1045
1074
  renderJsonSchemaMethod(node) {
1046
- if (this.opts?.preRenderJsonSchema) {
1075
+ const mode = resolveJsonSchemaMode(this.opts);
1076
+ const hasAnnotation = node.countAnnotations("emit.jsonSchema") > 0;
1077
+ if (hasAnnotation || mode === "bundle") {
1047
1078
  const schema = JSON.stringify(buildJsonSchema(this.toAnnotatedType(node)));
1048
1079
  this.writeln("static toJsonSchema() {");
1049
1080
  this.indent().writeln(`return ${schema}`).unindent();
1050
1081
  this.writeln("}");
1051
- } else {
1082
+ } else if (mode === "lazy") {
1052
1083
  this.writeln("static toJsonSchema() {");
1053
1084
  this.indent().writeln("return this._jsonSchema ?? (this._jsonSchema = $$(this))").unindent();
1054
1085
  this.writeln("}");
1086
+ } else {
1087
+ this.writeln("static toJsonSchema() {");
1088
+ this.indent().writeln("throw new Error(\"JSON Schema support is disabled. To enable, set `jsonSchema: 'lazy'` or `jsonSchema: 'bundle'` in tsPlugin options, or add @emit.jsonSchema annotation to individual interfaces.\")").unindent();
1089
+ this.writeln("}");
1055
1090
  }
1056
1091
  }
1057
1092
  toAnnotatedType(node) {
@@ -1494,6 +1529,10 @@ else {
1494
1529
 
1495
1530
  //#endregion
1496
1531
  //#region packages/typescript/src/plugin.ts
1532
+ function resolveJsonSchemaMode(opts) {
1533
+ if (opts?.jsonSchema !== undefined) return opts.jsonSchema;
1534
+ return false;
1535
+ }
1497
1536
  const tsPlugin = (opts) => {
1498
1537
  return {
1499
1538
  name: "typesccript",
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
- validate(value, safe) {
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
- switch (def.type.kind) {
75
- case "object": return this.validateObject(def, value);
76
- case "union": return this.validateUnion(def, value);
77
- case "intersection": return this.validateIntersection(def, value);
78
- case "tuple": return this.validateTuple(def, value);
79
- case "array": return this.validateArray(def, value);
80
- case "": return this.validatePrimitive(def, value);
81
- default: throw new Error(`Unknown type "${def.type.kind}"`);
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;
@@ -470,14 +493,12 @@ function isAnnotatedTypeOfPrimitive(t) {
470
493
  //#region packages/typescript/src/json-schema.ts
471
494
  function buildJsonSchema(type) {
472
495
  const build = (def) => {
473
- const t = def.type;
474
496
  const meta = def.metadata;
475
- switch (t.kind) {
476
- case "object": {
477
- const obj = t;
497
+ return forAnnotatedType(def, {
498
+ object(d) {
478
499
  const properties = {};
479
500
  const required = [];
480
- for (const [key, val] of obj.props.entries()) {
501
+ for (const [key, val] of d.type.props.entries()) {
481
502
  properties[key] = build(val);
482
503
  if (!val.optional) required.push(key);
483
504
  }
@@ -487,41 +508,36 @@ function buildJsonSchema(type) {
487
508
  };
488
509
  if (required.length) schema.required = required;
489
510
  return schema;
490
- }
491
- case "array": {
492
- const arr = t;
511
+ },
512
+ array(d) {
493
513
  const schema = {
494
514
  type: "array",
495
- items: build(arr.of)
515
+ items: build(d.type.of)
496
516
  };
497
517
  const minLength = meta.get("expect.minLength");
498
518
  if (typeof minLength === "number") schema.minItems = minLength;
499
519
  const maxLength = meta.get("expect.maxLength");
500
520
  if (typeof maxLength === "number") schema.maxItems = maxLength;
501
521
  return schema;
502
- }
503
- case "union": {
504
- const grp = t;
505
- return { anyOf: grp.items.map(build) };
506
- }
507
- case "intersection": {
508
- const grp = t;
509
- return { allOf: grp.items.map(build) };
510
- }
511
- case "tuple": {
512
- 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) {
513
530
  return {
514
531
  type: "array",
515
- items: grp.items.map(build),
532
+ items: d.type.items.map(build),
516
533
  additionalItems: false
517
534
  };
518
- }
519
- case "": {
520
- const fin = t;
535
+ },
536
+ final(d) {
521
537
  const schema = {};
522
- if (fin.value !== undefined) schema.const = fin.value;
523
- if (fin.designType && fin.designType !== "any") {
524
- schema.type = fin.designType === "undefined" ? "null" : fin.designType;
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;
525
541
  if (schema.type === "number" && meta.get("expect.int")) schema.type = "integer";
526
542
  }
527
543
  if (schema.type === "string") {
@@ -541,17 +557,266 @@ else schema.allOf = (schema.allOf || []).concat(patterns.map((p) => ({ pattern:
541
557
  }
542
558
  return schema;
543
559
  }
544
- default: return {};
545
- }
560
+ });
546
561
  };
547
562
  return build(type);
548
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
+ }
549
809
 
550
810
  //#endregion
811
+ exports.SERIALIZE_VERSION = SERIALIZE_VERSION
551
812
  exports.Validator = Validator
552
813
  exports.ValidatorError = ValidatorError
553
814
  exports.annotate = annotate
554
815
  exports.buildJsonSchema = buildJsonSchema
555
816
  exports.defineAnnotatedType = defineAnnotatedType
817
+ exports.deserializeAnnotatedType = deserializeAnnotatedType
818
+ exports.forAnnotatedType = forAnnotatedType
819
+ exports.fromJsonSchema = fromJsonSchema
556
820
  exports.isAnnotatedType = isAnnotatedType
557
- exports.isAnnotatedTypeOfPrimitive = isAnnotatedTypeOfPrimitive
821
+ exports.isAnnotatedTypeOfPrimitive = isAnnotatedTypeOfPrimitive
822
+ exports.serializeAnnotatedType = serializeAnnotatedType