@tsed/schema 8.13.4 → 8.14.0-rc.1

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 +11 -8
  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,7 +1,6 @@
1
1
  import { JsonLazyRef } from "../../domain/JsonLazyRef.js";
2
2
  import { JsonSchema } from "../../domain/JsonSchema.js";
3
3
  import { execMapper, execOneOfMapper, registerJsonSchemaMapper } from "../../registries/JsonSchemaMapperContainer.js";
4
- import { mapGenericsOptions } from "../../utils/generics.js";
5
4
  import { toRef } from "../../utils/ref.js";
6
5
  export function anyMapper(input, options = {}) {
7
6
  if (typeof input !== "object" || input === null) {
@@ -16,7 +15,7 @@ export function anyMapper(input, options = {}) {
16
15
  }
17
16
  if (input.$kind && input.$isJsonDocument) {
18
17
  const kind = execOneOfMapper([input.$kind, "map"], options);
19
- const schema = execMapper(kind, [input], mapGenericsOptions(options));
18
+ const schema = execMapper(kind, [input], options);
20
19
  return input.canRef ? toRef(input, schema, options) : schema;
21
20
  }
22
21
  return execMapper("object", [input], options);
@@ -1,37 +1,17 @@
1
1
  import { getValue, setValue } from "@tsed/core";
2
2
  import { JsonEntityStore } from "../../domain/JsonEntityStore.js";
3
3
  import { execMapper, registerJsonSchemaMapper } from "../../registries/JsonSchemaMapperContainer.js";
4
- import { mapGenericsOptions, popGenerics } from "../../utils/generics.js";
5
4
  import { createRef, createRefName } from "../../utils/ref.js";
6
5
  export function classMapper(value, options) {
7
6
  const store = JsonEntityStore.from(value.class);
8
7
  const name = createRefName(store.schema.getName() || value.getName(), options);
9
- if (value.hasGenerics) {
10
- // Inline generic
11
- const { type, properties, additionalProperties, items, ...props } = value.toJSON(options);
12
- const schema = {
13
- ...execMapper("any", [store.schema], {
14
- ...options,
15
- ...popGenerics(value),
16
- root: false
17
- }),
18
- ...props
19
- };
20
- if (schema.title) {
21
- const name = createRefName(schema.title, options);
22
- setValue(options.components, `schemas.${name}`, schema);
23
- delete schema.title;
24
- return createRef(name, value, options);
25
- }
26
- return schema;
27
- }
28
8
  if (!getValue(options, `components.schemas.${name}`)) {
29
9
  // avoid infinite calls
30
10
  setValue(options, `components.schemas.${name}`, {});
31
- options.components.schemas[name] = execMapper("any", [store.schema], mapGenericsOptions({
11
+ options.components.schemas[name] = execMapper("any", [store.schema], {
32
12
  ...options,
33
13
  root: false
34
- }));
14
+ });
35
15
  }
36
16
  return createRef(name, value, options);
37
17
  }
@@ -1,57 +1,71 @@
1
- import { isClass, isPrimitiveClass } from "@tsed/core";
2
- import { JsonEntityStore } from "../../domain/JsonEntityStore.js";
1
+ import { isObject } from "@tsed/core";
2
+ import { VendorKeys } from "../../constants/VendorKeys.js";
3
+ import { JsonSchema } from "../../domain/JsonSchema.js";
3
4
  import { execMapper, registerJsonSchemaMapper } from "../../registries/JsonSchemaMapperContainer.js";
4
- import { popGenerics } from "../../utils/generics.js";
5
- import { getJsonType } from "../../utils/getJsonType.js";
5
+ import { toRef } from "../../utils/ref.js";
6
+ function getNestedSchema(propertyKey, schema, options) {
7
+ if ("isLazyRef" in schema) {
8
+ return null;
9
+ }
10
+ if (schema.isGeneric) {
11
+ const genericLabel = schema.get(VendorKeys.GENERIC_LABEL);
12
+ const genericValue = options.generics?.[genericLabel];
13
+ if (!genericValue) {
14
+ return null;
15
+ }
16
+ const [model, next] = genericValue;
17
+ const refSchema = JsonSchema.from(model);
18
+ const modelSchema = execMapper("schema", [refSchema], {
19
+ ...options,
20
+ generics: next
21
+ });
22
+ if (next || !refSchema.isClass) {
23
+ return modelSchema;
24
+ }
25
+ return toRef(refSchema, modelSchema, options);
26
+ }
27
+ if (schema?.has("items")) {
28
+ const nestedSchema = getNestedSchema(propertyKey, schema.get("items"), options);
29
+ if (nestedSchema) {
30
+ return {
31
+ type: "array",
32
+ items: nestedSchema
33
+ };
34
+ }
35
+ }
36
+ if (schema.has("additionalProperties") && isObject(schema.get("additionalProperties"))) {
37
+ const nestedSchema = getNestedSchema(propertyKey, schema.get("additionalProperties"), options);
38
+ if (nestedSchema) {
39
+ return {
40
+ type: "object",
41
+ additionalProperties: nestedSchema
42
+ };
43
+ }
44
+ }
45
+ return null;
46
+ }
6
47
  /**
7
48
  * @ignore
8
49
  */
9
- export function genericsMapper(obj, options) {
10
- const { generics } = options;
11
- if (generics && obj.$ref) {
12
- if (generics.has(obj.$ref)) {
13
- let type = generics.get(obj.$ref);
14
- if (isPrimitiveClass(type)) {
15
- return {
16
- type: getJsonType(type)
17
- };
18
- }
19
- if (type === Date) {
20
- return {
21
- type: "string",
22
- format: "date-time"
23
- };
24
- }
25
- if (type.toJSON) {
26
- return type.toJSON({
27
- ...options,
28
- generics: undefined
29
- });
30
- }
31
- if (type === Object) {
32
- return {
33
- type: "object"
34
- };
35
- }
36
- if (isClass(type)) {
37
- const model = {
38
- class: type
39
- };
40
- if (options.nestedGenerics.length === 0) {
41
- return execMapper("class", [model], {
42
- ...options,
43
- generics: undefined
44
- });
45
- }
46
- const store = JsonEntityStore.from(model.class);
47
- return execMapper("schema", [store.schema], {
48
- ...options,
49
- ...popGenerics(options),
50
- root: false
51
- });
50
+ export function genericsMapper(baseObj, schema, options) {
51
+ if (schema.genericLabels?.length && schema.has("properties")) {
52
+ const properties = schema.get("properties");
53
+ let hasProps = false;
54
+ const additionalObj = Object.entries(properties || {}).reduce((obj, [propertyKey, jsonSchema]) => {
55
+ const nestedSchema = getNestedSchema(propertyKey, jsonSchema, options);
56
+ if (nestedSchema) {
57
+ obj[propertyKey] = nestedSchema;
58
+ hasProps = true;
52
59
  }
60
+ return obj;
61
+ }, {});
62
+ if (hasProps) {
63
+ return {
64
+ allOf: [toRef(schema, baseObj, options), { properties: additionalObj, type: "object" }]
65
+ };
53
66
  }
67
+ return baseObj;
54
68
  }
55
- return obj;
69
+ return baseObj;
56
70
  }
57
71
  registerJsonSchemaMapper("generics", genericsMapper);
@@ -1,5 +1,4 @@
1
1
  import { execMapper, registerJsonSchemaMapper } from "../../registries/JsonSchemaMapperContainer.js";
2
- import { mapGenericsOptions } from "../../utils/generics.js";
3
2
  import { createRef, toRef } from "../../utils/ref.js";
4
3
  export function lazyRefMapper(jsonLazyRef, options) {
5
4
  const name = jsonLazyRef.name;
@@ -7,7 +6,7 @@ export function lazyRefMapper(jsonLazyRef, options) {
7
6
  return createRef(name, jsonLazyRef.schema, options);
8
7
  }
9
8
  options.$refs = [...(options.$refs || []), jsonLazyRef.target];
10
- const schema = jsonLazyRef.getType() && execMapper("schema", [jsonLazyRef.schema], mapGenericsOptions(options));
9
+ const schema = jsonLazyRef.getType() && execMapper("schema", [jsonLazyRef.schema], options);
11
10
  return toRef(jsonLazyRef.schema, schema, options);
12
11
  }
13
12
  registerJsonSchemaMapper("lazyRef", lazyRefMapper);
@@ -1,5 +1,4 @@
1
1
  import { execMapper, registerJsonSchemaMapper } from "../../registries/JsonSchemaMapperContainer.js";
2
- import { mapGenericsOptions } from "../../utils/generics.js";
3
2
  /**
4
3
  * Serialize class which inherit from Map like JsonMap, JsonOperation, JsonParameter.
5
4
  * @param input
@@ -8,7 +7,6 @@ import { mapGenericsOptions } from "../../utils/generics.js";
8
7
  * @ignore
9
8
  */
10
9
  export function mapMapper(input, { ignore = [], ...options } = {}) {
11
- options = mapGenericsOptions(options);
12
10
  return Array.from(input.entries()).reduce((obj, [key, value]) => {
13
11
  if (ignore.includes(key)) {
14
12
  return obj;
@@ -0,0 +1,74 @@
1
+ import { JsonSchema } from "../../domain/JsonSchema.js";
2
+ import { execMapper, registerJsonSchemaMapper } from "../../registries/JsonSchemaMapperContainer.js";
3
+ import { getGenericsOptions } from "../../utils/generics.js";
4
+ import { mergeSchema } from "../../utils/mergeSchema.js";
5
+ function getMapper(input, mapper, root) {
6
+ if (input.isClass && !input.isLocalSchema && !root) {
7
+ return mapper || "class";
8
+ }
9
+ return "any";
10
+ }
11
+ function buildAndMergeSchemas(mapper, schema1, schema2, options) {
12
+ const schema = execMapper(getMapper(schema2, mapper, options.root), [schema2], {
13
+ ...options,
14
+ root: false,
15
+ mapper: mapper === "next" ? options.mapper : undefined
16
+ });
17
+ let extraSchema = execMapper(options.root ? "any" : mapper, [schema1], {
18
+ ...options,
19
+ root: false,
20
+ generics: undefined,
21
+ mapper: mapper === "next" ? options.mapper : undefined
22
+ });
23
+ if ((schema.$ref || schema.allOf) && extraSchema.type && Object.keys(extraSchema).length === 1) {
24
+ extraSchema = {};
25
+ }
26
+ if (schema1.canRef) {
27
+ const name = extraSchema.$ref.split("/").pop();
28
+ const titleSchema = options.components.schemas[name];
29
+ options.components.schemas[name] = mergeSchema(schema, titleSchema);
30
+ return extraSchema;
31
+ }
32
+ return mergeSchema(schema, extraSchema);
33
+ }
34
+ export function itemMapper(input, options) {
35
+ if (input && input instanceof JsonSchema) {
36
+ if (!input.isCollection && input?.itemSchema?.()) {
37
+ const { generics, mapper } = getGenericsOptions(input, options);
38
+ const schema1 = input;
39
+ const schema2 = input.itemSchema();
40
+ return buildAndMergeSchemas("next", schema1, schema2, { ...options, generics, mapper });
41
+ }
42
+ }
43
+ return execMapper("next", [input], options);
44
+ }
45
+ export function nextMapper(input, options) {
46
+ if (input && input instanceof JsonSchema && !input.isLocalSchema) {
47
+ const refSchema = input.getRefSchema();
48
+ if (refSchema) {
49
+ let { generics, mapper } = getGenericsOptions(input, options);
50
+ mapper = getMapper(input, mapper);
51
+ return buildAndMergeSchemas(mapper, input, refSchema, {
52
+ ...options,
53
+ generics
54
+ });
55
+ }
56
+ }
57
+ return execMapper(getMapper(input, options.mapper), [input], {
58
+ ...options,
59
+ root: false,
60
+ mapper: undefined
61
+ });
62
+ }
63
+ registerJsonSchemaMapper("item", itemMapper);
64
+ registerJsonSchemaMapper("next", nextMapper);
65
+ registerJsonSchemaMapper("properties", nextMapper);
66
+ registerJsonSchemaMapper("items", nextMapper);
67
+ registerJsonSchemaMapper("additionalProperties", nextMapper);
68
+ registerJsonSchemaMapper("propertyNames", nextMapper);
69
+ registerJsonSchemaMapper("contains", nextMapper);
70
+ registerJsonSchemaMapper("dependencies", nextMapper);
71
+ registerJsonSchemaMapper("patternProperties", nextMapper);
72
+ registerJsonSchemaMapper("additionalItems", nextMapper);
73
+ registerJsonSchemaMapper("not", nextMapper);
74
+ registerJsonSchemaMapper("definitions", nextMapper);
@@ -1,4 +1,5 @@
1
1
  import { isArray } from "@tsed/core";
2
+ import { VendorKeys } from "../../constants/VendorKeys.js";
2
3
  import { alterIgnore } from "../../hooks/alterIgnore.js";
3
4
  import { execMapper, registerJsonSchemaMapper } from "../../registries/JsonSchemaMapperContainer.js";
4
5
  /**
@@ -8,16 +9,20 @@ import { execMapper, registerJsonSchemaMapper } from "../../registries/JsonSchem
8
9
  * @ignore
9
10
  */
10
11
  export function objectMapper(input, options) {
11
- const { specType, operationIdFormatter, root, components, genericTypes, nestedGenerics, useAlias, genericLabels, ...ctx } = options;
12
+ const { specType, operationIdFormatter, root, components, useAlias, ...ctx } = options;
12
13
  return Object.entries(input).reduce((obj, [key, value]) => {
13
14
  if (options.withIgnoredProps !== false && !alterIgnore(value, ctx)) {
14
15
  const opts = {
15
16
  ...options,
16
- groups: input?.$forwardGroups || value?.$forwardGroups ? options.groups : undefined
17
+ parent: value,
18
+ groups: input?.get?.(VendorKeys.FORWARD_GROUPS) || value?.get?.(VendorKeys.FORWARD_GROUPS) ? options.groups : undefined
17
19
  };
18
- // remove groups to avoid bad schema generation over children models
19
20
  obj[key] = execMapper("item", [value], opts);
20
21
  obj[key] = execMapper("nullable", [obj[key], value], opts);
22
+ if (value.isGeneric && obj[key]?.type) {
23
+ const { type, ...rest } = obj[key];
24
+ obj[key] = rest;
25
+ }
21
26
  }
22
27
  return obj;
23
28
  }, isArray(input) ? [] : {});
@@ -1,10 +1,7 @@
1
1
  import { execMapper, registerJsonSchemaMapper } from "../../registries/JsonSchemaMapperContainer.js";
2
- export function ofMapper(input, options, parent) {
2
+ export function ofMapper(input, options) {
3
3
  return input.map((value) => {
4
- return execMapper("item", [value], {
5
- ...options,
6
- genericLabels: parent.genericLabels
7
- });
4
+ return execMapper("item", [value], options);
8
5
  });
9
6
  }
10
7
  registerJsonSchemaMapper("anyOf", ofMapper);
@@ -14,7 +14,7 @@ function mapRequiredProps(obj, schema, options = {}) {
14
14
  }
15
15
  function extractRequiredProps(obj, schema, options) {
16
16
  let required = obj.required || [];
17
- required = [...required, ...schema.$required];
17
+ required = [...required, ...schema.getRequiredFields()];
18
18
  if (schema.get("properties")) {
19
19
  required = Object.entries(schema.get("properties")).reduce((required, [key, prop]) => {
20
20
  if (prop && prop.$selfRequired !== undefined) {
@@ -26,7 +26,7 @@ function extractRequiredProps(obj, schema, options) {
26
26
  return alterRequiredGroups(uniq(required), schema, options);
27
27
  }
28
28
  export function requiredMapper(obj, schema, options) {
29
- if (options.groups && options.groups.includes("partial")) {
29
+ if (options.groups && options.groups?.includes("partial")) {
30
30
  if (obj.discriminator) {
31
31
  return {
32
32
  ...obj,
@@ -13,6 +13,7 @@ const IGNORES = ["name", "$required", "$hooks", "_nestedGenerics", SpecTypes.OPE
13
13
  const IGNORES_OPENSPEC = [];
14
14
  /**
15
15
  * @ignore
16
+ * TODO check if we can remove this
16
17
  */
17
18
  function isEmptyProperties(key, value) {
18
19
  return typeof value === "object" && ["items", "properties", "additionalProperties"].includes(key) && Object.keys(value).length === 0;
@@ -28,7 +29,8 @@ function shouldMapAlias(key, value, useAlias) {
28
29
  */
29
30
  function shouldSkipKey(key, { specType = SpecTypes.JSON, customKeys = false }) {
30
31
  return (IGNORES.includes(key) ||
31
- (key.startsWith("#") && (customKeys === false || specType !== SpecTypes.JSON)) ||
32
+ key.startsWith("x-") ||
33
+ (key.startsWith("#") && (!customKeys || specType !== SpecTypes.JSON)) ||
32
34
  (specType !== SpecTypes.JSON && IGNORES_OPENSPEC.includes(key)));
33
35
  }
34
36
  function isExample(key, value, options) {
@@ -81,17 +83,13 @@ function mapKeys(schema, options) {
81
83
  }
82
84
  function serializeSchema(schema, options) {
83
85
  let obj = mapKeys(schema, options);
84
- if (schema.isClass) {
86
+ if (schema.isClass && !schema.isLocalSchema) {
85
87
  obj = execMapper("inheritedClass", [obj], {
86
88
  ...options,
87
89
  root: false,
88
- target: schema.getComputedType()
90
+ target: schema.class
89
91
  });
90
92
  }
91
- obj = execMapper("generics", [obj], {
92
- ...options,
93
- root: false
94
- });
95
93
  if (schema.has(options.specType)) {
96
94
  obj = {
97
95
  ...obj,
@@ -106,6 +104,7 @@ function serializeSchema(schema, options) {
106
104
  obj = alterOneOf(obj, schema, options);
107
105
  obj = execMapper("enums", [obj, schema], options);
108
106
  obj = execMapper("discriminatorMapping", [obj, schema], options);
107
+ obj = execMapper("generics", [obj, schema], options);
109
108
  return obj;
110
109
  }
111
110
  export function schemaMapper(schema, opts) {
@@ -1,24 +1,18 @@
1
1
  /**
2
2
  * @file Automatically generated by @tsed/barrels.
3
3
  */
4
- export * from "./async-api/channelsMapper.js";
5
- export * from "./async-api/generate.js";
6
- export * from "./async-api/messageMapper.js";
7
- export * from "./async-api/payloadMapper.js";
8
- export * from "./async-api/responseMapper.js";
9
4
  export * from "./default/anyMapper.js";
10
5
  export * from "./default/classMapper.js";
11
6
  export * from "./default/discriminatorMappingMapper.js";
12
7
  export * from "./default/enumsMapper.js";
13
8
  export * from "./default/genericsMapper.js";
14
9
  export * from "./default/inheritedClassMapper.js";
15
- export * from "./default/itemMapper.js";
16
10
  export * from "./default/lazyRefMapper.js";
17
11
  export * from "./default/mapMapper.js";
12
+ export * from "./default/nextMapper.js";
18
13
  export * from "./default/nullableMapper.js";
19
14
  export * from "./default/objectMapper.js";
20
15
  export * from "./default/ofMapper.js";
21
- export * from "./default/propertiesMapper.js";
22
16
  export * from "./default/requiredMapper.js";
23
17
  export * from "./default/schemaMapper.js";
24
18
  export * from "./open-spec/discriminatorMappingMapper.js";
@@ -1,10 +1,14 @@
1
1
  import { cleanObject } from "@tsed/core";
2
2
  import { SpecTypes } from "../../domain/SpecTypes.js";
3
3
  import { registerJsonSchemaMapper } from "../../registries/JsonSchemaMapperContainer.js";
4
- export function nullableMapperOpenApi(obj, schema) {
4
+ import { nullableMapper } from "../default/nullableMapper.js";
5
+ export function nullableMapperOpenApi(obj, schema, options) {
5
6
  if (!schema?.isNullable) {
6
7
  return obj;
7
8
  }
9
+ if (options.specVersion === "3.1.0") {
10
+ return nullableMapper(obj, schema);
11
+ }
8
12
  if (obj.$ref) {
9
13
  return cleanObject({
10
14
  ...obj,
@@ -1,22 +1,18 @@
1
1
  import { camelCase } from "change-case";
2
2
  import { JsonParameterTypes } from "../../domain/JsonParameterTypes.js";
3
3
  import { execMapper, hasMapper, registerJsonSchemaMapper } from "../../registries/JsonSchemaMapperContainer.js";
4
- import { popGenerics } from "../../utils/generics.js";
5
4
  function mapOptions(parameter, options = {}) {
6
5
  return {
7
6
  ...options,
8
- groups: parameter.groups,
9
- groupsName: parameter.groupsName
7
+ groups: parameter.schema().getGroups(),
8
+ groupsName: parameter.schema().getGroupsName()
10
9
  };
11
10
  }
12
11
  export function operationInParameterMapper(jsonParameter, opts) {
13
12
  const options = mapOptions(jsonParameter, opts);
14
13
  const schemas = { ...(options.components?.schemas || {}) };
15
14
  const { type, schema, ...parameter } = execMapper("map", [jsonParameter], options);
16
- const jsonSchema = execMapper("item", [jsonParameter.$schema], {
17
- ...options,
18
- ...popGenerics(jsonParameter)
19
- });
15
+ const jsonSchema = execMapper("item", [jsonParameter.schema()], options);
20
16
  parameter.required = parameter.required || jsonParameter.get("in") === JsonParameterTypes.PATH;
21
17
  const paramOpts = {
22
18
  ...options,
@@ -1,6 +1,6 @@
1
1
  import { cleanObject } from "@tsed/core";
2
2
  import { registerJsonSchemaMapper } from "../../registries/JsonSchemaMapperContainer.js";
3
- import { createRefName } from "../../utils/ref.js";
3
+ import { createRefName, getSchemaFromRef } from "../../utils/ref.js";
4
4
  function buildExamples(property, examples) {
5
5
  if (!examples) {
6
6
  return undefined;
@@ -23,32 +23,37 @@ function buildExamples(property, examples) {
23
23
  return hasKey ? newExamples : undefined;
24
24
  }
25
25
  function inlineReference(parameter, { jsonParameter, ...options }) {
26
- const name = createRefName(jsonParameter.$schema.getName(), options);
26
+ const name = createRefName(jsonParameter.schema().itemSchema().getName(), options);
27
27
  const schema = options.components?.schemas?.[name];
28
28
  if (schema && !options.oldSchemas?.[name]) {
29
- delete options.components.schemas[jsonParameter.$schema.getName()];
29
+ delete options.components?.schemas?.[jsonParameter.schema().itemSchema().getName()];
30
30
  }
31
31
  return Object.entries(schema?.properties || {}).reduce((params, [key, { description, ...prop }]) => {
32
- return [
33
- ...params,
34
- cleanObject({
35
- ...parameter,
36
- name: key,
37
- required: (schema?.required || []).includes(key),
38
- description,
39
- schema: prop,
40
- style: prop.$ref ? "deepObject" : undefined,
41
- examples: buildExamples(key, parameter.examples)
42
- })
43
- ];
32
+ const style = parameter.style || (prop.$ref && !getSchemaFromRef(prop.$ref, options)?.enum) ? "deepObject" : undefined;
33
+ params.push(cleanObject({
34
+ ...parameter,
35
+ style,
36
+ explode: style === "deepObject" ? true : parameter.explode,
37
+ name: key,
38
+ required: (schema?.required || []).includes(key),
39
+ description,
40
+ schema: prop,
41
+ examples: buildExamples(key, parameter.examples)
42
+ }));
43
+ return params;
44
44
  }, []);
45
45
  }
46
- export function operationInQueryMapper(parameter, { jsonSchema, jsonParameters, ...options }) {
46
+ export function operationInQueryMapper(parameter, { jsonSchema, ...options }) {
47
47
  if (jsonSchema.$ref) {
48
48
  if (!parameter.name) {
49
49
  return inlineReference(parameter, options);
50
50
  }
51
- parameter.style = "deepObject";
51
+ const schema = getSchemaFromRef(jsonSchema.$ref, options);
52
+ // if the reference is an enum, we don't need to set the style or explode
53
+ if (!schema?.enum) {
54
+ parameter.style = "deepObject";
55
+ parameter.explode = true;
56
+ }
52
57
  }
53
58
  parameter.schema = jsonSchema;
54
59
  return parameter;
@@ -1,6 +1,9 @@
1
1
  import { execMapper, registerJsonSchemaMapper } from "../../registries/JsonSchemaMapperContainer.js";
2
2
  export function operationMediaMapper(jsonMedia, options) {
3
- let groups = [...(jsonMedia.groups || [])];
4
- return execMapper("map", [jsonMedia], { ...options, groups, groupsName: jsonMedia.groupsName });
3
+ return execMapper("map", [jsonMedia], {
4
+ ...options,
5
+ groups: [...(jsonMedia.schema().getGroups() || [])],
6
+ groupsName: jsonMedia.schema().getGroupsName()
7
+ });
5
8
  }
6
9
  registerJsonSchemaMapper("operationMedia", operationMediaMapper);
@@ -46,9 +46,9 @@ function buildSchemaFromBodyParameters(parameters, options) {
46
46
  delete props.description;
47
47
  }
48
48
  return {
49
- schema: schema.toJSON(options),
50
49
  required: false,
51
- ...props
50
+ ...props,
51
+ schema: schema.toJSON(options)
52
52
  };
53
53
  }
54
54
  export function operationRequestBodyMapper(bodyParameters, { consumes, ...options }) {
@@ -0,0 +1,11 @@
1
+ export var VendorKeys;
2
+ (function (VendorKeys) {
3
+ VendorKeys["GENERIC_LABELS"] = "genericLabels";
4
+ VendorKeys["GENERIC_LABEL"] = "genericLabel";
5
+ VendorKeys["GENERIC_OF"] = "genericOf";
6
+ VendorKeys["NULLABLE"] = "nullable";
7
+ VendorKeys["FORWARD_GROUPS"] = "forwardGroups";
8
+ VendorKeys["GROUPS"] = "groups";
9
+ VendorKeys["GROUPS_NAME"] = "groupsName";
10
+ VendorKeys["ALLOWED_GROUPS"] = "allowedGroups";
11
+ })(VendorKeys || (VendorKeys = {}));
@@ -1,3 +1,4 @@
1
+ import { DecoratorTypes } from "@tsed/core";
1
2
  import { JsonEntityStore } from "../../domain/JsonEntityStore.js";
2
3
  /**
3
4
  * Set the type of the item collection. The possible value is String, Boolean, Number, Date, Object, Class, etc...
@@ -37,6 +38,7 @@ export function CollectionOf(type, collectionType) {
37
38
  }
38
39
  const schema = {};
39
40
  let contains = false;
41
+ const nestedGenerics = [];
40
42
  const decorator = (...args) => {
41
43
  const store = JsonEntityStore.from(...args);
42
44
  if (collectionType) {
@@ -46,6 +48,14 @@ export function CollectionOf(type, collectionType) {
46
48
  store.type = type;
47
49
  store.itemSchema.type(type);
48
50
  store.schema.assign(schema);
51
+ if (nestedGenerics.length) {
52
+ if (store.is(DecoratorTypes.PARAM)) {
53
+ store.parameter.itemSchema().genericOf(...nestedGenerics);
54
+ }
55
+ else {
56
+ store.itemSchema.genericOf(...nestedGenerics);
57
+ }
58
+ }
49
59
  if (store.isArray && contains) {
50
60
  store.schema.set("contains", store.schema.get("items"));
51
61
  store.schema.delete("items");
@@ -79,9 +89,6 @@ export function CollectionOf(type, collectionType) {
79
89
  schema.maxProperties = maxProperties;
80
90
  return decorator;
81
91
  };
82
- /**
83
- * @deprecated Since 2025-05-12. Use Contains decorator instead.
84
- */
85
92
  decorator.Contains = () => {
86
93
  contains = true;
87
94
  return decorator;
@@ -93,6 +100,10 @@ export function CollectionOf(type, collectionType) {
93
100
  schema.uniqueItems = uniqueItems;
94
101
  return decorator;
95
102
  };
103
+ decorator.Nested = (...generics) => {
104
+ nestedGenerics.push(generics);
105
+ return decorator;
106
+ };
96
107
  return decorator;
97
108
  }
98
109
  /**
@@ -1,4 +1,4 @@
1
- import { decoratorTypeOf, DecoratorTypes } from "@tsed/core";
1
+ import { DecoratorTypes } from "@tsed/core";
2
2
  import { JsonEntityFn } from "./jsonEntityFn.js";
3
3
  /**
4
4
  * Add a description to the class, method or property
@@ -54,17 +54,14 @@ import { JsonEntityFn } from "./jsonEntityFn.js";
54
54
  */
55
55
  export function Description(description) {
56
56
  return JsonEntityFn((store, args) => {
57
- switch (decoratorTypeOf(args)) {
58
- case DecoratorTypes.PROP:
59
- case DecoratorTypes.CLASS:
60
- store.schema.description(description);
61
- break;
62
- case DecoratorTypes.PARAM:
63
- store.parameter.description(description);
64
- break;
65
- case DecoratorTypes.METHOD:
66
- store.operation?.description(description);
67
- break;
57
+ if (store.is(DecoratorTypes.PROP) || store.is(DecoratorTypes.CLASS)) {
58
+ store.schema.description(description);
59
+ }
60
+ else if (store.is(DecoratorTypes.PARAM)) {
61
+ store.parameter.description(description);
62
+ }
63
+ else if (store.is(DecoratorTypes.METHOD)) {
64
+ store.operation?.description(description);
68
65
  }
69
66
  });
70
67
  }
@@ -3,6 +3,6 @@ import { JsonEntityFn } from "./jsonEntityFn.js";
3
3
  import { Property } from "./property.js";
4
4
  export function DiscriminatorKey() {
5
5
  return useDecorators(Property(), JsonEntityFn((store) => {
6
- store.discriminatorKey();
6
+ store.parent.schema.discriminatorKey(String(store.propertyKey));
7
7
  }));
8
8
  }