@atscript/typescript 0.1.88 → 0.1.89

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.cjs CHANGED
@@ -1,6 +1,5 @@
1
- Object.defineProperty(exports, '__esModule', { value: true });
2
- const require_plugin = require('./plugin-CZ5g5D9I.cjs');
3
- require('./json-schema-3mti4G4J.cjs');
1
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
2
+ const require_plugin = require('./plugin-DMBkdYCf.cjs');
4
3
 
5
- exports.default = require_plugin.tsPlugin
6
- exports.tsPlugin = require_plugin.tsPlugin
4
+ exports.default = require_plugin.tsPlugin;
5
+ exports.tsPlugin = require_plugin.tsPlugin;
package/dist/index.mjs CHANGED
@@ -1,4 +1,3 @@
1
- import { tsPlugin } from "./plugin-CYzZm3rk.mjs";
2
- import "./json-schema-B64qclVa.mjs";
1
+ import { t as tsPlugin } from "./plugin-BOoquMkD.mjs";
3
2
 
4
3
  export { tsPlugin as default, tsPlugin };
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
 
3
2
  //#region packages/typescript/src/runtime/validator.ts
4
3
  function _define_property(obj, key, value) {
@@ -8,11 +7,31 @@ function _define_property(obj, key, value) {
8
7
  configurable: true,
9
8
  writable: true
10
9
  });
11
- else obj[key] = value;
10
+ else obj[key] = value;
12
11
  return obj;
13
12
  }
