@tsed/schema 8.13.5 → 8.14.0

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.
Files changed (87) hide show
  1. package/lib/esm/components/default/anyMapper.js +1 -2
  2. package/lib/esm/components/default/classMapper.js +2 -22
  3. package/lib/esm/components/default/genericsMapper.js +62 -48
  4. package/lib/esm/components/default/lazyRefMapper.js +1 -2
  5. package/lib/esm/components/default/mapMapper.js +0 -2
  6. package/lib/esm/components/default/nextMapper.js +74 -0
  7. package/lib/esm/components/default/objectMapper.js +8 -3
  8. package/lib/esm/components/default/ofMapper.js +2 -5
  9. package/lib/esm/components/default/requiredMapper.js +2 -2
  10. package/lib/esm/components/default/schemaMapper.js +6 -7
  11. package/lib/esm/components/index.js +1 -7
  12. package/lib/esm/components/open-spec/nullableMapper.js +5 -1
  13. package/lib/esm/components/open-spec/operationInParameterMapper.js +3 -7
  14. package/lib/esm/components/open-spec/operationInQueryMapper.js +22 -17
  15. package/lib/esm/components/open-spec/operationMediaMapper.js +5 -2
  16. package/lib/esm/components/open-spec/operationRequestBodyMapper.js +2 -2
  17. package/lib/esm/constants/VendorKeys.js +11 -0
  18. package/lib/esm/decorators/collections/collectionOf.js +14 -3
  19. package/lib/esm/decorators/common/description.js +9 -12
  20. package/lib/esm/decorators/common/discriminatorKey.js +1 -1
  21. package/lib/esm/decorators/common/forwardGroups.js +1 -1
  22. package/lib/esm/decorators/common/groups.js +15 -26
  23. package/lib/esm/decorators/common/oneOf.js +1 -1
  24. package/lib/esm/decorators/generics/genericOf.js +8 -17
  25. package/lib/esm/decorators/generics/generics.js +3 -3
  26. package/lib/esm/decorators/operations/redirect.js +1 -1
  27. package/lib/esm/decorators/operations/returns.js +40 -63
  28. package/lib/esm/domain/JsonEntityStore.js +40 -41
  29. package/lib/esm/domain/JsonMedia.js +27 -6
  30. package/lib/esm/domain/JsonMethodStore.js +28 -9
  31. package/lib/esm/domain/JsonOperation.js +15 -0
  32. package/lib/esm/domain/JsonParameter.js +11 -10
  33. package/lib/esm/domain/JsonParameterStore.js +3 -9
  34. package/lib/esm/domain/JsonPropertyStore.js +14 -45
  35. package/lib/esm/domain/JsonSchema.js +287 -80
  36. package/lib/esm/fn/email.js +2 -2
  37. package/lib/esm/fn/uri.js +2 -2
  38. package/lib/esm/fn/url.js +2 -2
  39. package/lib/esm/index.js +3 -8
  40. package/lib/esm/utils/generics.js +3 -32
  41. package/lib/esm/utils/getJsonSchema.js +24 -17
  42. package/lib/esm/utils/mergeSchema.js +98 -0
  43. package/lib/esm/utils/ref.js +14 -13
  44. package/lib/types/components/default/classMapper.d.ts +1 -1
  45. package/lib/types/components/default/genericsMapper.d.ts +9 -2
  46. package/lib/types/components/default/lazyRefMapper.d.ts +1 -1
  47. package/lib/types/components/default/nextMapper.d.ts +5 -0
  48. package/lib/types/components/default/ofMapper.d.ts +1 -1
  49. package/lib/types/components/index.d.ts +1 -7
  50. package/lib/types/components/open-spec/nullableMapper.d.ts +2 -1
  51. package/lib/types/components/open-spec/operationInQueryMapper.d.ts +1 -1
  52. package/lib/types/constants/VendorKeys.d.ts +10 -0
  53. package/lib/types/decorators/collections/collectionOf.d.ts +1 -1
  54. package/lib/types/decorators/generics/genericOf.d.ts +3 -0
  55. package/lib/types/decorators/generics/generics.d.ts +2 -2
  56. package/lib/types/decorators/operations/returns.d.ts +11 -9
  57. package/lib/types/domain/JsonEntityStore.d.ts +20 -18
  58. package/lib/types/domain/JsonMedia.d.ts +4 -5
  59. package/lib/types/domain/JsonMethodStore.d.ts +9 -2
  60. package/lib/types/domain/JsonOperation.d.ts +1 -0
  61. package/lib/types/domain/JsonParameter.d.ts +2 -7
  62. package/lib/types/domain/JsonParameterStore.d.ts +0 -2
  63. package/lib/types/domain/JsonPropertyStore.d.ts +1 -20
  64. package/lib/types/domain/JsonSchema.d.ts +82 -39
  65. package/lib/types/index.d.ts +3 -8
  66. package/lib/types/interfaces/JsonSchemaOptions.d.ts +16 -2
  67. package/lib/types/utils/generics.d.ts +7 -48
  68. package/lib/types/utils/getJsonSchema.d.ts +2 -1
  69. package/lib/types/utils/mergeSchema.d.ts +2 -0
  70. package/lib/types/utils/ref.d.ts +4 -2
  71. package/package.json +7 -7
  72. package/lib/esm/components/async-api/channelsMapper.js +0 -57
  73. package/lib/esm/components/async-api/generate.js +0 -17
  74. package/lib/esm/components/async-api/messageMapper.js +0 -39
  75. package/lib/esm/components/async-api/payloadMapper.js +0 -47
  76. package/lib/esm/components/async-api/responseMapper.js +0 -53
  77. package/lib/esm/components/default/itemMapper.js +0 -5
  78. package/lib/esm/components/default/propertiesMapper.js +0 -20
  79. package/lib/esm/utils/somethingOf.js +0 -11
  80. package/lib/types/components/async-api/channelsMapper.d.ts +0 -2
  81. package/lib/types/components/async-api/generate.d.ts +0 -1
  82. package/lib/types/components/async-api/messageMapper.d.ts +0 -6
  83. package/lib/types/components/async-api/payloadMapper.d.ts +0 -4
  84. package/lib/types/components/async-api/responseMapper.d.ts +0 -6
  85. package/lib/types/components/default/itemMapper.d.ts +0 -2
  86. package/lib/types/components/default/propertiesMapper.d.ts +0 -3
  87. package/lib/types/utils/somethingOf.d.ts +0 -1
