@tsed/schema 8.0.1 → 8.0.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.
Files changed (292) hide show
  1. package/package.json +11 -10
  2. package/readme.md +6 -6
  3. package/src/components/async-api/channelsMapper.ts +81 -0
  4. package/src/components/async-api/generate.ts +24 -0
  5. package/src/components/async-api/messageMapper.ts +62 -0
  6. package/src/components/async-api/payloadMapper.ts +61 -0
  7. package/src/components/async-api/responseMapper.ts +70 -0
  8. package/src/components/default/anyMapper.spec.ts +7 -0
  9. package/src/components/default/anyMapper.ts +33 -0
  10. package/src/components/default/classMapper.ts +55 -0
  11. package/src/components/default/discriminatorMappingMapper.ts +36 -0
  12. package/src/components/default/enumsMapper.spec.ts +64 -0
  13. package/src/components/default/enumsMapper.ts +17 -0
  14. package/src/components/default/genericsMapper.ts +70 -0
  15. package/src/components/default/inheritedClassMapper.ts +24 -0
  16. package/src/components/default/itemMapper.ts +8 -0
  17. package/src/components/default/lazyRefMapper.ts +21 -0
  18. package/src/components/default/mapMapper.ts +25 -0
  19. package/src/components/default/nullableMapper.ts +55 -0
  20. package/src/components/default/objectMapper.ts +36 -0
  21. package/src/components/default/ofMapper.ts +16 -0
  22. package/src/components/default/propertiesMapper.ts +25 -0
  23. package/src/components/default/requiredMapper.ts +69 -0
  24. package/src/components/default/schemaMapper.ts +151 -0
  25. package/src/components/index.ts +36 -0
  26. package/src/components/open-spec/discriminatorMappingMapper.ts +7 -0
  27. package/src/components/open-spec/enumsMapper.ts +20 -0
  28. package/src/components/open-spec/generate.ts +29 -0
  29. package/src/components/open-spec/nullableMapper.ts +51 -0
  30. package/src/components/open-spec/operationInFilesMapper.ts +32 -0
  31. package/src/components/open-spec/operationInParameterMapper.ts +56 -0
  32. package/src/components/open-spec/operationInParametersMapper.ts +9 -0
  33. package/src/components/open-spec/operationInQueryMapper.ts +74 -0
  34. package/src/components/open-spec/operationMapper.ts +65 -0
  35. package/src/components/open-spec/operationMediaMapper.ts +11 -0
  36. package/src/components/open-spec/operationRequestBodyMapper.ts +82 -0
  37. package/src/components/open-spec/operationResponseMapper.ts +26 -0
  38. package/src/components/open-spec/pathsMapper.ts +132 -0
  39. package/src/constants/OperationVerbs.ts +29 -0
  40. package/src/constants/httpStatusMessages.ts +21 -0
  41. package/src/constants/jsonSchemaProperties.ts +17 -0
  42. package/src/decorators/class/children.ts +22 -0
  43. package/src/decorators/class/discriminatorValue.ts +53 -0
  44. package/src/decorators/collections/collectionContains.ts +25 -0
  45. package/src/decorators/collections/collectionOf.spec.ts +327 -0
  46. package/src/decorators/collections/collectionOf.ts +182 -0
  47. package/src/decorators/collections/maxItems.spec.ts +40 -0
  48. package/src/decorators/collections/maxItems.ts +59 -0
  49. package/src/decorators/collections/maxProperties.spec.ts +109 -0
  50. package/src/decorators/collections/maxProperties.ts +82 -0
  51. package/src/decorators/collections/minItems.spec.ts +40 -0
  52. package/src/decorators/collections/minItems.ts +63 -0
  53. package/src/decorators/collections/minProperties.spec.ts +109 -0
  54. package/src/decorators/collections/minProperties.ts +81 -0
  55. package/src/decorators/collections/uniqueItems.spec.ts +28 -0
  56. package/src/decorators/collections/uniqueItems.ts +59 -0
  57. package/src/decorators/common/__snapshots__/groups.spec.ts.snap +321 -0
  58. package/src/decorators/common/additionalProperties.spec.ts +133 -0
  59. package/src/decorators/common/additionalProperties.ts +17 -0
  60. package/src/decorators/common/allOf.spec.ts +276 -0
  61. package/src/decorators/common/allOf.ts +19 -0
  62. package/src/decorators/common/allow.spec.ts +130 -0
  63. package/src/decorators/common/allow.ts +50 -0
  64. package/src/decorators/common/any.spec.ts +109 -0
  65. package/src/decorators/common/any.ts +45 -0
  66. package/src/decorators/common/anyOf.spec.ts +270 -0
  67. package/src/decorators/common/anyOf.ts +23 -0
  68. package/src/decorators/common/const.spec.ts +98 -0
  69. package/src/decorators/common/const.ts +68 -0
  70. package/src/decorators/common/customKey.spec.ts +105 -0
  71. package/src/decorators/common/customKey.ts +39 -0
  72. package/src/decorators/common/default.spec.ts +25 -0
  73. package/src/decorators/common/default.ts +47 -0
  74. package/src/decorators/common/defaultMsg.spec.ts +22 -0
  75. package/src/decorators/common/defaultMsg.ts +38 -0
  76. package/src/decorators/common/description.spec.ts +166 -0
  77. package/src/decorators/common/description.ts +77 -0
  78. package/src/decorators/common/discriminatorKey.ts +14 -0
  79. package/src/decorators/common/enum.spec.ts +305 -0
  80. package/src/decorators/common/enum.ts +111 -0
  81. package/src/decorators/common/errorMsg.spec.ts +57 -0
  82. package/src/decorators/common/errorMsg.ts +14 -0
  83. package/src/decorators/common/example.spec.ts +93 -0
  84. package/src/decorators/common/example.ts +18 -0
  85. package/src/decorators/common/examples.spec.ts +101 -0
  86. package/src/decorators/common/examples.ts +20 -0
  87. package/src/decorators/common/exclusiveMaximum.spec.ts +47 -0
  88. package/src/decorators/common/exclusiveMaximum.ts +75 -0
  89. package/src/decorators/common/exclusiveMinimum.spec.ts +47 -0
  90. package/src/decorators/common/exclusiveMinimum.ts +75 -0
  91. package/src/decorators/common/format.spec.ts +149 -0
  92. package/src/decorators/common/format.ts +486 -0
  93. package/src/decorators/common/forwardGroups.spec.ts +270 -0
  94. package/src/decorators/common/forwardGroups.ts +16 -0
  95. package/src/decorators/common/groups.spec.ts +968 -0
  96. package/src/decorators/common/groups.ts +66 -0
  97. package/src/decorators/common/hidden.spec.ts +52 -0
  98. package/src/decorators/common/hidden.ts +36 -0
  99. package/src/decorators/common/ignore.spec.ts +88 -0
  100. package/src/decorators/common/ignore.ts +66 -0
  101. package/src/decorators/common/integer.spec.ts +110 -0
  102. package/src/decorators/common/integer.ts +69 -0
  103. package/src/decorators/common/jsonEntityFn.spec.ts +16 -0
  104. package/src/decorators/common/jsonEntityFn.ts +33 -0
  105. package/src/decorators/common/maxLength.spec.ts +61 -0
  106. package/src/decorators/common/maxLength.ts +88 -0
  107. package/src/decorators/common/maximum.spec.ts +73 -0
  108. package/src/decorators/common/maximum.ts +146 -0
  109. package/src/decorators/common/minLength.spec.ts +186 -0
  110. package/src/decorators/common/minLength.ts +89 -0
  111. package/src/decorators/common/minimum.spec.ts +74 -0
  112. package/src/decorators/common/minimum.ts +145 -0
  113. package/src/decorators/common/multipleOf.spec.ts +33 -0
  114. package/src/decorators/common/multipleOf.ts +80 -0
  115. package/src/decorators/common/name.spec.ts +56 -0
  116. package/src/decorators/common/name.ts +50 -0
  117. package/src/decorators/common/nullable.spec.ts +818 -0
  118. package/src/decorators/common/nullable.ts +32 -0
  119. package/src/decorators/common/oneOf.spec.ts +301 -0
  120. package/src/decorators/common/oneOf.ts +24 -0
  121. package/src/decorators/common/optional.spec.ts +43 -0
  122. package/src/decorators/common/optional.ts +26 -0
  123. package/src/decorators/common/pattern.spec.ts +27 -0
  124. package/src/decorators/common/pattern.ts +102 -0
  125. package/src/decorators/common/property.ts +24 -0
  126. package/src/decorators/common/readOnly.spec.ts +135 -0
  127. package/src/decorators/common/readOnly.ts +17 -0
  128. package/src/decorators/common/recordOf.spec.ts +41 -0
  129. package/src/decorators/common/recordOf.ts +59 -0
  130. package/src/decorators/common/required.spec.ts +188 -0
  131. package/src/decorators/common/required.ts +50 -0
  132. package/src/decorators/common/requiredGroups.spec.ts +127 -0
  133. package/src/decorators/common/requiredGroups.ts +23 -0
  134. package/src/decorators/common/schema.spec.ts +23 -0
  135. package/src/decorators/common/schema.ts +64 -0
  136. package/src/decorators/common/title.spec.ts +20 -0
  137. package/src/decorators/common/title.ts +45 -0
  138. package/src/decorators/common/typeError.spec.ts +22 -0
  139. package/src/decorators/common/typeError.ts +15 -0
  140. package/src/decorators/common/writeOnly.spec.ts +105 -0
  141. package/src/decorators/common/writeOnly.ts +17 -0
  142. package/src/decorators/config/jsonEntityComponent.ts +16 -0
  143. package/src/decorators/generics/genericOf.spec.ts +246 -0
  144. package/src/decorators/generics/genericOf.ts +112 -0
  145. package/src/decorators/generics/generics.ts +22 -0
  146. package/src/decorators/operations/acceptMime.spec.ts +39 -0
  147. package/src/decorators/operations/acceptMime.ts +25 -0
  148. package/src/decorators/operations/consumes.spec.ts +89 -0
  149. package/src/decorators/operations/consumes.ts +37 -0
  150. package/src/decorators/operations/contentType.spec.ts +40 -0
  151. package/src/decorators/operations/contentType.ts +24 -0
  152. package/src/decorators/operations/deprecated.spec.ts +223 -0
  153. package/src/decorators/operations/deprecated.ts +49 -0
  154. package/src/decorators/operations/header.spec.ts +214 -0
  155. package/src/decorators/operations/header.ts +62 -0
  156. package/src/decorators/operations/in.spec.ts +321 -0
  157. package/src/decorators/operations/in.ts +141 -0
  158. package/src/decorators/operations/inFile.spec.ts +209 -0
  159. package/src/decorators/operations/inFile.ts +55 -0
  160. package/src/decorators/operations/location.spec.ts +51 -0
  161. package/src/decorators/operations/location.ts +26 -0
  162. package/src/decorators/operations/operation.ts +119 -0
  163. package/src/decorators/operations/operationId.spec.ts +43 -0
  164. package/src/decorators/operations/operationId.ts +22 -0
  165. package/src/decorators/operations/operationPath.spec.ts +42 -0
  166. package/src/decorators/operations/operationPath.ts +33 -0
  167. package/src/decorators/operations/partial.spec.ts +249 -0
  168. package/src/decorators/operations/partial.ts +14 -0
  169. package/src/decorators/operations/path.spec.ts +47 -0
  170. package/src/decorators/operations/path.ts +27 -0
  171. package/src/decorators/operations/produces.spec.ts +89 -0
  172. package/src/decorators/operations/produces.ts +44 -0
  173. package/src/decorators/operations/publish.spec.ts +26 -0
  174. package/src/decorators/operations/publish.ts +6 -0
  175. package/src/decorators/operations/redirect.spec.ts +146 -0
  176. package/src/decorators/operations/redirect.ts +82 -0
  177. package/src/decorators/operations/returns.spec.ts +1393 -0
  178. package/src/decorators/operations/returns.ts +662 -0
  179. package/src/decorators/operations/route.spec.ts +211 -0
  180. package/src/decorators/operations/route.ts +154 -0
  181. package/src/decorators/operations/security.spec.ts +162 -0
  182. package/src/decorators/operations/security.ts +83 -0
  183. package/src/decorators/operations/status.spec.ts +582 -0
  184. package/src/decorators/operations/status.ts +130 -0
  185. package/src/decorators/operations/subscribe.spec.ts +32 -0
  186. package/src/decorators/operations/subscribe.ts +6 -0
  187. package/src/decorators/operations/summary.spec.ts +45 -0
  188. package/src/decorators/operations/summary.ts +32 -0
  189. package/src/decorators/operations/tags.spec.ts +113 -0
  190. package/src/decorators/operations/tags.ts +53 -0
  191. package/src/decorators/operations/view.spec.ts +16 -0
  192. package/src/decorators/operations/view.ts +27 -0
  193. package/src/domain/DecoratorContext.ts +116 -0
  194. package/src/domain/JsonAliasMap.ts +19 -0
  195. package/src/domain/JsonClassStore.ts +35 -0
  196. package/src/domain/JsonDiscriminator.spec.ts +65 -0
  197. package/src/domain/JsonDiscriminator.ts +52 -0
  198. package/src/domain/JsonEntityStore.spec.ts +277 -0
  199. package/src/domain/JsonEntityStore.ts +284 -0
  200. package/src/domain/JsonFormatTypes.ts +17 -0
  201. package/src/domain/JsonLazyRef.ts +21 -0
  202. package/src/domain/JsonMap.spec.ts +15 -0
  203. package/src/domain/JsonMap.ts +33 -0
  204. package/src/domain/JsonMedia.ts +24 -0
  205. package/src/domain/JsonMethodStore.spec.ts +301 -0
  206. package/src/domain/JsonMethodStore.ts +212 -0
  207. package/src/domain/JsonOperation.spec.ts +126 -0
  208. package/src/domain/JsonOperation.ts +219 -0
  209. package/src/domain/JsonOperationPathsMap.ts +16 -0
  210. package/src/domain/JsonOperationRoute.spec.ts +109 -0
  211. package/src/domain/JsonOperationRoute.ts +75 -0
  212. package/src/domain/JsonParameter.ts +70 -0
  213. package/src/domain/JsonParameterStore.spec.ts +212 -0
  214. package/src/domain/JsonParameterStore.ts +138 -0
  215. package/src/domain/JsonParameterTypes.spec.ts +12 -0
  216. package/src/domain/JsonParameterTypes.ts +20 -0
  217. package/src/domain/JsonPropertyStore.spec.ts +177 -0
  218. package/src/domain/JsonPropertyStore.ts +92 -0
  219. package/src/domain/JsonRequestBody.ts +47 -0
  220. package/src/domain/JsonResponse.spec.ts +33 -0
  221. package/src/domain/JsonResponse.ts +64 -0
  222. package/src/domain/JsonSchema.spec.ts +1470 -0
  223. package/src/domain/JsonSchema.ts +1049 -0
  224. package/src/domain/SpecTypes.ts +6 -0
  225. package/src/hooks/alterIgnore.ts +25 -0
  226. package/src/hooks/alterOneOf.ts +67 -0
  227. package/src/hooks/alterRequiredGroups.ts +12 -0
  228. package/src/index.ts +185 -0
  229. package/src/interfaces/IgnoreCallback.ts +5 -0
  230. package/src/interfaces/JsonHookContext.ts +18 -0
  231. package/src/interfaces/JsonOpenSpec.ts +7 -0
  232. package/src/interfaces/JsonSchemaOptions.ts +35 -0
  233. package/src/registries/JsonSchemaMapperContainer.ts +52 -0
  234. package/src/registries/enumRegistries.ts +3 -0
  235. package/src/utils/__snapshots__/generateSpec.spec.ts.snap +109 -0
  236. package/src/utils/buildPath.ts +8 -0
  237. package/src/utils/concatParameters.ts +12 -0
  238. package/src/utils/concatPath.spec.ts +23 -0
  239. package/src/utils/concatPath.ts +24 -0
  240. package/src/utils/defineStatusModel.ts +11 -0
  241. package/src/utils/from.spec.ts +243 -0
  242. package/src/utils/from.ts +281 -0
  243. package/src/utils/generateSpec.spec.ts +1262 -0
  244. package/src/utils/generateSpec.ts +54 -0
  245. package/src/utils/generics.ts +83 -0
  246. package/src/utils/getComputedType.spec.ts +45 -0
  247. package/src/utils/getComputedType.ts +39 -0
  248. package/src/utils/getInheritedStores.spec.ts +47 -0
  249. package/src/utils/getInheritedStores.ts +23 -0
  250. package/src/utils/getJsonEntityStore.ts +36 -0
  251. package/src/utils/getJsonPathParameters.spec.ts +126 -0
  252. package/src/utils/getJsonPathParameters.ts +97 -0
  253. package/src/utils/getJsonSchema.spec.ts +695 -0
  254. package/src/utils/getJsonSchema.ts +69 -0
  255. package/src/utils/getJsonType.spec.ts +28 -0
  256. package/src/utils/getJsonType.ts +46 -0
  257. package/src/utils/getOperationsRoutes.spec.ts +284 -0
  258. package/src/utils/getOperationsRoutes.ts +56 -0
  259. package/src/utils/getOperationsStore.spec.ts +47 -0
  260. package/src/utils/getOperationsStores.ts +37 -0
  261. package/src/utils/getPropertiesStores.spec.ts +138 -0
  262. package/src/utils/getPropertiesStores.ts +66 -0
  263. package/src/utils/getSpec.spec.ts +610 -0
  264. package/src/utils/getSpec.ts +117 -0
  265. package/src/utils/getSpecType.spec.ts +16 -0
  266. package/src/utils/getSpecType.ts +19 -0
  267. package/src/utils/isSuccessStatus.spec.ts +22 -0
  268. package/src/utils/isSuccessStatus.ts +2 -0
  269. package/src/utils/mapHeaders.spec.ts +57 -0
  270. package/src/utils/mapHeaders.ts +33 -0
  271. package/src/utils/mapOpenSpec.ts +44 -0
  272. package/src/utils/mapOpenSpec2.ts +50 -0
  273. package/src/utils/mapOpenSpec3.ts +25 -0
  274. package/src/utils/mapOpenSpecInfo.ts +19 -0
  275. package/src/utils/mapOperationOptions.ts +34 -0
  276. package/src/utils/matchGroups.spec.ts +85 -0
  277. package/src/utils/matchGroups.ts +64 -0
  278. package/src/utils/mergeSpec.spec.ts +533 -0
  279. package/src/utils/mergeSpec.ts +54 -0
  280. package/src/utils/operationIdFormatter.spec.ts +11 -0
  281. package/src/utils/operationIdFormatter.ts +49 -0
  282. package/src/utils/ref.ts +65 -0
  283. package/src/utils/removeHiddenOperation.ts +5 -0
  284. package/src/utils/serializeEnumValues.ts +27 -0
  285. package/src/utils/somethingOf.ts +11 -0
  286. package/src/utils/toJsonMapCollection.spec.ts +18 -0
  287. package/src/utils/toJsonMapCollection.ts +12 -0
  288. package/src/utils/toJsonRegex.ts +7 -0
  289. package/src/utils/transformToOS2.spec.ts +177 -0
  290. package/src/utils/transformToOS2.ts +607 -0
  291. package/src/utils/withErrorMsg.spec.ts +16 -0
  292. package/src/utils/withErrorMsg.ts +56 -0