14
- const regexCache = new Map();
15
- var Validator = class {
13
+ const regexCache = /* @__PURE__ */ new Map();
14
+ /**
15
+ * Validates values against an {@link TAtscriptAnnotatedType} definition.
16
+ *
17
+ * `DataType` is automatically inferred from the type definition's phantom generic,
18
+ * enabling the {@link validate} method to act as a type guard.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * // From a generated interface class:
23
+ * const validator = new Validator(MyInterface)
24
+ * if (validator.validate(data, true)) {
25
+ * data // narrowed to MyInterface
26
+ * }
27
+ *
28
+ * // Or use the built-in factory:
29
+ * MyInterface.validator().validate(data)
30
+ * ```
31
+ *
32
+ * @typeParam T - The annotated type definition.
33
+ * @typeParam DataType - The TypeScript type that `validate` narrows to (auto-inferred).
34
+ */ var Validator = class {
16
35
  buildPath() {
17
36
  if (this.depth <= 0) return "";
18
37
  let path = this.pathSegments[0];
@@ -27,7 +46,7 @@ var Validator = class {
27
46
  pop(saveErrors) {
28
47
  this.depth--;
29
48
  const popped = this.stackErrors.pop();
30
- if (saveErrors && popped !== null && popped !== undefined && popped.length > 0) for (const err of popped) this.error(err.message, err.path, err.details);
49
+ if (saveErrors && popped !== null && popped !== void 0 && popped.length > 0) for (const err of popped) this.error(err.message, err.path, err.details);
31
50
  return popped;
32
51
  }
33
52
  clear() {
@@ -68,7 +87,7 @@ var Validator = class {
68
87
  this.limitExceeded = false;
69
88
  this.context = context;
70
89
  const passed = this.validateSafe(this.def, value);
71
- this.context = undefined;
90
+ this.context = void 0;
72
91
  if (!passed) {
73
92
  if (safe) return false;
74
93
  this.throw();
@@ -79,13 +98,13 @@ var Validator = class {
79
98
  if (this.limitExceeded) return false;
80
99
  if (this.hasReplace) {
81
100
  let replaced = this.replaceCache.get(def);
82
- if (replaced === undefined) {
101
+ if (replaced === void 0) {
83
102
  replaced = this.opts.replace(def, this.buildPath());
84
103
  this.replaceCache.set(def, replaced);
85
104
  }
86
105
  def = replaced;
87
106
  }
88
- if (def.optional && (value === undefined || value === null)) return true;
107
+ if (def.optional && (value === void 0 || value === null)) return true;
89
108
  if (this.hasPlugins) for (const plugin of this.opts.plugins) {
90
109
  const result = plugin(this, def, value);
91
110
  if (result === false || result === true) return result;
@@ -97,10 +116,9 @@ var Validator = class {
97
116
  }
98
117
  validateAnnotatedType(def, value) {
99
118
  switch (def.type.kind) {
100
- case "": {
119
+ case "":
101
120
  if (def.type.designType === "phantom") return true;
102
121
  return this.validatePrimitive(def, value);
103
- }
104
122
  case "object": return this.validateObject(def, value);
105
123
  case "array": return this.validateArray(def, value);
106
124
  case "union": return this.validateUnion(def, value);
@@ -121,10 +139,10 @@ var Validator = class {
121
139
  const branchErrors = this.stackErrors.pop();
122
140
  if (this.limitExceeded) this.limitExceeded = false;
123
141
  if (branchErrors) if (details) for (const err of branchErrors) details.push(err);
124
- else details = branchErrors;
142
+ else details = branchErrors;
125
143
  }
126
144
  const expected = items.map((item, i) => `[${item.type.kind || item.type.designType}(${i})]`).join(", ");
127
- this.error(`Value does not match any of the allowed types: ${expected}`, undefined, details);
145
+ this.error(`Value does not match any of the allowed types: ${expected}`, void 0, details);
128
146
  return false;
129
147
  }
130
148
  validateIntersection(def, value) {
@@ -174,8 +192,8 @@ else details = branchErrors;
174
192
  const uniqueItems = def.metadata.get("expect.array.uniqueItems");
175
193
  if (uniqueItems) {
176
194
  const separator = "▼↩";
177
- const seen = new Set();
178
- const keyProps = new Set();
195
+ const seen = /* @__PURE__ */ new Set();
196
+ const keyProps = /* @__PURE__ */ new Set();
179
197
  if (def.type.of.type.kind === "object") {
180
198
  for (const [key, val] of def.type.of.type.props.entries()) if (val.metadata.get("expect.array.key")) keyProps.add(key);
181
199
  }
@@ -220,7 +238,7 @@ else details = branchErrors;
220
238
  const path = this.depth > 0 ? `${this.buildPath()}.` : "";
221
239
  for (const item of this.opts.skipList) if (item.startsWith(path)) {
222
240
  const key = item.slice(path.length);
223
- if (!skipList) skipList = new Set();
241
+ if (!skipList) skipList = /* @__PURE__ */ new Set();
224
242
  skipList.add(key);
225
243
  }
226
244
  }
@@ -228,12 +246,12 @@ else details = branchErrors;
228
246
  if (typeof this.opts.partial === "function") partialFunctionMatched = this.opts.partial(def, this.buildPath());
229
247
  for (const [key, item] of def.type.props.entries()) {
230
248
  if (skipList && skipList.has(key) || isPhantomType(item)) continue;
231
- if (value[key] === undefined) {
249
+ if (value[key] === void 0) {
232
250
  if (partialFunctionMatched || this.opts.partial === "deep" || this.opts.partial === true && this.depth === 0) continue;
233
251
  }
234
252
  this.push(key);
235
253
  if (this.validateSafe(item, value[key])) this.pop(false);
236
- else {
254
+ else {
237
255
  passed = false;
238
256
  this.pop(true);
239
257
  if (this.limitExceeded) return false;
@@ -283,7 +301,7 @@ else {
283
301
  return passed;
284
302
  }
285
303
  validatePrimitive(def, value) {
286
- if (def.type.value !== undefined) {
304
+ if (def.type.value !== void 0) {
287
305
  if (value !== def.type.value) {
288
306
  this.error(`Expected ${def.type.value}, got ${value}`);
289
307
  return false;
@@ -292,47 +310,41 @@ else {
292
310
  }
293
311
  const typeOfValue = Array.isArray(value) ? "array" : typeof value;
294
312
  switch (def.type.designType) {
295
- case "never": {
313
+ case "never":
296
314
  this.error(`This type is impossible, must be an internal problem`);
297
315
  return false;
298
- }
299
316
  case "any": return true;
300
- case "string": {
317
+ case "string":
301
318
  if (typeOfValue !== def.type.designType) {
302
319
  this.error(`Expected ${def.type.designType}, got ${typeOfValue}`);
303
320
  return false;
304
321
  }
305
322
  return this.validateString(def, value);
306
- }
307
- case "number": {
323
+ case "number":
308
324
  if (typeOfValue !== def.type.designType) {
309
325
  this.error(`Expected ${def.type.designType}, got ${typeOfValue}`);
310
326
  return false;
311
327
  }
312
328
  return this.validateNumber(def, value);
313
- }
314
- case "boolean": {
329
+ case "boolean":
315
330
  if (typeOfValue !== def.type.designType) {
316
331
  this.error(`Expected ${def.type.designType}, got ${typeOfValue}`);
317
332
  return false;
318
333
  }
319
334
  return this.validateBoolean(def, value);
320
- }
321
- case "undefined": {
322
- if (value !== undefined) {
335
+ case "undefined":
336
+ if (value !== void 0) {
323
337
  this.error(`Expected ${def.type.designType}, got ${typeOfValue}`);
324
338
  return false;
325
339
  }
326
340
  return true;
327
- }
328
- case "null": {
341
+ case "null":
329
342
  if (value !== null) {
330
343
  this.error(`Expected ${def.type.designType}, got ${typeOfValue}`);
331
344
  return false;
332
345
  }
333
346
  return true;
334
- }
335
- case "decimal": {
347
+ case "decimal":
336
348
  if (typeOfValue !== "string") {
337
349
  this.error(`Expected string (decimal), got ${typeOfValue}`);
338
350
  return false;
@@ -342,7 +354,6 @@ else {
342
354
  return false;
343
355
  }
344
356
  return true;
345
- }
346
357
  default: throw new Error(`Unknown type "${def.type.designType}"`);
347
358
  }
348
359
  }
@@ -457,10 +468,10 @@ else {
457
468
  };
458
469
  this.hasPlugins = this.opts.plugins.length > 0;
459
470
  this.hasReplace = typeof this.opts.replace === "function";
460
- if (this.hasReplace) this.replaceCache = new WeakMap();
471
+ if (this.hasReplace) this.replaceCache = /* @__PURE__ */ new WeakMap();
461
472
  }
462
473
  };
463
- var ValidatorError = class extends Error {
474
+ /** Error thrown by {@link Validator.validate} when validation fails. Contains structured error details. */ var ValidatorError = class extends Error {
464
475
  constructor(errors) {
465
476
  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";
466
477
  }
@@ -477,7 +488,10 @@ const NON_PRIMITIVE_KINDS = new Set(["array", "object"]);
477
488
  /** Shared validator method reused by all annotated type nodes. */ function validatorMethod(opts) {
478
489
  return new Validator(this, opts);
479
490
  }
480
- function createAnnotatedTypeNode(type, metadata, opts) {
491
+ /**
492
+ * Creates a minimal annotated type node from a type def and metadata map.
493
+ * Centralises the shape so callers never duplicate the boilerplate.
494
+ */ function createAnnotatedTypeNode(type, metadata, opts) {
481
495
  return {
482
496
  __is_atscript_annotated_type: true,
483
497
  type,
@@ -488,19 +502,27 @@ function createAnnotatedTypeNode(type, metadata, opts) {
488
502
  ref: opts?.ref
489
503
  };
490
504
  }
491
- function isAnnotatedType(type) {
505
+ /**
506
+ * Type Guard to check if a type is atscript-annotated
507
+ */ function isAnnotatedType(type) {
492
508
  return type && type.__is_atscript_annotated_type;
493
509
  }
494
- function annotate(metadata, key, value, asArray) {
510
+ /**
511
+ * Standalone annotate function that handles both replace and append (array) strategies.
512
+ * Used by the handle's .annotate() method and by generated mutation statements.
513
+ */ function annotate(metadata, key, value, asArray) {
495
514
  if (!metadata) return;
496
515
  if (asArray) if (metadata.has(key)) {
497
516
  const a = metadata.get(key);
498
517
  if (Array.isArray(a)) a.push(value);
499
- else metadata.set(key, [a, value]);
518
+ else metadata.set(key, [a, value]);
500
519
  } else metadata.set(key, [value]);
501
- else metadata.set(key, value);
520
+ else metadata.set(key, value);
502
521
  }
503
- function cloneRefProp(parentType, propName) {
522
+ /**
523
+ * Clones a property's type tree in-place so mutations don't leak to shared refs.
524
+ * Used by mutating annotate codegen when paths cross ref boundaries.
525
+ */ function cloneRefProp(parentType, propName) {
504
526
  if (parentType.kind !== "object") return;
505
527
  const objType = parentType;
506
528
  const existing = objType.props.get(propName);
@@ -514,7 +536,7 @@ function cloneRefProp(parentType, propName) {
514
536
  function cloneTypeDef(type) {
515
537
  if (type.kind === "object") {
516
538
  const obj = type;
517
- const props = new Map();
539
+ const props = /* @__PURE__ */ new Map();
518
540
  for (const [k, v] of obj.props) props.set(k, createAnnotatedTypeNode(v.type, new Map(v.metadata), {
519
541
  id: v.id,
520
542
  optional: v.optional
@@ -547,18 +569,36 @@ function cloneTypeDef(type) {
547
569
  tags: new Set(type.tags)
548
570
  };
549
571
  }
550
- function defineAnnotatedType(_kind, base) {
572
+ /**
573
+ * Creates a builder handle for constructing a {@link TAtscriptAnnotatedType} at runtime.
574
+ *
575
+ * This is primarily used by generated `.as.js` code. The returned handle provides
576
+ * a fluent API for setting the type definition, metadata, and properties.
577
+ *
578
+ * @example
579
+ * ```ts
580
+ * const handle = defineAnnotatedType('object')
581
+ * .prop('name', defineAnnotatedType().designType('string').$type)
582
+ * .prop('age', defineAnnotatedType().designType('number').$type)
583
+ *
584
+ * handle.$type // the resulting TAtscriptAnnotatedType
585
+ * ```
586
+ *
587
+ * @param _kind - The kind of type to create (e.g. `'object'`, `'array'`, `'union'`). Defaults to `''` (primitive/final).
588
+ * @param base - Optional existing object to augment with annotated type fields.
589
+ * @returns A builder handle for fluent type construction.
590
+ */ function defineAnnotatedType(_kind, base) {
551
591
  const kind = _kind || "";
552
- const baseProvided = base !== undefined;
592
+ const baseProvided = base !== void 0;
553
593
  const type = base?.type || {};
554
594
  type.kind = kind;
555
595
  if (COMPLEX_KINDS.has(kind)) type.items = [];
556
596
  if (kind === "object") {
557
- type.props = new Map();
597
+ type.props = /* @__PURE__ */ new Map();
558
598
  type.propsPatterns = [];
559
599
  }
560
- type.tags = new Set();
561
- const metadata = base?.metadata || new Map();
600
+ type.tags = /* @__PURE__ */ new Set();
601
+ const metadata = base?.metadata || /* @__PURE__ */ new Map();
562
602
  const payload = {
563
603
  __is_atscript_annotated_type: true,
564
604
  metadata,
@@ -566,7 +606,7 @@ function defineAnnotatedType(_kind, base) {
566
606
  validator: validatorMethod
567
607
  };
568
608
  base = base ? Object.assign(base, payload) : payload;
569
- const handle = {
609
+ return {
570
610
  $type: base,
571
611
  $def: type,
572
612
  $metadata: metadata,
@@ -609,15 +649,15 @@ function defineAnnotatedType(_kind, base) {
609
649
  for (const [key, value] of fromMetadata.entries()) if (!ignore || !ignore.has(key)) this.$metadata.set(key, value);
610
650
  return this;
611
651
  },
612
- refTo(type$1, chain) {
652
+ refTo(type, chain) {
613
653
  const node = this.$type;
614
- if (isAnnotatedType(type$1)) {
615
- let newBase = type$1;
616
- const typeName = type$1.name || "Unknown";
654
+ if (isAnnotatedType(type)) {
655
+ let newBase = type;
656
+ const typeName = type.name || "Unknown";
617
657
  if (chain) for (let i = 0; i < chain.length; i++) {
618
658
  const c = chain[i];
619
659
  if (newBase.type.kind === "object" && newBase.type.props.has(c)) newBase = newBase.type.props.get(c);
620
- else {
660
+ else {
621
661
  const keys = chain.slice(0, i + 1).map((k) => `["${k}"]`).join("");
622
662
  throw new Error(`Can't find prop ${typeName}${keys}`);
623
663
  }
@@ -625,11 +665,11 @@ else {
625
665
  node.type = baseProvided ? cloneTypeDef(newBase.type) : newBase.type;
626
666
  node.id = node.id ?? newBase.id;
627
667
  if (chain && chain.length > 0) node.ref = {
628
- type: () => type$1,
668
+ type: () => type,
629
669
  field: chain.join(".")
630
670
  };
631
- } else if (typeof type$1 === "function") {
632
- const lazyType = type$1;
671
+ } else if (typeof type === "function") {
672
+ const lazyType = type;
633
673
  const ownId = node.id;
634
674
  node.ref = {
635
675
  type: lazyType,
@@ -649,7 +689,7 @@ else {
649
689
  }
650
690
  let target = t;
651
691
  if (chain) for (const c of chain) if (target.type.kind === "object" && target.type.props.has(c)) target = target.type.props.get(c);
652
- else return t.type;
692
+ else return t.type;
653
693
  node.id = ownId ?? target.id;
654
694
  const resolved = baseProvided ? cloneTypeDef(target.type) : target.type;
655
695
  Object.defineProperty(node, "type", {
@@ -661,7 +701,7 @@ else return t.type;
661
701
  },
662
702
  configurable: true
663
703
  });
664
- } else throw new TypeError(`${type$1} is not annotated type`);
704
+ } else throw new TypeError(`${type} is not annotated type`);
665
705
  return this;
666
706
  },
667
707
  annotate(key, value, asArray) {
@@ -673,12 +713,21 @@ else return t.type;
673
713
  return this;
674
714
  }
675
715
  };
676
- return handle;
677
716
  }
678
- function isPhantomType(def) {
717
+ /**
718
+ * Checks whether an annotated type is a phantom type.
719
+ *
720
+ * Phantom types do not affect the data type, validation, or schema,
721
+ * but are discoverable via runtime type traversal.
722
+ */ function isPhantomType(def) {
679
723
  return def.type.kind === "" && def.type.designType === "phantom";
680
724
  }
681
- function isAnnotatedTypeOfPrimitive(t) {
725
+ /**
726
+ * Checks whether an annotated type resolves to a primitive (non-object, non-array) shape.
727
+ *
728
+ * Returns `true` for final types and for unions/intersections/tuples
729
+ * whose members are all primitives.
730
+ */ function isAnnotatedTypeOfPrimitive(t) {
682
731
  if (NON_PRIMITIVE_KINDS.has(t.type.kind)) return false;
683
732
  if (!t.type.kind) return true;
684
733
  if (COMPLEX_KINDS.has(t.type.kind)) {
@@ -690,7 +739,17 @@ function isAnnotatedTypeOfPrimitive(t) {
690
739
 
691
740
  //#endregion
692
741
  //#region packages/typescript/src/runtime/traverse.ts
693
- function forAnnotatedType(def, handlers) {
742
+ /**
743
+ * Type-safe dispatch over `TAtscriptAnnotatedType` by its `type.kind`.
744
+ *
745
+ * Provides the common `switch (def.type.kind)` pattern used by
746
+ * the validator, JSON-schema builder, and serializer.
747
+ * Each caller supplies its own handlers that control recursion.
748
+ *
749
+ * When a `phantom` handler is provided, phantom types (`designType === 'phantom'`)
750
+ * are dispatched to it instead of `final`. This allows consumers to skip or
751
+ * handle phantom props without polluting their `final` handler.
752
+ */ function forAnnotatedType(def, handlers) {
694
753
  switch (def.type.kind) {
695
754
  case "": {
696
755
  const typed = def;
@@ -708,21 +767,27 @@ function forAnnotatedType(def, handlers) {
708
767
 
709
768
  //#endregion
710
769
  //#region packages/typescript/src/runtime/json-schema.ts
711
- function detectDiscriminator(items) {
770
+ /**
771
+ * Detects a discriminator property across union items.
772
+ *
773
+ * Scans all items for object-typed members that share a common property
774
+ * with distinct const/literal values. If exactly one such property exists,
775
+ * it is returned as the discriminator. Returns `null` when no qualifying
776
+ * property exists, or when more than one does (ambiguous).
777
+ */ function detectDiscriminator(items) {
712
778
  if (items.length < 2) return null;
713
779
  for (const item of items) if (item.type.kind !== "object") return null;
714
780
  const firstObj = items[0].type;
715
781
  const candidates = [];
716
- for (const [propName, propType] of firstObj.props.entries()) if (propType.type.kind === "" && propType.type.value !== undefined) candidates.push(propName);
782
+ for (const [propName, propType] of firstObj.props.entries()) if (propType.type.kind === "" && propType.type.value !== void 0) candidates.push(propName);
717
783
  let result = null;
718
784
  for (const candidate of candidates) {
719
- const values = new Set();
785
+ const values = /* @__PURE__ */ new Set();
720
786
  const indexMapping = {};
721
787
  let valid = true;
722
788
  for (let i = 0; i < items.length; i++) {
723
- const obj = items[i].type;
724
- const prop = obj.props.get(candidate);
725
- if (!prop || prop.type.kind !== "" || prop.type.value === undefined) {
789
+ const prop = items[i].type.props.get(candidate);
790
+ if (!prop || prop.type.kind !== "" || prop.type.value === void 0) {
726
791
  valid = false;
727
792
  break;
728
793
  }
@@ -744,7 +809,23 @@ function detectDiscriminator(items) {
744
809
  }
745
810
  return result;
746
811
  }
747
- function buildJsonSchema(type) {
812
+ /**
813
+ * Builds a JSON Schema from an {@link TAtscriptAnnotatedType}.
814
+ *
815
+ * Translates the atscript type structure and validation metadata
816
+ * (min/max, patterns, integer constraints, etc.) into a standard JSON Schema.
817
+ *
818
+ * @example
819
+ * ```ts
820
+ * import { buildJsonSchema } from '@atscript/typescript'
821
+ *
822
+ * const schema = buildJsonSchema(MyInterface)
823
+ * // { type: 'object', properties: { ... }, required: [...] }
824
+ * ```
825
+ *
826
+ * @param type - The annotated type to convert.
827
+ * @returns A JSON Schema object.
828
+ */ function buildJsonSchema(type) {
748
829
  const defs = {};
749
830
  let hasDefs = false;
750
831
  const buildObject = (d) => {
@@ -755,12 +836,12 @@ function buildJsonSchema(type) {
755
836
  properties[key] = build(val);
756
837
  if (!val.optional) required.push(key);
757
838
  }
758
- const schema$1 = {
839
+ const schema = {
759
840
  type: "object",
760
841
  properties
761
842
  };
762
- if (required.length > 0) schema$1.required = required;
763
- return schema$1;
843
+ if (required.length > 0) schema.required = required;
844
+ return schema;
764
845
  };
765
846
  const build = (def) => {
766
847
  if (def.id && def.type.kind === "object" && def !== type) {
@@ -781,15 +862,15 @@ function buildJsonSchema(type) {
781
862
  return buildObject(d);
782
863
  },
783
864
  array(d) {
784
- const schema$1 = {
865
+ const schema = {
785
866
  type: "array",
786
867
  items: build(d.type.of)
787
868
  };
788
869
  const minLength = meta.get("expect.minLength");
789
- if (minLength) schema$1.minItems = typeof minLength === "number" ? minLength : minLength.length;
870
+ if (minLength) schema.minItems = typeof minLength === "number" ? minLength : minLength.length;
790
871
  const maxLength = meta.get("expect.maxLength");
791
- if (maxLength) schema$1.maxItems = typeof maxLength === "number" ? maxLength : maxLength.length;
792
- return schema$1;
872
+ if (maxLength) schema.maxItems = typeof maxLength === "number" ? maxLength : maxLength.length;
873
+ return schema;
793
874
  },
794
875
  union(d) {
795
876
  const disc = detectDiscriminator(d.type.items);
@@ -821,30 +902,30 @@ function buildJsonSchema(type) {
821
902
  };
822
903
  },
823
904
  final(d) {
824
- const schema$1 = {};
825
- if (d.type.value !== undefined) schema$1.const = d.type.value;
905
+ const schema = {};
906
+ if (d.type.value !== void 0) schema.const = d.type.value;
826
907
  if (d.type.designType && d.type.designType !== "any") {
827
908
  const dt = d.type.designType;
828
- schema$1.type = dt === "undefined" ? "null" : dt === "decimal" ? "string" : dt;
829
- if (schema$1.type === "number" && meta.get("expect.int")) schema$1.type = "integer";
909
+ schema.type = dt === "undefined" ? "null" : dt === "decimal" ? "string" : dt;
910
+ if (schema.type === "number" && meta.get("expect.int")) schema.type = "integer";
830
911
  }
831
- if (schema$1.type === "string") {
832
- if (meta.get("meta.required")) schema$1.minLength = 1;
912
+ if (schema.type === "string") {
913
+ if (meta.get("meta.required")) schema.minLength = 1;
833
914
  const minLength = meta.get("expect.minLength");
834
- if (minLength) schema$1.minLength = typeof minLength === "number" ? minLength : minLength.length;
915
+ if (minLength) schema.minLength = typeof minLength === "number" ? minLength : minLength.length;
835
916
  const maxLength = meta.get("expect.maxLength");
836
- if (maxLength) schema$1.maxLength = typeof maxLength === "number" ? maxLength : maxLength.length;
917
+ if (maxLength) schema.maxLength = typeof maxLength === "number" ? maxLength : maxLength.length;
837
918
  const patterns = meta.get("expect.pattern");
838
- if (patterns?.length) if (patterns.length === 1) schema$1.pattern = patterns[0].pattern;
839
- else schema$1.allOf = (schema$1.allOf || []).concat(patterns.map((p) => ({ pattern: p.pattern })));
919
+ if (patterns?.length) if (patterns.length === 1) schema.pattern = patterns[0].pattern;
920
+ else schema.allOf = (schema.allOf || []).concat(patterns.map((p) => ({ pattern: p.pattern })));
840
921
  }
841
- if (schema$1.type === "number" || schema$1.type === "integer") {
922
+ if (schema.type === "number" || schema.type === "integer") {
842
923
  const min = meta.get("expect.min");
843
- if (min) schema$1.minimum = typeof min === "number" ? min : min.minValue;
924
+ if (min) schema.minimum = typeof min === "number" ? min : min.minValue;
844
925
  const max = meta.get("expect.max");
845
- if (max) schema$1.maximum = typeof max === "number" ? max : max.maxValue;
926
+ if (max) schema.maximum = typeof max === "number" ? max : max.maxValue;
846
927
  }
847
- return schema$1;
928
+ return schema;
848
929
  }
849
930
  });
850
931
  };
@@ -855,9 +936,28 @@ else schema$1.allOf = (schema$1.allOf || []).concat(patterns.map((p) => ({ patte
855
936
  };
856
937
  return schema;
857
938
  }
858
- function fromJsonSchema(schema) {
939
+ /**
940
+ * Converts a JSON Schema object into a {@link TAtscriptAnnotatedType}.
941
+ *
942
+ * This is the inverse of {@link buildJsonSchema}. A round-trip
943
+ * `buildJsonSchema(fromJsonSchema(schema))` preserves structure and constraints.
944
+ *
945
+ * Supports the JSON Schema subset produced by `buildJsonSchema` plus
946
+ * common extensions like `oneOf` (treated as union) and `enum` (union of literals).
947
+ *
948
+ * @example
949
+ * ```ts
950
+ * import { fromJsonSchema } from '@atscript/typescript'
951
+ *
952
+ * const type = fromJsonSchema({ type: 'object', properties: { name: { type: 'string' } }, required: ['name'] })
953
+ * type.validator().validate({ name: 'Alice' }) // passes
954
+ * ```
955
+ *
956
+ * @param schema - A JSON Schema object.
957
+ * @returns An annotated type with full validator support.
958
+ */ function fromJsonSchema(schema) {
859
959
  const defsSource = schema.$defs || schema.definitions || {};
860
- const resolved = new Map();
960
+ const resolved = /* @__PURE__ */ new Map();
861
961
  const convert = (s) => {
862
962
  if (!s || Object.keys(s).length === 0) return defineAnnotatedType().designType("any").$type;
863
963
  if (s.$ref) {
@@ -920,9 +1020,9 @@ function fromJsonSchema(schema) {
920
1020
  }
921
1021
  if (s.type === "array") {
922
1022
  if (Array.isArray(s.items)) {
923
- const handle$1 = defineAnnotatedType("tuple");
924
- for (const item of s.items) handle$1.item(convert(item));
925
- return handle$1.$type;
1023
+ const handle = defineAnnotatedType("tuple");
1024
+ for (const item of s.items) handle.item(convert(item));
1025
+ return handle.$type;
926
1026
  }
927
1027
  const itemType = s.items ? convert(s.items) : defineAnnotatedType().designType("any").$type;
928
1028
  const handle = defineAnnotatedType("array").of(itemType);
@@ -959,7 +1059,16 @@ function fromJsonSchema(schema) {
959
1059
  };
960
1060
  return convert(schema);
961
1061
  }
962
- function mergeJsonSchemas(types) {
1062
+ /**
1063
+ * Merges multiple annotated types into a combined schema map with shared `$defs`.
1064
+ *
1065
+ * Each type must have an `id`. The returned `schemas` object contains individual
1066
+ * schemas keyed by type id, and `$defs` contains all shared type definitions
1067
+ * deduplicated across schemas.
1068
+ *
1069
+ * @param types - Array of annotated types, each with an `id`.
1070
+ * @returns An object with `schemas` (keyed by id) and shared `$defs`.
1071
+ */ function mergeJsonSchemas(types) {
963
1072
  const mergedDefs = {};
964
1073
  const schemas = {};
965
1074
  for (const type of types) {
@@ -968,7 +1077,7 @@ function mergeJsonSchemas(types) {
968
1077
  const schema = buildJsonSchema(type);
969
1078
  if (schema.$defs) {
970
1079
  for (const [defName, defSchema] of Object.entries(schema.$defs)) if (!mergedDefs[defName]) mergedDefs[defName] = defSchema;
971
- const { $defs: _,...rest } = schema;
1080
+ const { $defs: _, ...rest } = schema;
972
1081
  schemas[name] = rest;
973
1082
  } else schemas[name] = schema;
974
1083
  }