@@ -1,5 +1,5 @@
1
1
  import { __decorate } from "tslib";
2
- import { DecoratorTypes, Metadata, prototypeOf } from "@tsed/core";
2
+ import { DecoratorTypes, isClass, Metadata, prototypeOf } from "@tsed/core";
3
3
  import { JsonEntityComponent } from "../decorators/config/jsonEntityComponent.js";
4
4
  import { JsonEntityStore } from "./JsonEntityStore.js";
5
5
  import { JsonSchema } from "./JsonSchema.js";
@@ -8,43 +8,8 @@ let JsonPropertyStore = class JsonPropertyStore extends JsonEntityStore {
8
8
  super(...arguments);
9
9
  this.parent = JsonEntityStore.from(this.target);
10
10
  }
11
- /**
12
- * Return the required state.
13
- * @returns {boolean}
14
- */
15
- get required() {
16
- return this.parent.schema.isRequired(this.propertyKey);
17
- }
18
- /**
19
- * Change the state of the required data.
20
- * @param value
21
- */
22
- set required(value) {
23
- if (value) {
24
- this.parent.schema.addRequired(this.propertyKey);
25
- }
26
- else {
27
- this.parent.schema.removeRequired(this.propertyKey);
28
- }
29
- }
30
- get allowedRequiredValues() {
31
- return this.schema.$allow;
32
- }
33
- discriminatorKey() {
34
- this.parent.schema.discriminatorKey(String(this.propertyKey));
35
- this.itemSchema.isDiscriminatorKey = true;
36
- return this;
37
- }
38
- isDiscriminatorKey() {
39
- return this.itemSchema.isDiscriminatorKey;
40
- }
41
- /**
42
- * Check precondition between value, required and allowedRequiredValues to know if the entity is required.
43
- * @param value
44
- * @returns {boolean}
45
- */
46
- isRequired(value) {
47
- return this.required && [undefined, null, ""].includes(value) && !this.allowedRequiredValues.includes(value);
11
+ static get(target, propertyKey) {
12
+ return JsonEntityStore.from(prototypeOf(target), propertyKey);
48
13
  }
49
14
  build() {
50
15
  if (!this._type) {
@@ -55,19 +20,23 @@ let JsonPropertyStore = class JsonPropertyStore extends JsonEntityStore {
55
20
  let schema = properties[this.propertyName];
56
21
  if (!schema) {
57
22
  this.parent.children.set(this.propertyName, this);
58
- schema = JsonSchema.from({
59
- type: this.collectionType || this.type
60
- });
61
- if (this.collectionType) {
23
+ if (this.isCollection) {
24
+ schema = JsonSchema.from({
25
+ type: this.collectionType
26
+ });
27
+ schema.itemSchema(this.type);
28
+ }
29
+ else if (isClass(this.type)) {
30
+ schema = JsonSchema.from({ type: "object" });
62
31
  schema.itemSchema(this.type);
63
32
  }
33
+ else {
34
+ schema = JsonSchema.from({ type: this.type });
35
+ }
64
36
  }
65
37
  this.parent.schema.addProperty(this.propertyName, schema);
66
38
  this._schema = schema;
67
39
  }
68
- static get(target, propertyKey) {
69
- return JsonEntityStore.from(prototypeOf(target), propertyKey);
70
- }
71
40
  };
72
41
  JsonPropertyStore = __decorate([
73
42
  JsonEntityComponent(DecoratorTypes.PROP)
@@ -1,9 +1,11 @@
1
- import { ancestorsOf, classOf, isArray, isClass, isFunction, isObject, isPrimitiveClass, nameOf, uniq } from "@tsed/core";
1
+ import { ancestorOf, ancestorsOf, classOf, isArray, isClass, isFunction, isObject, isPlainObject, isPrimitiveClass, nameOf, uniq } from "@tsed/core";
2
2
  import { Hooks } from "@tsed/hooks";
3
+ import { VendorKeys } from "../constants/VendorKeys.js";
3
4
  import { enumsRegistry } from "../registries/enumRegistries.js";
4
5
  import { execMapper } from "../registries/JsonSchemaMapperContainer.js";
5
6
  import { getComputedType } from "../utils/getComputedType.js";
6
7
  import { getJsonType } from "../utils/getJsonType.js";
8
+ import { matchGroups } from "../utils/matchGroups.js";
7
9
  import { serializeEnumValues } from "../utils/serializeEnumValues.js";
8
10
  import { toJsonRegex } from "../utils/toJsonRegex.js";
9
11
  import { Discriminator } from "./JsonDiscriminator.js";
@@ -15,6 +17,9 @@ function mapProperties(properties) {
15
17
  }
16
18
  return Object.entries(properties).reduce((properties, [key, schema]) => {
17
19
  properties[toJsonRegex(key)] = mapToJsonSchema(schema);
20
+ if (schema instanceof JsonSchema) {
21
+ schema.propertyKey(toJsonRegex(key));
22
+ }
18
23
  return properties;
19
24
  }, {});
20
25
  }
@@ -36,35 +41,83 @@ function mapToJsonSchema(item) {
36
41
  }
37
42
  return item;
38
43
  }
44
+ function isEnum(type) {
45
+ return isObject(type) && !("toJSON" in type);
46
+ }
47
+ function mapGenerics(jsonSchema, generics) {
48
+ const genericLabels = jsonSchema.getGenericLabels();
49
+ if (!genericLabels) {
50
+ return {};
51
+ }
52
+ const [types, ...nextTypes] = generics;
53
+ return types.reduce((mapping, type, index) => {
54
+ const label = genericLabels[index];
55
+ if (label) {
56
+ if (isEnum(type)) {
57
+ mapping[label] = [JsonSchema.from({ type: "string", enum: Object.values(type) })];
58
+ }
59
+ else if (nextTypes.length) {
60
+ const nextSchema = mapToJsonSchema(type);
61
+ mapping[label] = [nextSchema, mapGenerics(nextSchema, nextTypes)];
62
+ }
63
+ else {
64
+ mapping[label] = [mapToJsonSchema(type)];
65
+ }
66
+ }
67
+ return mapping;
68
+ }, {});
69
+ }
39
70
  export class JsonSchema extends Map {
40
- #nullable;
71
+ /**
72
+ * All required fields are stored here
73
+ * @private
74
+ */
75
+ #required;
76
+ /**
77
+ * Internal custom props
78
+ * @private
79
+ */
80
+ #vendors;
41
81
  #discriminator;
42
- #genericLabels;
43
- #nestedGenerics;
44
82
  #alias;
45
83
  #itemSchema;
84
+ /**
85
+ * This flag is used to know if the schema is created to link property/param to a class schema.
86
+ * @private
87
+ */
88
+ #isLocalSchema;
46
89
  #target;
47
- #isGeneric;
48
90
  #isCollection;
49
- #ref;
91
+ #useRefLabel;
92
+ #propertyKey;
50
93
  constructor(obj = {}) {
51
94
  super();
52
95
  this.$kind = "schema";
53
96
  this.$isJsonDocument = true;
54
97
  this.$hooks = new Hooks();
55
- this.$required = new Set();
56
98
  this.$allow = [];
57
- this.$forwardGroups = false;
58
99
  this.$ignore = false;
59
100
  this.isDiscriminatorKey = false;
60
101
  this.isDiscriminator = false;
61
- this.#nullable = false;
102
+ /**
103
+ * All required fields are stored here
104
+ * @private
105
+ */
106
+ this.#required = new Set();
107
+ /**
108
+ * Internal custom props
109
+ * @private
110
+ */
111
+ this.#vendors = new Map();
62
112
  this.#discriminator = null;
63
- this.#nestedGenerics = [];
64
113
  this.#alias = new Map();
65
- this.#isGeneric = false;
114
+ /**
115
+ * This flag is used to know if the schema is created to link property/param to a class schema.
116
+ * @private
117
+ */
118
+ this.#isLocalSchema = false;
66
119
  this.#isCollection = false;
67
- this.#ref = false;
120
+ this.#useRefLabel = false;
68
121
  if (obj) {
69
122
  this.assign(obj);
70
123
  }
@@ -72,32 +125,27 @@ export class JsonSchema extends Map {
72
125
  get alias() {
73
126
  return this.#alias;
74
127
  }
75
- get nestedGenerics() {
76
- return this.#nestedGenerics;
77
- }
78
- set nestedGenerics(value) {
79
- this.#nestedGenerics = value;
80
- }
81
- get genericLabels() {
82
- return this.#genericLabels;
83
- }
84
- set genericLabels(value) {
85
- this.#genericLabels = value;
86
- }
87
128
  get isClass() {
88
- return isClass(this.class) && ![Map, Array, Set, Object, Date, Boolean, Number, String].includes(this.#target);
129
+ return isClass(this.class) && !this.isCollection;
89
130
  }
90
131
  /**
91
- * Current schema is a collection
132
+ * The current schema is a collection
92
133
  */
93
134
  get isCollection() {
94
135
  return this.#isCollection;
95
136
  }
137
+ /**
138
+ * The current schema is a reference to another schema
139
+ * to link property/param to a class schema (if the reference exists).
140
+ */
141
+ get isLocalSchema() {
142
+ return this.#isLocalSchema;
143
+ }
96
144
  /**
97
145
  * Current schema is a generic
98
146
  */
99
147
  get isGeneric() {
100
- return this.#isGeneric;
148
+ return this.has(VendorKeys.GENERIC_LABEL);
101
149
  }
102
150
  get discriminatorAncestor() {
103
151
  const ancestors = ancestorsOf(this.#target);
@@ -105,22 +153,27 @@ export class JsonSchema extends Map {
105
153
  return ancestor && JsonEntityStore.from(ancestor).schema;
106
154
  }
107
155
  /**
108
- * Current schema has generics items
156
+ * Return the itemSchema computed type.
157
+ * If the type is a function used for a recursive model,
158
+ * the function will be called to get the right type.
109
159
  */
110
- get hasGenerics() {
111
- return !!(this.nestedGenerics && this.nestedGenerics.length);
112
- }
113
- get genericType() {
114
- return this.get("$ref");
115
- }
116
160
  get class() {
117
- return this.getComputedType();
161
+ if (this.#isLocalSchema) {
162
+ return this.#itemSchema?.getTarget();
163
+ }
164
+ return getComputedType(this.#target);
165
+ }
166
+ /**
167
+ * Return the itemSchema computed type.
168
+ */
169
+ get collectionClass() {
170
+ return this.isCollection && this.#itemSchema ? this.#itemSchema.class : this.class;
118
171
  }
119
172
  get canRef() {
120
- return this.#ref;
173
+ return this.#useRefLabel;
121
174
  }
122
175
  get isNullable() {
123
- return this.#nullable;
176
+ return !!this.get("nullable");
124
177
  }
125
178
  get isReadOnly() {
126
179
  return this.get("readOnly");
@@ -131,15 +184,105 @@ export class JsonSchema extends Map {
131
184
  get hasDiscriminator() {
132
185
  return !!this.#discriminator;
133
186
  }
134
- static from(obj = {}) {
135
- return new JsonSchema(obj);
187
+ static from(item = {}) {
188
+ if (item instanceof JsonSchema) {
189
+ return item;
190
+ }
191
+ if (classOf(item) !== Object && isClass(item)) {
192
+ return JsonEntityStore.from(item).schema;
193
+ }
194
+ if (isPrimitiveClass(item)) {
195
+ return new JsonSchema({ type: item });
196
+ }
197
+ return new JsonSchema(item);
198
+ }
199
+ /**
200
+ * Check if the schema as key, #key or x-key
201
+ * @param key
202
+ */
203
+ has(key) {
204
+ if (super.has(key)) {
205
+ return true;
206
+ }
207
+ if (super.has(`#${key}`)) {
208
+ return true;
209
+ }
210
+ return this.#vendors.has(key);
211
+ }
212
+ get(key, defaultValue) {
213
+ if (this.#vendors.has(key)) {
214
+ return this.#vendors.get(key);
215
+ }
216
+ if (super.has(key)) {
217
+ return super.get(key);
218
+ }
219
+ if (super.has(`#${key}`)) {
220
+ return super.get(`#${key}`);
221
+ }
222
+ return defaultValue;
223
+ }
224
+ forwardGroups(bool = true) {
225
+ this.vendorKey(VendorKeys.FORWARD_GROUPS, bool);
226
+ return this;
227
+ }
228
+ groups(groups, isProperty) {
229
+ if (groups) {
230
+ this.vendorKey(VendorKeys.GROUPS, groups);
231
+ // this.customKey("x-groups", groups);
232
+ if (isProperty) {
233
+ this.$hooks.on("groups", (prev, givenGroups) => {
234
+ if (!prev) {
235
+ if (matchGroups(groups, givenGroups)) {
236
+ return true;
237
+ }
238
+ }
239
+ return prev;
240
+ });
241
+ }
242
+ }
243
+ return this;
244
+ }
245
+ groupsName(groupsName) {
246
+ groupsName && this.vendorKey(VendorKeys.GROUPS_NAME, groupsName);
247
+ return this;
248
+ }
249
+ allowedGroups(groups) {
250
+ groups && this.vendorKey(VendorKeys.ALLOWED_GROUPS, groups);
251
+ return this;
252
+ }
253
+ /**
254
+ * Assign the Generic Labels used over a class or a schema.
255
+ * @param genericLabels
256
+ */
257
+ genericLabels(genericLabels) {
258
+ this.vendorKey(VendorKeys.GENERIC_LABELS, genericLabels);
259
+ return this;
260
+ }
261
+ genericLabel(genericLabel) {
262
+ this.vendorKey(VendorKeys.GENERIC_LABEL, genericLabel);
263
+ return this;
264
+ }
265
+ /**
266
+ * Assign the types of the generics that must be used for the property
267
+ * @param generics
268
+ */
269
+ genericOf(...generics) {
270
+ const mapped = mapGenerics(this.#itemSchema || mapToJsonSchema(this.getTarget()), generics);
271
+ this.vendorKey(VendorKeys.GENERIC_OF, mapped);
272
+ return this;
136
273
  }
137
274
  nullable(value) {
138
- this.#nullable = value;
275
+ this.vendorKey(VendorKeys.NULLABLE, value);
276
+ return this;
139
277
  }
140
278
  itemSchema(obj = {}) {
141
279
  this.#itemSchema = this.#itemSchema || mapToJsonSchema(obj);
142
- this.#itemSchema.assign(obj);
280
+ if (isPlainObject(obj)) {
281
+ this.#itemSchema.assign(obj);
282
+ }
283
+ if (!this.isCollection && this.#itemSchema?.isClass) {
284
+ this.#isLocalSchema = true;
285
+ }
143
286
  return this.#itemSchema;
144
287
  }
145
288
  getAliasOf(property) {
@@ -173,7 +316,7 @@ export class JsonSchema extends Map {
173
316
  * @param name
174
317
  */
175
318
  label(name) {
176
- this.#ref = true;
319
+ this.#useRefLabel = true;
177
320
  super.set("name", name);
178
321
  return this;
179
322
  }
@@ -225,6 +368,15 @@ export class JsonSchema extends Map {
225
368
  discriminatorKey(propertyName) {
226
369
  this.discriminator().propertyName = propertyName;
227
370
  this.isDiscriminator = true;
371
+ const propertySchema = this.get("properties")[propertyName];
372
+ if (propertySchema) {
373
+ if (propertySchema.isCollection) {
374
+ propertySchema.itemSchema().isDiscriminatorKey = true;
375
+ }
376
+ else {
377
+ propertySchema.isDiscriminatorKey = true;
378
+ }
379
+ }
228
380
  return this;
229
381
  }
230
382
  discriminatorValue(...values) {
@@ -368,8 +520,8 @@ export class JsonSchema extends Map {
368
520
  */
369
521
  required(required = true) {
370
522
  if (isArray(required)) {
371
- this.$required.clear();
372
- required.forEach((value) => this.$required.add(value));
523
+ this.#required.clear();
524
+ required.forEach((value) => this.#required.add(value));
373
525
  }
374
526
  else {
375
527
  const schema = this.clone();
@@ -382,15 +534,18 @@ export class JsonSchema extends Map {
382
534
  return this;
383
535
  }
384
536
  addRequired(property) {
385
- this.$required.add(property);
537
+ this.#required.add(property);
386
538
  return this;
387
539
  }
388
540
  removeRequired(property) {
389
- this.$required.delete(property);
541
+ this.#required.delete(property);
390
542
  return this;
391
543
  }
392
544
  isRequired(property) {
393
- return this.$required.has(property);
545
+ return this.#required.has(property);
546
+ }
547
+ getRequiredFields() {
548
+ return [...this.#required];
394
549
  }
395
550
  /**
396
551
  * This keyword determines how child instances validate for objects, and does not directly validate the immediate instance itself.
@@ -508,7 +663,12 @@ export class JsonSchema extends Map {
508
663
  * @see https://tools.ietf.org/html/draft-wright-json-schema-validation-01#section-6.28
509
664
  */
510
665
  oneOf(oneOf) {
511
- this.setManyOf("oneOf", oneOf);
666
+ if (this.isCollection) {
667
+ this.itemSchema().oneOf(oneOf);
668
+ }
669
+ else {
670
+ this.setManyOf("oneOf", oneOf);
671
+ }
512
672
  return this;
513
673
  }
514
674
  /**
@@ -606,7 +766,7 @@ export class JsonSchema extends Map {
606
766
  case "map":
607
767
  case Map:
608
768
  super.set("type", getJsonType(type));
609
- this.#target = type;
769
+ this.target(type);
610
770
  this.#isCollection = true;
611
771
  if (!this.has("additionalProperties")) {
612
772
  super.set("additionalProperties", this.itemSchema({}));
@@ -615,7 +775,7 @@ export class JsonSchema extends Map {
615
775
  case "array":
616
776
  case Array:
617
777
  super.set("type", getJsonType(type));
618
- this.#target = type;
778
+ this.target(type);
619
779
  this.#isCollection = true;
620
780
  if (!this.has("items")) {
621
781
  super.set("items", this.itemSchema({}));
@@ -624,7 +784,7 @@ export class JsonSchema extends Map {
624
784
  case "set":
625
785
  case Set:
626
786
  super.set("type", getJsonType(type));
627
- this.#target = type;
787
+ this.target(type);
628
788
  this.#isCollection = true;
629
789
  this.uniqueItems(true);
630
790
  if (!this.has("items")) {
@@ -644,7 +804,7 @@ export class JsonSchema extends Map {
644
804
  case Number:
645
805
  case String:
646
806
  super.set("type", getJsonType(type));
647
- this.#target = type;
807
+ this.target(type);
648
808
  if (!this.has("properties")) {
649
809
  super.set("properties", {});
650
810
  }
@@ -652,7 +812,7 @@ export class JsonSchema extends Map {
652
812
  default:
653
813
  if (isClass(type) || isFunction(type)) {
654
814
  super.set("type", undefined);
655
- this.#target = type;
815
+ this.target(type);
656
816
  if (!this.has("properties")) {
657
817
  super.set("properties", {});
658
818
  }
@@ -660,8 +820,7 @@ export class JsonSchema extends Map {
660
820
  else {
661
821
  const jsonType = getJsonType(type);
662
822
  if (jsonType === "generic") {
663
- this.#isGeneric = true;
664
- super.set("$ref", type);
823
+ this.genericLabel(type);
665
824
  }
666
825
  else {
667
826
  super.set("type", jsonType);
@@ -709,6 +868,10 @@ export class JsonSchema extends Map {
709
868
  super.set(`#${key}`, value);
710
869
  return this;
711
870
  }
871
+ vendorKey(key, value) {
872
+ this.#vendors.set(key, value);
873
+ return this;
874
+ }
712
875
  toObject(options) {
713
876
  return this.toJSON(options);
714
877
  }
@@ -723,21 +886,16 @@ export class JsonSchema extends Map {
723
886
  if (obj instanceof JsonSchema) {
724
887
  this.$selfRequired = obj.$selfRequired;
725
888
  this.$allow.push(...obj.$allow);
726
- obj.$required.forEach((key) => {
727
- this.$required.add(key);
728
- });
889
+ this.#required = new Set(obj.#required.keys());
890
+ this.#alias = new Map(this.#alias.entries());
891
+ this.#vendors = new Map(obj.#vendors.entries());
729
892
  this.#discriminator = this.#discriminator ? new Discriminator(this.#discriminator) : null;
730
893
  this.isDiscriminator = obj.isDiscriminator;
731
894
  this.isDiscriminatorKey = obj.isDiscriminatorKey;
732
- this.#ref = obj.#ref;
733
- this.#alias = new Map(this.#alias.entries());
734
- obj.#genericLabels && (this.#genericLabels = [...obj.#genericLabels]);
735
- this.#nestedGenerics = obj.#nestedGenerics.map((item) => [...item]);
895
+ this.#useRefLabel = obj.#useRefLabel;
736
896
  this.#target = obj.#target;
737
- this.#isGeneric = obj.#isGeneric;
738
897
  this.#isCollection = obj.#isCollection;
739
- this.#ref = obj.#ref;
740
- this.#nullable = obj.#nullable;
898
+ this.#isLocalSchema = obj.#isLocalSchema;
741
899
  super.set("type", obj.get("type"));
742
900
  }
743
901
  return this;
@@ -751,17 +909,6 @@ export class JsonSchema extends Map {
751
909
  }
752
910
  return this;
753
911
  }
754
- /**
755
- * Return the itemSchema computed type.
756
- * If the type is a function used for recursive model,
757
- * the function will be called to get the right type.
758
- */
759
- getComputedType() {
760
- return getComputedType(this.#target);
761
- }
762
- getComputedItemType() {
763
- return this.#itemSchema ? this.#itemSchema.getComputedType() : this.getComputedType();
764
- }
765
912
  /**
766
913
  * Return the Json type as string
767
914
  */
@@ -771,24 +918,84 @@ export class JsonSchema extends Map {
771
918
  return o.getJsonType();
772
919
  });
773
920
  }
774
- return this.get("type") || getJsonType(this.getComputedType());
921
+ return this.get("type") || getJsonType(this.class);
775
922
  }
776
923
  getTarget() {
777
924
  return this.#target;
778
925
  }
926
+ getAllowedGroups() {
927
+ return this.get(VendorKeys.ALLOWED_GROUPS);
928
+ }
929
+ getAllowedRequiredValues() {
930
+ return this.$allow;
931
+ }
932
+ getGroups() {
933
+ return this.get(VendorKeys.GROUPS);
934
+ }
935
+ getGroupsName() {
936
+ return this.get(VendorKeys.GROUPS_NAME);
937
+ }
779
938
  /**
780
939
  * Get the symbolic name of the entity
781
940
  */
782
941
  getName() {
783
- return this.get("name") || (isClass(this.#target) ? nameOf(classOf(this.getComputedType())) : "");
942
+ return this.get("name") || (isClass(this.#target) ? nameOf(classOf(this.class)) : "");
784
943
  }
785
944
  clone() {
786
945
  return new JsonSchema(this);
787
946
  }
947
+ getGenericLabels() {
948
+ const labels = this.get(VendorKeys.GENERIC_LABELS);
949
+ if (this.isClass && !labels) {
950
+ const ancestor = ancestorOf(this.class);
951
+ return ancestor === Object ? undefined : JsonSchema.from(ancestor).getGenericLabels();
952
+ }
953
+ return this.get(VendorKeys.GENERIC_LABELS);
954
+ }
955
+ getGenericOf() {
956
+ return this.get(VendorKeys.GENERIC_OF);
957
+ }
958
+ /**
959
+ * Returns the reference schema for class-based schemas.
960
+ * Used to get the original schema definition when this schema is a local reference.
961
+ * @returns The reference schema or undefined if not applicable
962
+ */
963
+ getRefSchema() {
964
+ if (!this.isLocalSchema && this.isClass) {
965
+ const refSchema = JsonSchema.from(this.class);
966
+ if (refSchema !== this) {
967
+ return refSchema;
968
+ }
969
+ }
970
+ }
971
+ propertyKey(s) {
972
+ this.#propertyKey = s;
973
+ return this;
974
+ }
975
+ getPropertyKey() {
976
+ return this.#propertyKey;
977
+ }
978
+ target(target) {
979
+ if (target === "object") {
980
+ this.#target = Object;
981
+ }
982
+ else {
983
+ this.#target = target;
984
+ }
985
+ }
986
+ isRequiredValue(property, value) {
987
+ if (this.isRequired(property) && [undefined, null, ""].includes(value)) {
988
+ const propertySchema = this.get("properties")?.[property];
989
+ if (propertySchema) {
990
+ return !propertySchema.getAllowedRequiredValues().includes(value);
991
+ }
992
+ }
993
+ return false;
994
+ }
788
995
  setManyOf(keyword, value) {
789
996
  let resolved = value
790
997
  .filter((o) => {
791
- if (o?.type === "null") {
998
+ if (o && "type" in o && o.type === "null") {
792
999
  this.nullable(true);
793
1000
  return false;
794
1001
  }
@@ -807,7 +1014,7 @@ export class JsonSchema extends Map {
807
1014
  }
808
1015
  super.set(keyword, resolved);
809
1016
  const jsonSchema = resolved[0];
810
- if (jsonSchema.isDiscriminator) {
1017
+ if (jsonSchema?.isDiscriminator) {
811
1018
  const discriminator = jsonSchema.discriminatorAncestor.discriminator();
812
1019
  const { propertyName } = discriminator;
813
1020
  super.set("discriminator", {
@@ -1,5 +1,5 @@
1
1
  import { JsonFormatTypes } from "../domain/JsonFormatTypes.js";
2
- import { from } from "./from.js";
2
+ import { string } from "./string.js";
3
3
  /**
4
4
  * Declare a new string model with `format: email`.
5
5
  *
@@ -13,5 +13,5 @@ import { from } from "./from.js";
13
13
  * ```
14
14
  */
15
15
  export function email() {
16
- return from(String).format(JsonFormatTypes.EMAIL);
16
+ return string().format(JsonFormatTypes.EMAIL);
17
17
  }
package/lib/esm/fn/uri.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { JsonFormatTypes } from "../domain/JsonFormatTypes.js";
2
- import { from } from "./from.js";
2
+ import { string } from "./string.js";
3
3
  /**
4
4
  * Declare a new string model with `format: uri`.
5
5
  *
@@ -8,5 +8,5 @@ import { from } from "./from.js";
8
8
  * @schemaFunctional
9
9
  */
10
10
  export function uri() {
11
- return from(String).format(JsonFormatTypes.URI);
11
+ return string().format(JsonFormatTypes.URI);
12
12
  }