@@ -0,0 +1,607 @@
1
+ "use strict";
2
+ import {cleanObject} from "@tsed/core";
3
+ import {OpenSpec2, OpenSpec3, type OS2Security, OS3Operation} from "@tsed/openspec";
4
+
5
+ const HTTP_METHODS = ["get", "put", "post", "delete", "options", "head", "patch", "trace"];
6
+ const SCHEMA_PROPERTIES = [
7
+ "format",
8
+ "minimum",
9
+ "maximum",
10
+ "exclusiveMinimum",
11
+ "exclusiveMaximum",
12
+ "minLength",
13
+ "maxLength",
14
+ "multipleOf",
15
+ "minItems",
16
+ "maxItems",
17
+ "uniqueItems",
18
+ "minProperties",
19
+ "maxProperties",
20
+ "additionalProperties",
21
+ "pattern",
22
+ "enum",
23
+ "default"
24
+ ];
25
+ const ARRAY_PROPERTIES = ["type", "items"];
26
+
27
+ const APPLICATION_JSON_REGEX = /^(application\/json|[^;\/ \t]+\/[^;\/ \t]+[+]json)[ \t]*(;.*)?$/;
28
+ const SUPPORTED_MIME_TYPES: Record<string, any> = {
29
+ APPLICATION_X_WWW_URLENCODED: "application/x-www-form-urlencoded",
30
+ MULTIPART_FORM_DATA: "multipart/form-data"
31
+ };
32
+
33
+ function fixRef(ref: string) {
34
+ return ref.replace("#/components/schemas/", "#/definitions/").replace("#/components/", "#/x-components/");
35
+ }
36
+
37
+ function fixRefs(obj: any) {
38
+ if (Array.isArray(obj)) {
39
+ obj.forEach(fixRefs);
40
+ } else if (typeof obj === "object") {
41
+ for (let key in obj) {
42
+ if (key === "$ref") {
43
+ obj.$ref = fixRef(obj.$ref);
44
+ } else {
45
+ fixRefs(obj[key]);
46
+ }
47
+ }
48
+ }
49
+ }
50
+
51
+ function isJsonMimeType(type: string) {
52
+ return new RegExp(APPLICATION_JSON_REGEX, "i").test(type);
53
+ }
54
+
55
+ function getSupportedMimeTypes(content: any) {
56
+ const MIME_VALUES = Object.keys(SUPPORTED_MIME_TYPES).map((key) => {
57
+ return SUPPORTED_MIME_TYPES[key];
58
+ });
59
+ return Object.keys(content).filter((key) => {
60
+ return MIME_VALUES.indexOf(key) > -1 || isJsonMimeType(key);
61
+ });
62
+ }
63
+
64
+ export function transformSecurity(securitySchemes: any) {
65
+ function map(security: any): OS2Security | undefined {
66
+ const {scheme, type, name, bearerFormat, flows, ...props} = security;
67
+
68
+ switch (type) {
69
+ case "http":
70
+ if (scheme === "basic") {
71
+ return {
72
+ ...props,
73
+ type: scheme
74
+ };
75
+ }
76
+
77
+ if (scheme === "bearer") {
78
+ return {
79
+ ...props,
80
+ type: "apiKey",
81
+ name: "Authorization",
82
+ in: "header"
83
+ };
84
+ }
85
+ break;
86
+ case "oauth2":
87
+ const flowName = Object.keys(flows)[0];
88
+ const flow = flows[flowName];
89
+ let flowType = flowName;
90
+
91
+ if (flowType === "clientCredentials") {
92
+ flowType = "application";
93
+ } else if (flowType === "authorizationCode") {
94
+ flowType = "accessCode";
95
+ }
96
+
97
+ return {
98
+ type,
99
+ flow: flowType as never,
100
+ authorizationUrl: flow.authorizationUrl,
101
+ tokenUrl: flow.tokenUrl,
102
+ scopes: flow.scopes
103
+ };
104
+ }
105
+ }
106
+
107
+ return Object.entries(securitySchemes).reduce(
108
+ (securityDefinitions, [key, security]) => {
109
+ const securityDefinition = map(security);
110
+
111
+ if (securityDefinition) {
112
+ securityDefinitions[key] = securityDefinition;
113
+ }
114
+
115
+ return securityDefinitions;
116
+ },
117
+ {} as Record<string, OS2Security>
118
+ );
119
+ }
120
+
121
+ export function transformInformation(server: any) {
122
+ let serverUrl = server.url;
123
+
124
+ const variables = server["variables"] || {};
125
+
126
+ for (const variable in variables) {
127
+ const variableObject = variables[variable] || {};
128
+ if (variableObject["default"]) {
129
+ const re = RegExp(`{${variable}}`, "g");
130
+ serverUrl = serverUrl.replace(re, variableObject["default"]);
131
+ }
132
+ }
133
+
134
+ const url = new URL(serverUrl);
135
+
136
+ return {
137
+ host: url.host ? url.host : undefined,
138
+ basePath: url.pathname,
139
+ schemes: url.protocol !== null ? [url.protocol.substring(0, url.protocol.length - 1)] : undefined
140
+ };
141
+ }
142
+
143
+ export class Converter {
144
+ private spec: any;
145
+
146
+ constructor(spec: Partial<OpenSpec3>) {
147
+ this.spec = JSON.parse(JSON.stringify(spec));
148
+ }
149
+
150
+ convertInfos() {
151
+ const server = this.spec.servers && this.spec.servers[0];
152
+
153
+ if (server) {
154
+ return transformInformation(server);
155
+ }
156
+
157
+ return {};
158
+ }
159
+
160
+ resolveReference(base: any, obj: any, shouldClone: boolean) {
161
+ if (!obj || !obj.$ref) {
162
+ return obj;
163
+ }
164
+
165
+ const ref: string = obj.$ref;
166
+
167
+ if (ref.startsWith("#")) {
168
+ const keys = ref.split("/").map((k) => k.replace(/~1/g, "/").replace(/~0/g, "~"));
169
+ keys.shift();
170
+
171
+ let cur = base;
172
+ keys.forEach((k) => {
173
+ cur = cur[k];
174
+ });
175
+
176
+ return shouldClone ? JSON.parse(JSON.stringify(cur)) : cur;
177
+ }
178
+ }
179
+
180
+ convert() {
181
+ const spec = {
182
+ swagger: "2.0",
183
+ ...this.convertInfos(),
184
+ paths: this.spec.paths ? this.convertOperations(this.spec.paths, this.spec) : undefined
185
+ };
186
+
187
+ if (this.spec.components) {
188
+ this.convertSchemas();
189
+ this.convertSecurityDefinitions();
190
+
191
+ this.spec["x-components"] = this.spec.components;
192
+ delete this.spec.components;
193
+
194
+ fixRefs(this.spec);
195
+ }
196
+
197
+ delete this.spec.servers;
198
+ delete this.spec.openapi;
199
+ delete this.spec["x-components"];
200
+
201
+ return cleanObject({
202
+ ...spec,
203
+ ...this.spec
204
+ });
205
+ }
206
+
207
+ convertOperations(paths: any, spec: any) {
208
+ return Object.entries(paths).reduce((paths, [path, operation]) => {
209
+ const pathObject = (paths[path] = this.resolveReference({...spec, paths}, operation, true));
210
+
211
+ this.convertParameters(pathObject); // converts common parameters
212
+
213
+ Object.keys(pathObject).forEach((method) => {
214
+ if (HTTP_METHODS.indexOf(method) >= 0) {
215
+ const operation = (pathObject[method] = this.resolveReference({...spec, paths}, pathObject[method], true));
216
+
217
+ this.convertOperationParameters(operation);
218
+ this.convertResponses(operation);
219
+ }
220
+ });
221
+
222
+ return paths;
223
+ }, paths);
224
+ }
225
+
226
+ convertOperationParameters(operation: OS3Operation) {
227
+ let content, contentKey, mediaRanges, mediaTypes;
228
+ operation.parameters = operation.parameters || [];
229
+
230
+ if (operation.requestBody) {
231
+ let param = this.resolveReference(this.spec, operation.requestBody, true);
232
+
233
+ // fixing external $ref in body
234
+ if (operation.requestBody.content) {
235
+ const type = getSupportedMimeTypes(operation.requestBody.content)[0];
236
+ const structuredObj: any = {content: {}};
237
+ const data = operation.requestBody.content[type];
238
+
239
+ if (data && data.schema && data.schema.$ref && !data.schema.$ref.startsWith("#")) {
240
+ param = this.resolveReference(this.spec, data.schema, true);
241
+ structuredObj["content"][`${type}`] = {schema: param};
242
+ param = structuredObj;
243
+ }
244
+ }
245
+
246
+ param.name = "body";
247
+ content = param.content;
248
+
249
+ if (content && Object.keys(content).length) {
250
+ mediaRanges = Object.keys(content).filter((mediaRange) => mediaRange.indexOf("/") > 0);
251
+ mediaTypes = mediaRanges.filter((range) => range.indexOf("*") < 0);
252
+ contentKey = getSupportedMimeTypes(content)[0];
253
+
254
+ delete param.content;
255
+
256
+ if ([SUPPORTED_MIME_TYPES.APPLICATION_X_WWW_URLENCODED, SUPPORTED_MIME_TYPES.MULTIPART_FORM_DATA].includes(contentKey)) {
257
+ (operation as any).consumes = mediaTypes;
258
+
259
+ param.in = "formData";
260
+ param.schema = content[contentKey].schema;
261
+ param.schema = this.resolveReference(this.spec, param.schema, true);
262
+
263
+ if (param.schema.type === "object" && param.schema.properties) {
264
+ const required = param.schema.required || [];
265
+
266
+ Object.keys(param.schema.properties).forEach((name) => {
267
+ const schema = param.schema.properties[name];
268
+
269
+ // readOnly properties should not be sent in requests
270
+ if (!schema.readOnly) {
271
+ const formDataParam: any = {
272
+ name,
273
+ in: "formData",
274
+ schema
275
+ };
276
+ if (required.indexOf(name) >= 0) {
277
+ formDataParam.required = true;
278
+ }
279
+
280
+ operation.parameters?.push(formDataParam);
281
+ }
282
+ });
283
+ } else {
284
+ operation.parameters.push(param);
285
+ }
286
+ } else if (contentKey) {
287
+ (operation as any).consumes = mediaTypes;
288
+ param.in = "body";
289
+ param.schema = content[contentKey].schema;
290
+ operation.parameters.push(param);
291
+ } else if (mediaRanges) {
292
+ (operation as any).consumes = mediaTypes || ["application/octet-stream"];
293
+ param.in = "body";
294
+ param.name = param.name || "file";
295
+ delete param.type;
296
+
297
+ param.schema = content[mediaRanges[0]].schema || {
298
+ type: "string",
299
+ format: "binary"
300
+ };
301
+
302
+ operation.parameters.push(param);
303
+ }
304
+
305
+ if (param.schema) {
306
+ this.convertSchema(param.schema, "request");
307
+ }
308
+ }
309
+
310
+ delete operation.requestBody;
311
+ }
312
+ this.convertParameters(operation);
313
+ }
314
+
315
+ convertParameters(obj: any) {
316
+ if (obj.parameters === undefined) {
317
+ return;
318
+ }
319
+
320
+ obj.parameters = obj.parameters || [];
321
+
322
+ (obj.parameters || []).forEach((param: any, i: number) => {
323
+ param = obj.parameters[i] = this.resolveReference(this.spec, param, false);
324
+
325
+ if (param.in !== "body") {
326
+ this.copySchemaProperties(param, SCHEMA_PROPERTIES);
327
+ this.copySchemaProperties(param, ARRAY_PROPERTIES);
328
+ this.copySchemaXProperties(param);
329
+
330
+ if (!param.description) {
331
+ const schema = this.resolveReference(this.spec, param.schema, false);
332
+ if (!!schema && schema.description) {
333
+ param.description = schema.description;
334
+ }
335
+ }
336
+
337
+ if (param.example !== undefined) {
338
+ param["x-example"] = param.example;
339
+ }
340
+
341
+ delete param.schema;
342
+ delete param.allowReserved;
343
+ delete param.example;
344
+ }
345
+
346
+ if (param.type === "array") {
347
+ let style = param.style || (param.in === "query" || param.in === "cookie" ? "form" : "simple");
348
+
349
+ switch (style) {
350
+ case "matrix":
351
+ param.collectionFormat = param.explode ? undefined : "csv";
352
+ break;
353
+ case "label":
354
+ param.collectionFormat = undefined;
355
+ break;
356
+ case "simple":
357
+ param.collectionFormat = "csv";
358
+ break;
359
+ case "spaceDelimited":
360
+ param.collectionFormat = "ssv";
361
+ break;
362
+ case "pipeDelimited":
363
+ param.collectionFormat = "pipes";
364
+ break;
365
+ case "deepOpbject":
366
+ param.collectionFormat = "multi";
367
+ break;
368
+ case "form":
369
+ param.collectionFormat = param.explode === false ? "csv" : "multi";
370
+ break;
371
+ }
372
+ }
373
+
374
+ delete param.style;
375
+ delete param.explode;
376
+ });
377
+ }
378
+
379
+ copySchemaProperties(obj: any, props: any[]) {
380
+ let schema = this.resolveReference(this.spec, obj.schema, true);
381
+
382
+ if (!schema) {
383
+ return;
384
+ }
385
+
386
+ props.forEach((prop) => {
387
+ const value = schema[prop];
388
+
389
+ if (prop === "additionalProperties" && typeof value === "boolean") {
390
+ return;
391
+ }
392
+
393
+ if (value !== undefined) {
394
+ obj[prop] = value;
395
+ }
396
+ });
397
+ }
398
+
399
+ copySchemaXProperties(obj: Record<string, any>) {
400
+ let schema = this.resolveReference(this.spec, obj.schema, true);
401
+ if (!schema) {
402
+ return;
403
+ }
404
+
405
+ Object.keys(schema).forEach((propName) => {
406
+ if (Reflect.hasOwnProperty.call(schema, propName) && !Reflect.hasOwnProperty.call(obj, propName) && propName.startsWith("x-")) {
407
+ obj[propName] = schema[propName];
408
+ }
409
+ });
410
+ }
411
+
412
+ convertResponses(operation: Record<string, any>) {
413
+ // var anySchema, code, content, jsonSchema, mediaRange, mediaType, response, resolved, headers
414
+
415
+ Object.keys(operation.responses || {}).forEach((code) => {
416
+ const response = (operation.responses[code] = this.resolveReference(this.spec, operation.responses[code], true));
417
+
418
+ if (response.content) {
419
+ let anySchema: any = null;
420
+ let jsonSchema: any = null;
421
+
422
+ Object.keys(response.content).forEach((mediaRange) => {
423
+ // produces and examples only allow media types, not ranges
424
+ // use application/octet-stream as a catch-all type
425
+ const mediaType = mediaRange.indexOf("*") < 0 ? mediaRange : "application/octet-stream";
426
+
427
+ if (!operation.produces) {
428
+ operation.produces = [mediaType];
429
+ } else if (operation.produces.indexOf(mediaType) < 0) {
430
+ operation.produces.push(mediaType);
431
+ }
432
+
433
+ const content = response.content[mediaRange];
434
+ anySchema = anySchema || content.schema;
435
+
436
+ if (!jsonSchema && isJsonMimeType(mediaType)) {
437
+ jsonSchema = content.schema;
438
+ }
439
+
440
+ if (content.example) {
441
+ response.examples = response.examples || {};
442
+ response.examples[mediaType] = content.example;
443
+ }
444
+ });
445
+
446
+ if (anySchema) {
447
+ response.schema = jsonSchema || anySchema;
448
+ const resolved = this.resolveReference(this.spec, response.schema, true);
449
+
450
+ if (resolved && response.schema.$ref && !response.schema.$ref.startsWith("#")) {
451
+ response.schema = resolved;
452
+ }
453
+
454
+ this.convertSchema(response.schema, "response");
455
+ }
456
+ }
457
+
458
+ Object.keys(response.headers || {}).forEach((header) => {
459
+ // Always resolve headers when converting to v2.
460
+ const resolved = this.resolveReference(this.spec, response.headers[header], true);
461
+
462
+ // Headers should be converted like parameters.
463
+ if (resolved.schema) {
464
+ resolved.type = resolved.schema.type;
465
+ resolved.format = resolved.schema.format;
466
+ delete resolved.schema;
467
+ }
468
+
469
+ response.headers[header] = resolved;
470
+ });
471
+
472
+ delete response.content;
473
+ });
474
+ }
475
+
476
+ convertSchema(def: any, operationDirection?: any) {
477
+ if (def.oneOf) {
478
+ delete def.oneOf;
479
+
480
+ if (def.discriminator) {
481
+ delete def.discriminator;
482
+ }
483
+ }
484
+
485
+ if (def.anyOf) {
486
+ delete def.anyOf;
487
+
488
+ if (def.discriminator) {
489
+ delete def.discriminator;
490
+ }
491
+ }
492
+
493
+ if (def.allOf) {
494
+ for (const i in def.allOf) {
495
+ this.convertSchema(def.allOf[i], operationDirection);
496
+ }
497
+ }
498
+
499
+ if (def.discriminator) {
500
+ if (def.discriminator.mapping) {
501
+ this.convertDiscriminatorMapping(def.discriminator.mapping);
502
+ }
503
+
504
+ def.discriminator = def.discriminator.propertyName;
505
+ }
506
+
507
+ switch (def.type) {
508
+ case "object":
509
+ if (def.properties) {
510
+ Object.keys(def.properties).forEach((propName) => {
511
+ if (def.properties[propName].writeOnly === true && operationDirection === "response") {
512
+ delete def.properties[propName];
513
+ } else {
514
+ this.convertSchema(def.properties[propName], operationDirection);
515
+ delete def.properties[propName].writeOnly;
516
+ }
517
+ });
518
+ }
519
+ break;
520
+ case "array":
521
+ if (def.items) {
522
+ this.convertSchema(def.items, operationDirection);
523
+ }
524
+ }
525
+
526
+ if (def.nullable) {
527
+ def["x-nullable"] = true;
528
+ delete def.nullable;
529
+ }
530
+
531
+ // OpenAPI 3 has boolean "deprecated" on Schema, OpenAPI 2 does not
532
+ // Convert to x-deprecated for Autorest (and perhaps others)
533
+ if (def["deprecated"] !== undefined) {
534
+ // Move to x-deprecated, unless it is already defined
535
+ if (def["x-deprecated"] === undefined) {
536
+ def["x-deprecated"] = def.deprecated;
537
+ }
538
+ delete def.deprecated;
539
+ }
540
+ }
541
+
542
+ convertSchemas() {
543
+ this.spec.definitions = this.spec.components.schemas;
544
+
545
+ Object.keys(this.spec.definitions || {}).forEach((defName) => {
546
+ this.convertSchema(this.spec.definitions[defName]);
547
+ });
548
+
549
+ delete this.spec.components.schemas;
550
+ }
551
+
552
+ convertDiscriminatorMapping(mapping: any) {
553
+ Object.keys(mapping).forEach((payload) => {
554
+ const schemaNameOrRef = mapping[payload];
555
+
556
+ if (typeof schemaNameOrRef !== "string") {
557
+ console.warn(`Ignoring ${schemaNameOrRef} for ${payload} in discriminator.mapping.`);
558
+ return;
559
+ }
560
+
561
+ // payload may be a schema name or JSON Reference string.
562
+ // OAS3 spec limits schema names to ^[a-zA-Z0-9._-]+$
563
+ // Note: Valid schema name could be JSON file name without extension.
564
+ // Prefer schema name, with file name as fallback.
565
+ let schema;
566
+ if (/^[a-zA-Z0-9._-]+$/.test(schemaNameOrRef)) {
567
+ try {
568
+ schema = this.resolveReference(this.spec, {$ref: `#/components/schemas/${schemaNameOrRef}`}, false);
569
+ } catch (err) {
570
+ console.debug(`Error resolving ${schemaNameOrRef} for ${payload} as schema name in discriminator.mapping: ${err}`);
571
+ }
572
+ }
573
+
574
+ // schemaNameRef is not a schema name. Try to resolve as JSON Ref.
575
+ if (!schema) {
576
+ try {
577
+ schema = this.resolveReference(this.spec, {$ref: schemaNameOrRef}, false);
578
+ } catch (err) {
579
+ console.debug(`Error resolving ${schemaNameOrRef} for ${payload} in discriminator.mapping: ${err}`);
580
+ }
581
+ }
582
+
583
+ if (schema) {
584
+ // Swagger Codegen + OpenAPI Generator extension
585
+ // https://github.com/swagger-api/swagger-codegen/pull/4252
586
+ schema["x-discriminator-value"] = payload;
587
+
588
+ // AutoRest extension
589
+ // https://github.com/Azure/autorest/pull/474
590
+ schema["x-ms-discriminator-value"] = payload;
591
+ } else {
592
+ console.warn(`Unable to resolve ${schemaNameOrRef} for ${payload} in discriminator.mapping.`);
593
+ }
594
+ });
595
+ }
596
+
597
+ convertSecurityDefinitions() {
598
+ if (this.spec.components.securitySchemes) {
599
+ this.spec.securityDefinitions = transformSecurity(this.spec.components.securitySchemes);
600
+ delete this.spec.components.securitySchemes;
601
+ }
602
+ }
603
+ }
604
+
605
+ export function transformToOS2(spec: any): Partial<OpenSpec2> {
606
+ return new Converter(spec).convert();
607
+ }
@@ -0,0 +1,16 @@
1
+ import {withErrorMsg} from "./withErrorMsg.js";
2
+
3
+ // TODO: complete this test
4
+ describe("withErrorMsg", () => {
5
+ it("should return a function when called", () => {
6
+ const result = withErrorMsg("test", () => {});
7
+ expect(result).toBeInstanceOf(Function);
8
+ });
9
+
10
+ it("should return an ErrorChainedMethods object when the returned function is called", () => {
11
+ const result = withErrorMsg("test", () => {})();
12
+ expect(result).toBeInstanceOf(Object);
13
+ expect(result).toHaveProperty("Error");
14
+ expect(result.Error).toBeInstanceOf(Function);
15
+ });
16
+ });
@@ -0,0 +1,56 @@
1
+ import {deepMerge, useDecorators} from "@tsed/core";
2
+
3
+ import {JsonEntityFn} from "../decorators/common/jsonEntityFn.js";
4
+
5
+ export interface ErrorChainedMethods<T> {
6
+ <T>(target: Object, propertyKey?: string | symbol | undefined, descriptor?: TypedPropertyDescriptor<T> | number): any;
7
+
8
+ Error(msg: string): this;
9
+ }
10
+
11
+ export type ErrorChainedDecorator<Decorator extends (...args: any[]) => any> = (
12
+ ...args: Parameters<Decorator>
13
+ ) => ErrorChainedMethods<Decorator>;
14
+
15
+ export function withErrorMsg<Decorator extends (...args: any[]) => any>(
16
+ errorKey: string,
17
+ originalDecorator: Decorator
18
+ ): ErrorChainedDecorator<Decorator> {
19
+ const schema: any = {};
20
+
21
+ return ((...decoratorOptions: any[]) => {
22
+ const decorator = useDecorators(originalDecorator(...decoratorOptions));
23
+ (decorator as any).Error = (message: string) => {
24
+ schema.message = message;
25
+
26
+ return useDecorators(
27
+ decorator,
28
+ schema.message &&
29
+ JsonEntityFn((store) => {
30
+ // since errorMessage is a custom key, it is prefixed with a # to avoid conflict with JSON Schema keywords
31
+ const errorMessage = store.parentSchema.get("#errorMessage") || {};
32
+
33
+ if (errorKey === "required") {
34
+ store.parentSchema.customKey(
35
+ "errorMessage",
36
+ deepMerge(errorMessage, {
37
+ [errorKey]: {
38
+ [store.propertyName]: message
39
+ }
40
+ })
41
+ );
42
+ } else {
43
+ store.itemSchema.customKey(
44
+ "errorMessage",
45
+ deepMerge(errorMessage, {
46
+ [errorKey]: message
47
+ })
48
+ );
49
+ }
50
+ })
51
+ );
52
+ };
53
+
54
+ return decorator;
55
+ }) as any;
56
+ }