@typia/utils 12.0.0-dev.20260316 → 12.0.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.
@@ -1,318 +1,318 @@
1
- import { OpenApi, OpenApiV3_1 } from "@typia/interface";
2
-
3
- import { OpenApiTypeChecker } from "../../validators/OpenApiTypeChecker";
4
-
5
- export namespace OpenApiV3_1Downgrader {
6
- export interface IComponentsCollection {
7
- original: OpenApi.IComponents;
8
- downgraded: OpenApiV3_1.IComponents;
9
- }
10
-
11
- export const downgrade = (input: OpenApi.IDocument): OpenApiV3_1.IDocument => {
12
- const collection: IComponentsCollection = downgradeComponents(
13
- input.components,
14
- );
15
- return {
16
- openapi: "3.1.0",
17
- servers: input.servers,
18
- info: input.info,
19
- components: collection.downgraded,
20
- paths: input.paths
21
- ? Object.fromEntries(
22
- Object.entries(input.paths)
23
- .filter(([_, v]) => v !== undefined)
24
- .map(
25
- ([key, value]) =>
26
- [key, downgradePathItem(collection)(value)] as const,
27
- ),
28
- )
29
- : undefined,
30
- webhooks: input.webhooks
31
- ? Object.fromEntries(
32
- Object.entries(input.webhooks)
33
- .filter(([_, v]) => v !== undefined)
34
- .map(
35
- ([key, value]) =>
36
- [key, downgradePathItem(collection)(value)] as const,
37
- ),
38
- )
39
- : undefined,
40
- security: input.security,
41
- tags: input.tags,
42
- };
43
- };
44
-
45
- /* -----------------------------------------------------------
46
- OPERATORS
47
- ----------------------------------------------------------- */
48
- const downgradePathItem =
49
- (collection: IComponentsCollection) =>
50
- (pathItem: OpenApi.IPath): OpenApiV3_1.IPath => {
51
- // Collect non-standard operations for x-additionalOperations
52
- const xAdditionalOperations: Record<string, OpenApiV3_1.IOperation> = {};
53
-
54
- // query method goes to x-additionalOperations
55
- if (pathItem.query) {
56
- xAdditionalOperations["query"] = downgradeOperation(collection)(pathItem.query);
57
- }
58
-
59
- // additionalOperations also go to x-additionalOperations
60
- if (pathItem.additionalOperations) {
61
- for (const [key, value] of Object.entries(pathItem.additionalOperations)) {
62
- if (value !== undefined) {
63
- xAdditionalOperations[key] = downgradeOperation(collection)(value);
64
- }
65
- }
66
- }
67
-
68
- return {
69
- ...(pathItem as any),
70
- ...(pathItem.get
71
- ? { get: downgradeOperation(collection)(pathItem.get) }
72
- : undefined),
73
- ...(pathItem.put
74
- ? { put: downgradeOperation(collection)(pathItem.put) }
75
- : undefined),
76
- ...(pathItem.post
77
- ? { post: downgradeOperation(collection)(pathItem.post) }
78
- : undefined),
79
- ...(pathItem.delete
80
- ? { delete: downgradeOperation(collection)(pathItem.delete) }
81
- : undefined),
82
- ...(pathItem.options
83
- ? { options: downgradeOperation(collection)(pathItem.options) }
84
- : undefined),
85
- ...(pathItem.head
86
- ? { head: downgradeOperation(collection)(pathItem.head) }
87
- : undefined),
88
- ...(pathItem.patch
89
- ? { patch: downgradeOperation(collection)(pathItem.patch) }
90
- : undefined),
91
- ...(pathItem.trace
92
- ? { trace: downgradeOperation(collection)(pathItem.trace) }
93
- : undefined),
94
- ...(Object.keys(xAdditionalOperations).length > 0
95
- ? { "x-additionalOperations": xAdditionalOperations }
96
- : undefined),
97
- // Remove v3.2-only properties from spread
98
- query: undefined,
99
- additionalOperations: undefined,
100
- };
101
- };
102
-
103
- const downgradeOperation =
104
- (collection: IComponentsCollection) =>
105
- (input: OpenApi.IOperation): OpenApiV3_1.IOperation => ({
106
- ...input,
107
- parameters: input.parameters
108
- ? input.parameters.map(downgradeParameter(collection))
109
- : undefined,
110
- requestBody: input.requestBody
111
- ? downgradeRequestBody(collection)(input.requestBody)
112
- : undefined,
113
- responses: input.responses
114
- ? Object.fromEntries(
115
- Object.entries(input.responses)
116
- .filter(([_, v]) => v !== undefined)
117
- .map(([key, value]) => [
118
- key,
119
- downgradeResponse(collection)(value),
120
- ]),
121
- )
122
- : undefined,
123
- });
124
-
125
- const downgradeParameter =
126
- (collection: IComponentsCollection) =>
127
- (
128
- input: OpenApi.IOperation.IParameter,
129
- ): OpenApiV3_1.IOperation.IParameter => ({
130
- ...input,
131
- in: input.in === "querystring" ? "query" : input.in,
132
- schema: downgradeSchema(collection)(input.schema),
133
- });
134
-
135
- const downgradeRequestBody =
136
- (collection: IComponentsCollection) =>
137
- (
138
- input: OpenApi.IOperation.IRequestBody,
139
- ): OpenApiV3_1.IOperation.IRequestBody => ({
140
- ...input,
141
- content: input.content
142
- ? downgradeContent(collection)(input.content)
143
- : undefined,
144
- });
145
-
146
- const downgradeResponse =
147
- (collection: IComponentsCollection) =>
148
- (input: OpenApi.IOperation.IResponse): OpenApiV3_1.IOperation.IResponse => ({
149
- ...input,
150
- content: input.content
151
- ? downgradeContent(collection)(input.content)
152
- : undefined,
153
- headers: input.headers
154
- ? Object.fromEntries(
155
- Object.entries(input.headers)
156
- .filter(([_, v]) => v !== undefined)
157
- .map(([key, value]) => [
158
- key,
159
- {
160
- ...value,
161
- schema: downgradeSchema(collection)(value.schema),
162
- },
163
- ]),
164
- )
165
- : undefined,
166
- });
167
-
168
- const downgradeContent =
169
- (collection: IComponentsCollection) =>
170
- (
171
- record: OpenApi.IOperation.IContent,
172
- ): Record<string, OpenApiV3_1.IOperation.IMediaType> =>
173
- Object.fromEntries(
174
- Object.entries(record)
175
- .filter(([_, v]) => v !== undefined)
176
- .map(
177
- ([key, value]) =>
178
- [
179
- key,
180
- {
181
- ...value,
182
- schema: value?.schema
183
- ? downgradeSchema(collection)(value.schema)
184
- : undefined,
185
- // itemSchema is v3.2-only, remove it
186
- itemSchema: undefined,
187
- },
188
- ] as const,
189
- ),
190
- );
191
-
192
- /* -----------------------------------------------------------
193
- DEFINITIONS
194
- ----------------------------------------------------------- */
195
- export const downgradeComponents = (
196
- input: OpenApi.IComponents,
197
- ): IComponentsCollection => {
198
- const collection: IComponentsCollection = {
199
- original: input,
200
- downgraded: {
201
- securitySchemes: input.securitySchemes
202
- ? downgradeSecuritySchemes(input.securitySchemes)
203
- : undefined,
204
- },
205
- };
206
- if (input.schemas) {
207
- collection.downgraded.schemas = {};
208
- for (const [key, value] of Object.entries(input.schemas))
209
- if (value !== undefined)
210
- collection.downgraded.schemas[key] =
211
- downgradeSchema(collection)(value);
212
- }
213
- return collection;
214
- };
215
-
216
- export const downgradeSchema =
217
- (collection: IComponentsCollection) =>
218
- (input: OpenApi.IJsonSchema): OpenApiV3_1.IJsonSchema => {
219
- const union: OpenApiV3_1.IJsonSchema[] = [];
220
- const attribute: OpenApiV3_1.IJsonSchema.__IAttribute = {
221
- title: input.title,
222
- description: input.description,
223
- deprecated: input.deprecated,
224
- readOnly: input.readOnly,
225
- writeOnly: input.writeOnly,
226
- example: input.example,
227
- examples: input.examples,
228
- ...Object.fromEntries(
229
- Object.entries(input).filter(
230
- ([key, value]) => key.startsWith("x-") && value !== undefined,
231
- ),
232
- ),
233
- };
234
- const visit = (schema: OpenApi.IJsonSchema): void => {
235
- if (OpenApiTypeChecker.isNull(schema))
236
- union.push({ type: "null" });
237
- else if (OpenApiTypeChecker.isConstant(schema))
238
- union.push({ const: schema.const });
239
- else if (
240
- OpenApiTypeChecker.isBoolean(schema) ||
241
- OpenApiTypeChecker.isInteger(schema) ||
242
- OpenApiTypeChecker.isNumber(schema) ||
243
- OpenApiTypeChecker.isString(schema) ||
244
- OpenApiTypeChecker.isReference(schema)
245
- )
246
- union.push({ ...schema });
247
- else if (OpenApiTypeChecker.isArray(schema))
248
- union.push({
249
- ...schema,
250
- items: downgradeSchema(collection)(schema.items),
251
- });
252
- else if (OpenApiTypeChecker.isTuple(schema))
253
- union.push({
254
- ...schema,
255
- prefixItems: schema.prefixItems.map(
256
- downgradeSchema(collection),
257
- ),
258
- additionalItems:
259
- typeof schema.additionalItems === "object"
260
- ? downgradeSchema(collection)(schema.additionalItems)
261
- : schema.additionalItems,
262
- });
263
- else if (OpenApiTypeChecker.isObject(schema))
264
- union.push({
265
- ...schema,
266
- properties: schema.properties
267
- ? Object.fromEntries(
268
- Object.entries(schema.properties)
269
- .filter(([_, v]) => v !== undefined)
270
- .map(([key, value]) => [
271
- key,
272
- downgradeSchema(collection)(value),
273
- ]),
274
- )
275
- : undefined,
276
- additionalProperties:
277
- typeof schema.additionalProperties === "object"
278
- ? downgradeSchema(collection)(schema.additionalProperties)
279
- : schema.additionalProperties,
280
- required: schema.required,
281
- });
282
- else if (OpenApiTypeChecker.isOneOf(schema))
283
- schema.oneOf.forEach(visit);
284
- };
285
- visit(input);
286
- return {
287
- ...(union.length === 0
288
- ? { type: undefined }
289
- : union.length === 1
290
- ? { ...union[0] }
291
- : { oneOf: union }),
292
- ...attribute,
293
- };
294
- };
295
-
296
- const downgradeSecuritySchemes = (
297
- input: Record<string, OpenApi.ISecurityScheme>,
298
- ): Record<string, OpenApiV3_1.ISecurityScheme> =>
299
- Object.fromEntries(
300
- Object.entries(input)
301
- .filter(([_, v]) => v !== undefined)
302
- .map(([key, value]) => [key, downgradeSecurityScheme(value)]),
303
- );
304
-
305
- const downgradeSecurityScheme = (
306
- input: OpenApi.ISecurityScheme,
307
- ): OpenApiV3_1.ISecurityScheme => {
308
- if (input.type === "oauth2") {
309
- const { deviceAuthorization: _, ...flows } = input.flows;
310
- return {
311
- type: "oauth2",
312
- flows,
313
- description: input.description,
314
- };
315
- }
316
- return { ...input } as OpenApiV3_1.ISecurityScheme;
317
- };
318
- }
1
+ import { OpenApi, OpenApiV3_1 } from "@typia/interface";
2
+
3
+ import { OpenApiTypeChecker } from "../../validators/OpenApiTypeChecker";
4
+
5
+ export namespace OpenApiV3_1Downgrader {
6
+ export interface IComponentsCollection {
7
+ original: OpenApi.IComponents;
8
+ downgraded: OpenApiV3_1.IComponents;
9
+ }
10
+
11
+ export const downgrade = (input: OpenApi.IDocument): OpenApiV3_1.IDocument => {
12
+ const collection: IComponentsCollection = downgradeComponents(
13
+ input.components,
14
+ );
15
+ return {
16
+ openapi: "3.1.0",
17
+ servers: input.servers,
18
+ info: input.info,
19
+ components: collection.downgraded,
20
+ paths: input.paths
21
+ ? Object.fromEntries(
22
+ Object.entries(input.paths)
23
+ .filter(([_, v]) => v !== undefined)
24
+ .map(
25
+ ([key, value]) =>
26
+ [key, downgradePathItem(collection)(value)] as const,
27
+ ),
28
+ )
29
+ : undefined,
30
+ webhooks: input.webhooks
31
+ ? Object.fromEntries(
32
+ Object.entries(input.webhooks)
33
+ .filter(([_, v]) => v !== undefined)
34
+ .map(
35
+ ([key, value]) =>
36
+ [key, downgradePathItem(collection)(value)] as const,
37
+ ),
38
+ )
39
+ : undefined,
40
+ security: input.security,
41
+ tags: input.tags,
42
+ };
43
+ };
44
+
45
+ /* -----------------------------------------------------------
46
+ OPERATORS
47
+ ----------------------------------------------------------- */
48
+ const downgradePathItem =
49
+ (collection: IComponentsCollection) =>
50
+ (pathItem: OpenApi.IPath): OpenApiV3_1.IPath => {
51
+ // Collect non-standard operations for x-additionalOperations
52
+ const xAdditionalOperations: Record<string, OpenApiV3_1.IOperation> = {};
53
+
54
+ // query method goes to x-additionalOperations
55
+ if (pathItem.query) {
56
+ xAdditionalOperations["query"] = downgradeOperation(collection)(pathItem.query);
57
+ }
58
+
59
+ // additionalOperations also go to x-additionalOperations
60
+ if (pathItem.additionalOperations) {
61
+ for (const [key, value] of Object.entries(pathItem.additionalOperations)) {
62
+ if (value !== undefined) {
63
+ xAdditionalOperations[key] = downgradeOperation(collection)(value);
64
+ }
65
+ }
66
+ }
67
+
68
+ return {
69
+ ...(pathItem as any),
70
+ ...(pathItem.get
71
+ ? { get: downgradeOperation(collection)(pathItem.get) }
72
+ : undefined),
73
+ ...(pathItem.put
74
+ ? { put: downgradeOperation(collection)(pathItem.put) }
75
+ : undefined),
76
+ ...(pathItem.post
77
+ ? { post: downgradeOperation(collection)(pathItem.post) }
78
+ : undefined),
79
+ ...(pathItem.delete
80
+ ? { delete: downgradeOperation(collection)(pathItem.delete) }
81
+ : undefined),
82
+ ...(pathItem.options
83
+ ? { options: downgradeOperation(collection)(pathItem.options) }
84
+ : undefined),
85
+ ...(pathItem.head
86
+ ? { head: downgradeOperation(collection)(pathItem.head) }
87
+ : undefined),
88
+ ...(pathItem.patch
89
+ ? { patch: downgradeOperation(collection)(pathItem.patch) }
90
+ : undefined),
91
+ ...(pathItem.trace
92
+ ? { trace: downgradeOperation(collection)(pathItem.trace) }
93
+ : undefined),
94
+ ...(Object.keys(xAdditionalOperations).length > 0
95
+ ? { "x-additionalOperations": xAdditionalOperations }
96
+ : undefined),
97
+ // Remove v3.2-only properties from spread
98
+ query: undefined,
99
+ additionalOperations: undefined,
100
+ };
101
+ };
102
+
103
+ const downgradeOperation =
104
+ (collection: IComponentsCollection) =>
105
+ (input: OpenApi.IOperation): OpenApiV3_1.IOperation => ({
106
+ ...input,
107
+ parameters: input.parameters
108
+ ? input.parameters.map(downgradeParameter(collection))
109
+ : undefined,
110
+ requestBody: input.requestBody
111
+ ? downgradeRequestBody(collection)(input.requestBody)
112
+ : undefined,
113
+ responses: input.responses
114
+ ? Object.fromEntries(
115
+ Object.entries(input.responses)
116
+ .filter(([_, v]) => v !== undefined)
117
+ .map(([key, value]) => [
118
+ key,
119
+ downgradeResponse(collection)(value),
120
+ ]),
121
+ )
122
+ : undefined,
123
+ });
124
+
125
+ const downgradeParameter =
126
+ (collection: IComponentsCollection) =>
127
+ (
128
+ input: OpenApi.IOperation.IParameter,
129
+ ): OpenApiV3_1.IOperation.IParameter => ({
130
+ ...input,
131
+ in: input.in === "querystring" ? "query" : input.in,
132
+ schema: downgradeSchema(collection)(input.schema),
133
+ });
134
+
135
+ const downgradeRequestBody =
136
+ (collection: IComponentsCollection) =>
137
+ (
138
+ input: OpenApi.IOperation.IRequestBody,
139
+ ): OpenApiV3_1.IOperation.IRequestBody => ({
140
+ ...input,
141
+ content: input.content
142
+ ? downgradeContent(collection)(input.content)
143
+ : undefined,
144
+ });
145
+
146
+ const downgradeResponse =
147
+ (collection: IComponentsCollection) =>
148
+ (input: OpenApi.IOperation.IResponse): OpenApiV3_1.IOperation.IResponse => ({
149
+ ...input,
150
+ content: input.content
151
+ ? downgradeContent(collection)(input.content)
152
+ : undefined,
153
+ headers: input.headers
154
+ ? Object.fromEntries(
155
+ Object.entries(input.headers)
156
+ .filter(([_, v]) => v !== undefined)
157
+ .map(([key, value]) => [
158
+ key,
159
+ {
160
+ ...value,
161
+ schema: downgradeSchema(collection)(value.schema),
162
+ },
163
+ ]),
164
+ )
165
+ : undefined,
166
+ });
167
+
168
+ const downgradeContent =
169
+ (collection: IComponentsCollection) =>
170
+ (
171
+ record: OpenApi.IOperation.IContent,
172
+ ): Record<string, OpenApiV3_1.IOperation.IMediaType> =>
173
+ Object.fromEntries(
174
+ Object.entries(record)
175
+ .filter(([_, v]) => v !== undefined)
176
+ .map(
177
+ ([key, value]) =>
178
+ [
179
+ key,
180
+ {
181
+ ...value,
182
+ schema: value?.schema
183
+ ? downgradeSchema(collection)(value.schema)
184
+ : undefined,
185
+ // itemSchema is v3.2-only, remove it
186
+ itemSchema: undefined,
187
+ },
188
+ ] as const,
189
+ ),
190
+ );
191
+
192
+ /* -----------------------------------------------------------
193
+ DEFINITIONS
194
+ ----------------------------------------------------------- */
195
+ export const downgradeComponents = (
196
+ input: OpenApi.IComponents,
197
+ ): IComponentsCollection => {
198
+ const collection: IComponentsCollection = {
199
+ original: input,
200
+ downgraded: {
201
+ securitySchemes: input.securitySchemes
202
+ ? downgradeSecuritySchemes(input.securitySchemes)
203
+ : undefined,
204
+ },
205
+ };
206
+ if (input.schemas) {
207
+ collection.downgraded.schemas = {};
208
+ for (const [key, value] of Object.entries(input.schemas))
209
+ if (value !== undefined)
210
+ collection.downgraded.schemas[key] =
211
+ downgradeSchema(collection)(value);
212
+ }
213
+ return collection;
214
+ };
215
+
216
+ export const downgradeSchema =
217
+ (collection: IComponentsCollection) =>
218
+ (input: OpenApi.IJsonSchema): OpenApiV3_1.IJsonSchema => {
219
+ const union: OpenApiV3_1.IJsonSchema[] = [];
220
+ const attribute: OpenApiV3_1.IJsonSchema.__IAttribute = {
221
+ title: input.title,
222
+ description: input.description,
223
+ deprecated: input.deprecated,
224
+ readOnly: input.readOnly,
225
+ writeOnly: input.writeOnly,
226
+ example: input.example,
227
+ examples: input.examples,
228
+ ...Object.fromEntries(
229
+ Object.entries(input).filter(
230
+ ([key, value]) => key.startsWith("x-") && value !== undefined,
231
+ ),
232
+ ),
233
+ };
234
+ const visit = (schema: OpenApi.IJsonSchema): void => {
235
+ if (OpenApiTypeChecker.isNull(schema))
236
+ union.push({ type: "null" });
237
+ else if (OpenApiTypeChecker.isConstant(schema))
238
+ union.push({ const: schema.const });
239
+ else if (
240
+ OpenApiTypeChecker.isBoolean(schema) ||
241
+ OpenApiTypeChecker.isInteger(schema) ||
242
+ OpenApiTypeChecker.isNumber(schema) ||
243
+ OpenApiTypeChecker.isString(schema) ||
244
+ OpenApiTypeChecker.isReference(schema)
245
+ )
246
+ union.push({ ...schema });
247
+ else if (OpenApiTypeChecker.isArray(schema))
248
+ union.push({
249
+ ...schema,
250
+ items: downgradeSchema(collection)(schema.items),
251
+ });
252
+ else if (OpenApiTypeChecker.isTuple(schema))
253
+ union.push({
254
+ ...schema,
255
+ prefixItems: schema.prefixItems.map(
256
+ downgradeSchema(collection),
257
+ ),
258
+ additionalItems:
259
+ typeof schema.additionalItems === "object"
260
+ ? downgradeSchema(collection)(schema.additionalItems)
261
+ : schema.additionalItems,
262
+ });
263
+ else if (OpenApiTypeChecker.isObject(schema))
264
+ union.push({
265
+ ...schema,
266
+ properties: schema.properties
267
+ ? Object.fromEntries(
268
+ Object.entries(schema.properties)
269
+ .filter(([_, v]) => v !== undefined)
270
+ .map(([key, value]) => [
271
+ key,
272
+ downgradeSchema(collection)(value),
273
+ ]),
274
+ )
275
+ : undefined,
276
+ additionalProperties:
277
+ typeof schema.additionalProperties === "object"
278
+ ? downgradeSchema(collection)(schema.additionalProperties)
279
+ : schema.additionalProperties,
280
+ required: schema.required,
281
+ });
282
+ else if (OpenApiTypeChecker.isOneOf(schema))
283
+ schema.oneOf.forEach(visit);
284
+ };
285
+ visit(input);
286
+ return {
287
+ ...(union.length === 0
288
+ ? { type: undefined }
289
+ : union.length === 1
290
+ ? { ...union[0] }
291
+ : { oneOf: union }),
292
+ ...attribute,
293
+ };
294
+ };
295
+
296
+ const downgradeSecuritySchemes = (
297
+ input: Record<string, OpenApi.ISecurityScheme>,
298
+ ): Record<string, OpenApiV3_1.ISecurityScheme> =>
299
+ Object.fromEntries(
300
+ Object.entries(input)
301
+ .filter(([_, v]) => v !== undefined)
302
+ .map(([key, value]) => [key, downgradeSecurityScheme(value)]),
303
+ );
304
+
305
+ const downgradeSecurityScheme = (
306
+ input: OpenApi.ISecurityScheme,
307
+ ): OpenApiV3_1.ISecurityScheme => {
308
+ if (input.type === "oauth2") {
309
+ const { deviceAuthorization: _, ...flows } = input.flows;
310
+ return {
311
+ type: "oauth2",
312
+ flows,
313
+ description: input.description,
314
+ };
315
+ }
316
+ return { ...input } as OpenApiV3_1.ISecurityScheme;
317
+ };
318
+ }