@sdk-it/spec 0.46.0 → 0.46.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -0
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -6
- package/dist/index.js.map +2 -2
- package/dist/lib/find-polymorphic-varients.js +1 -1
- package/dist/lib/find-polymorphic-varients.js.map +1 -1
- package/dist/lib/is-primitive-schema.js +1 -1
- package/dist/lib/is-primitive-schema.js.map +1 -1
- package/dist/lib/is.d.ts +2 -0
- package/dist/lib/is.d.ts.map +1 -1
- package/dist/lib/is.js +5 -0
- package/dist/lib/is.js.map +2 -2
- package/dist/lib/pagination/guess-pagination.js +1 -1
- package/dist/lib/pagination/guess-pagination.js.map +1 -1
- package/dist/lib/processing-plugins/extract-inline-schemas.d.ts.map +1 -1
- package/dist/lib/processing-plugins/extract-inline-schemas.js +151 -3
- package/dist/lib/processing-plugins/extract-inline-schemas.js.map +2 -2
- package/dist/lib/processing-plugins/normalize-request-bodies.d.ts +3 -0
- package/dist/lib/processing-plugins/normalize-request-bodies.d.ts.map +1 -1
- package/dist/lib/processing-plugins/normalize-request-bodies.js +99 -4
- package/dist/lib/processing-plugins/normalize-request-bodies.js.map +2 -2
- package/dist/lib/processing-plugins/normalize-responses.d.ts.map +1 -1
- package/dist/lib/processing-plugins/normalize-responses.js +126 -3
- package/dist/lib/processing-plugins/normalize-responses.js.map +2 -2
- package/dist/lib/processing-plugins/normalize-schemas.d.ts.map +1 -1
- package/dist/lib/processing-plugins/normalize-schemas.js +159 -2
- package/dist/lib/processing-plugins/normalize-schemas.js.map +3 -3
- package/package.json +2 -2
- package/dist/lib/tune-request-body.d.ts +0 -5
- package/dist/lib/tune-request-body.d.ts.map +0 -1
- package/dist/lib/tune-request-body.js +0 -101
- package/dist/lib/tune-request-body.js.map +0 -7
- package/dist/lib/tune-response.d.ts +0 -5
- package/dist/lib/tune-response.d.ts.map +0 -1
- package/dist/lib/tune-response.js +0 -135
- package/dist/lib/tune-response.js.map +0 -7
- package/dist/lib/tune.d.ts +0 -11
- package/dist/lib/tune.d.ts.map +0 -1
- package/dist/lib/tune.js +0 -315
- package/dist/lib/tune.js.map +0 -7
|
@@ -1,6 +1,100 @@
|
|
|
1
|
-
import { resolveRef } from "@sdk-it/core/ref.js";
|
|
1
|
+
import { followRef, isRef, resolveRef } from "@sdk-it/core/ref.js";
|
|
2
|
+
import { isEmpty } from "@sdk-it/core/utils.js";
|
|
3
|
+
import { findUniqueSchemaName } from "../find-unique-schema-name.js";
|
|
2
4
|
import { iterateOperations } from "../for-each-operation.js";
|
|
3
|
-
import {
|
|
5
|
+
import { securityToOptions } from "../security.js";
|
|
6
|
+
function patchParameters(spec, schema, parameters, security) {
|
|
7
|
+
const securityOptions = securityToOptions(
|
|
8
|
+
spec,
|
|
9
|
+
security,
|
|
10
|
+
spec.components.securitySchemes
|
|
11
|
+
);
|
|
12
|
+
const required = new Set(
|
|
13
|
+
Array.isArray(schema.required) ? schema.required : []
|
|
14
|
+
);
|
|
15
|
+
schema["x-properties"] ??= {};
|
|
16
|
+
for (const param of parameters) {
|
|
17
|
+
if (param.required) {
|
|
18
|
+
required.add(param.name);
|
|
19
|
+
}
|
|
20
|
+
schema["x-properties"][param.name] = {
|
|
21
|
+
"x-in": param.in,
|
|
22
|
+
...isRef(param.schema) ? followRef(spec, param.schema.$ref) : param.schema ?? { type: "string" }
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
for (const param of securityOptions) {
|
|
26
|
+
required.delete(param.name);
|
|
27
|
+
schema["x-properties"][param.name] = {
|
|
28
|
+
"x-in": "header",
|
|
29
|
+
...isRef(param.schema) ? followRef(spec, param.schema.$ref) : param.schema ?? { type: "string" }
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
schema["x-required"] = [...required];
|
|
33
|
+
}
|
|
34
|
+
function normalizeRequestBody(spec, operationId, operation, parameters, security) {
|
|
35
|
+
const requestBodySource = isRef(operation.requestBody) ? followRef(spec, operation.requestBody.$ref) : operation.requestBody ?? {
|
|
36
|
+
content: {},
|
|
37
|
+
required: false
|
|
38
|
+
};
|
|
39
|
+
const requestBody = structuredClone(requestBodySource);
|
|
40
|
+
if (isEmpty(requestBody.content)) {
|
|
41
|
+
const inputName = findUniqueSchemaName(spec, operationId, [
|
|
42
|
+
"input",
|
|
43
|
+
"payload",
|
|
44
|
+
"request"
|
|
45
|
+
]);
|
|
46
|
+
const schema = {
|
|
47
|
+
"x-inputname": inputName,
|
|
48
|
+
"x-requestbody": true
|
|
49
|
+
};
|
|
50
|
+
patchParameters(spec, schema, parameters, security);
|
|
51
|
+
const normalized = {
|
|
52
|
+
...requestBody,
|
|
53
|
+
content: {
|
|
54
|
+
"application/empty": {
|
|
55
|
+
schema: { $ref: `#/components/schemas/${inputName}` }
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
spec.components.schemas[inputName] = schema;
|
|
60
|
+
return normalized;
|
|
61
|
+
}
|
|
62
|
+
for (const contentType in requestBody.content) {
|
|
63
|
+
const mediaType = requestBody.content[contentType];
|
|
64
|
+
const inputName = findUniqueSchemaName(spec, operationId, [
|
|
65
|
+
"input",
|
|
66
|
+
"payload",
|
|
67
|
+
"request"
|
|
68
|
+
]);
|
|
69
|
+
let schema;
|
|
70
|
+
switch (true) {
|
|
71
|
+
case isRef(mediaType.schema):
|
|
72
|
+
schema = structuredClone(
|
|
73
|
+
followRef(spec, mediaType.schema.$ref)
|
|
74
|
+
);
|
|
75
|
+
break;
|
|
76
|
+
case isEmpty(mediaType.schema):
|
|
77
|
+
schema ??= {};
|
|
78
|
+
console.warn(
|
|
79
|
+
`Request body schema for content type "${contentType}" is empty.`
|
|
80
|
+
);
|
|
81
|
+
break;
|
|
82
|
+
default:
|
|
83
|
+
schema = structuredClone(mediaType.schema);
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
patchParameters(spec, schema, parameters, security);
|
|
87
|
+
spec.components.schemas[inputName] = {
|
|
88
|
+
...schema,
|
|
89
|
+
"x-requestbody": true,
|
|
90
|
+
"x-inputname": inputName
|
|
91
|
+
};
|
|
92
|
+
requestBody.content[contentType].schema = {
|
|
93
|
+
$ref: `#/components/schemas/${inputName}`
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
return requestBody;
|
|
97
|
+
}
|
|
4
98
|
function normalizeRequestBodies() {
|
|
5
99
|
return {
|
|
6
100
|
name: "normalize-request-bodies",
|
|
@@ -27,7 +121,7 @@ function normalizeRequestBodies() {
|
|
|
27
121
|
continue;
|
|
28
122
|
}
|
|
29
123
|
}
|
|
30
|
-
tunedOperation.requestBody =
|
|
124
|
+
tunedOperation.requestBody = normalizeRequestBody(
|
|
31
125
|
spec,
|
|
32
126
|
tunedOperation.operationId,
|
|
33
127
|
operation,
|
|
@@ -39,6 +133,7 @@ function normalizeRequestBodies() {
|
|
|
39
133
|
};
|
|
40
134
|
}
|
|
41
135
|
export {
|
|
42
|
-
normalizeRequestBodies
|
|
136
|
+
normalizeRequestBodies,
|
|
137
|
+
patchParameters
|
|
43
138
|
};
|
|
44
139
|
//# sourceMappingURL=normalize-request-bodies.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/processing-plugins/normalize-request-bodies.ts"],
|
|
4
|
-
"sourcesContent": ["import type {
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import type {\n OperationObject,\n ParameterObject,\n RequestBodyObject,\n SchemaObject,\n SecurityRequirementObject,\n} from 'openapi3-ts/oas31';\n\nimport { followRef, isRef, resolveRef } from '@sdk-it/core/ref.js';\nimport { isEmpty } from '@sdk-it/core/utils.js';\n\nimport { findUniqueSchemaName } from '../find-unique-schema-name.js';\nimport { iterateOperations } from '../for-each-operation.js';\nimport type { ProcessingPlugin } from '../processing.js';\nimport { securityToOptions } from '../security.js';\nimport type {\n IR,\n OurRequestBodyObject,\n TunedOperationObject,\n} from '../types.js';\n\nexport function patchParameters(\n spec: IR,\n schema: SchemaObject,\n parameters: ParameterObject[],\n security: SecurityRequirementObject[],\n) {\n const securityOptions = securityToOptions(\n spec,\n security,\n spec.components.securitySchemes,\n );\n\n const required = new Set(\n Array.isArray(schema.required) ? schema.required : [],\n );\n schema['x-properties'] ??= {};\n for (const param of parameters) {\n if (param.required) {\n required.add(param.name);\n }\n schema['x-properties'][param.name] = {\n 'x-in': param.in,\n ...(isRef(param.schema)\n ? followRef<SchemaObject>(spec, param.schema.$ref)\n : (param.schema ?? { type: 'string' })),\n };\n }\n for (const param of securityOptions) {\n required.delete(param.name);\n schema['x-properties'][param.name] = {\n 'x-in': 'header',\n ...(isRef(param.schema)\n ? followRef<SchemaObject>(spec, param.schema.$ref)\n : (param.schema ?? { type: 'string' })),\n };\n }\n schema['x-required'] = [...required];\n}\n\nfunction normalizeRequestBody(\n spec: IR,\n operationId: string,\n operation: OperationObject,\n parameters: ParameterObject[],\n security: SecurityRequirementObject[],\n): OurRequestBodyObject {\n const requestBodySource = isRef(operation.requestBody)\n ? followRef<RequestBodyObject>(spec, operation.requestBody.$ref)\n : (operation.requestBody ?? {\n content: {},\n required: false,\n });\n const requestBody = structuredClone(requestBodySource);\n if (isEmpty(requestBody.content)) {\n const inputName = findUniqueSchemaName(spec, operationId, [\n 'input',\n 'payload',\n 'request',\n ]);\n const schema: SchemaObject = {\n 'x-inputname': inputName,\n 'x-requestbody': true,\n };\n patchParameters(spec, schema, parameters, security);\n const normalized: OurRequestBodyObject = {\n ...requestBody,\n content: {\n 'application/empty': {\n schema: { $ref: `#/components/schemas/${inputName}` },\n },\n },\n };\n\n spec.components.schemas[inputName] = schema;\n return normalized;\n }\n for (const contentType in requestBody.content) {\n const mediaType = requestBody.content[contentType];\n const inputName = findUniqueSchemaName(spec, operationId, [\n 'input',\n 'payload',\n 'request',\n ]);\n let schema: SchemaObject | undefined;\n\n switch (true) {\n case isRef(mediaType.schema):\n schema = structuredClone(\n followRef<SchemaObject>(spec, mediaType.schema.$ref),\n );\n break;\n case isEmpty(mediaType.schema):\n schema ??= {};\n console.warn(\n `Request body schema for content type \"${contentType}\" is empty.`,\n );\n break;\n default:\n schema = structuredClone(mediaType.schema);\n break;\n }\n\n patchParameters(spec, schema, parameters, security);\n spec.components.schemas[inputName] = {\n ...schema,\n 'x-requestbody': true,\n 'x-inputname': inputName,\n };\n\n requestBody.content[contentType].schema = {\n $ref: `#/components/schemas/${inputName}`,\n };\n }\n return requestBody as OurRequestBodyObject;\n}\n\nexport function normalizeRequestBodies(): ProcessingPlugin {\n return {\n name: 'normalize-request-bodies',\n process({ spec }) {\n for (const { operation } of iterateOperations(spec)) {\n const tunedOperation = operation as TunedOperationObject;\n if (operation.requestBody) {\n const requestBody = resolveRef<RequestBodyObject>(\n spec,\n operation.requestBody,\n );\n const schemas = Object.values(requestBody.content).map(\n ({ schema }) =>\n schema ? resolveRef<SchemaObject>(spec, schema) : undefined,\n );\n if (\n schemas.length > 0 &&\n schemas.every((schema) => schema?.['x-requestbody'])\n ) {\n for (const schema of new Set(schemas)) {\n patchParameters(\n spec,\n schema as SchemaObject,\n tunedOperation.parameters,\n operation.security ?? [],\n );\n }\n continue;\n }\n }\n tunedOperation.requestBody = normalizeRequestBody(\n spec,\n tunedOperation.operationId,\n operation,\n tunedOperation.parameters,\n operation.security ?? [],\n );\n }\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalize-responses.d.ts","sourceRoot":"","sources":["../../../src/lib/processing-plugins/normalize-responses.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"normalize-responses.d.ts","sourceRoot":"","sources":["../../../src/lib/processing-plugins/normalize-responses.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AA8IzD,wBAAgB,kBAAkB,IAAI,gBAAgB,CA+BrD"}
|
|
@@ -1,6 +1,129 @@
|
|
|
1
|
+
import { parse as parseContentType } from "fast-content-type-parse";
|
|
2
|
+
import { isRef, parseRef, resolveRef } from "@sdk-it/core/ref.js";
|
|
3
|
+
import { isEmpty, pascalcase } from "@sdk-it/core/utils.js";
|
|
4
|
+
import { findUniqueSchemaName } from "../find-unique-schema-name.js";
|
|
1
5
|
import { iterateOperations } from "../for-each-operation.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
6
|
+
import {
|
|
7
|
+
isBinaryContentType,
|
|
8
|
+
isSseContentType,
|
|
9
|
+
isStreamingContentType,
|
|
10
|
+
isSuccessStatusCode,
|
|
11
|
+
isTextContentType,
|
|
12
|
+
parseJsonContentType
|
|
13
|
+
} from "../is.js";
|
|
14
|
+
function normalizeOperationResponses(spec, operationId, operation, responsesConfig) {
|
|
15
|
+
const responses = operation.responses ?? {};
|
|
16
|
+
operation.responses ??= {};
|
|
17
|
+
let foundSuccessResponse = false;
|
|
18
|
+
for (const status in responses) {
|
|
19
|
+
operation.responses[status] = structuredClone(
|
|
20
|
+
resolveRef(spec, responses[status])
|
|
21
|
+
);
|
|
22
|
+
if (status !== "default" && isSuccessStatusCode(status)) {
|
|
23
|
+
foundSuccessResponse = true;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (!foundSuccessResponse) {
|
|
27
|
+
operation.responses["200"] = {
|
|
28
|
+
description: "OK",
|
|
29
|
+
content: {
|
|
30
|
+
"application/json": {
|
|
31
|
+
schema: {}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
for (const status in operation.responses) {
|
|
37
|
+
const response = operation.responses[status];
|
|
38
|
+
const statusCode = +status;
|
|
39
|
+
if (!responsesConfig?.flattenErrorResponses && !isSuccessStatusCode(status)) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (isEmpty(response.content)) {
|
|
43
|
+
response.content = {
|
|
44
|
+
"application/octet-stream": {}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
let responseName;
|
|
48
|
+
for (const [contentType, mediaType] of Object.entries(
|
|
49
|
+
response.content
|
|
50
|
+
)) {
|
|
51
|
+
if (isRef(mediaType.schema)) {
|
|
52
|
+
const { model } = parseRef(mediaType.schema.$ref);
|
|
53
|
+
Object.assign(spec.components.schemas[model], {
|
|
54
|
+
"x-responsebody": true
|
|
55
|
+
});
|
|
56
|
+
responseName ??= model;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const outputName = statusCode !== 200 ? findUniqueSchemaName(spec, `${pascalcase(operationId)}${status}`, [
|
|
60
|
+
"output",
|
|
61
|
+
"payload",
|
|
62
|
+
"result"
|
|
63
|
+
]) : findUniqueSchemaName(spec, operationId, [
|
|
64
|
+
"output",
|
|
65
|
+
"payload",
|
|
66
|
+
"result"
|
|
67
|
+
]);
|
|
68
|
+
responseName ??= outputName;
|
|
69
|
+
const isSse = isSseContentType(contentType);
|
|
70
|
+
const normalizedContentType = normalizeContentType(contentType);
|
|
71
|
+
const hasContentDisposition = hasHeader(
|
|
72
|
+
response.headers,
|
|
73
|
+
"Content-Disposition"
|
|
74
|
+
);
|
|
75
|
+
const isBinary = isBinaryContentType(contentType) || isStreamingContentType(normalizedContentType) && hasContentDisposition;
|
|
76
|
+
const isText = isTextContentType(contentType);
|
|
77
|
+
if (parseJsonContentType(contentType)) {
|
|
78
|
+
if (isEmpty(mediaType.schema)) {
|
|
79
|
+
spec.components.schemas[outputName] = {
|
|
80
|
+
type: "object",
|
|
81
|
+
additionalProperties: true
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
if (isEmpty(mediaType.schema) && (isText || isBinary)) {
|
|
86
|
+
mediaType.schema = {
|
|
87
|
+
type: "string",
|
|
88
|
+
...isBinary ? { format: "binary" } : {}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
spec.components.schemas[outputName] = {
|
|
92
|
+
...spec.components.schemas[outputName],
|
|
93
|
+
"x-stream": isSse || !isText && !isBinary,
|
|
94
|
+
...isSse ? { "x-sse": true } : {}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
spec.components.schemas[outputName] = {
|
|
98
|
+
...spec.components.schemas[outputName],
|
|
99
|
+
...mediaType.schema,
|
|
100
|
+
"x-responsebody": true,
|
|
101
|
+
"x-response-group": operationId
|
|
102
|
+
};
|
|
103
|
+
operation.responses[status].content[contentType].schema = {
|
|
104
|
+
$ref: `#/components/schemas/${outputName}`
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
if (responseName) {
|
|
108
|
+
response["x-response-name"] = responseName;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return operation.responses;
|
|
112
|
+
}
|
|
113
|
+
function normalizeContentType(contentType) {
|
|
114
|
+
try {
|
|
115
|
+
return parseContentType(contentType)?.type?.toLowerCase();
|
|
116
|
+
} catch {
|
|
117
|
+
return contentType.split(";")[0]?.trim().toLowerCase();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function hasHeader(headers, name) {
|
|
121
|
+
if (!headers) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
const target = name.toLowerCase();
|
|
125
|
+
return Object.keys(headers).some((key) => key.toLowerCase() === target);
|
|
126
|
+
}
|
|
4
127
|
function normalizeResponses() {
|
|
5
128
|
return {
|
|
6
129
|
name: "normalize-responses",
|
|
@@ -14,7 +137,7 @@ function normalizeResponses() {
|
|
|
14
137
|
const hadSuccessResponse = Object.keys(operation.responses ?? {}).some(
|
|
15
138
|
isSuccessStatusCode
|
|
16
139
|
);
|
|
17
|
-
operation.responses =
|
|
140
|
+
operation.responses = normalizeOperationResponses(
|
|
18
141
|
spec,
|
|
19
142
|
operation.operationId,
|
|
20
143
|
operation,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/processing-plugins/normalize-responses.ts"],
|
|
4
|
-
"sourcesContent": ["import { iterateOperations } from '../for-each-operation.js';\nimport {
|
|
5
|
-
"mappings": "AAAA,SAAS,yBAAyB;AAClC,SAAS,
|
|
4
|
+
"sourcesContent": ["import { parse as parseContentType } from 'fast-content-type-parse';\nimport type {\n MediaTypeObject,\n OperationObject,\n ResponseObject,\n} from 'openapi3-ts/oas31';\n\nimport { isRef, parseRef, resolveRef } from '@sdk-it/core/ref.js';\nimport { isEmpty, pascalcase } from '@sdk-it/core/utils.js';\n\nimport { findUniqueSchemaName } from '../find-unique-schema-name.js';\nimport { iterateOperations } from '../for-each-operation.js';\nimport {\n isBinaryContentType,\n isSseContentType,\n isStreamingContentType,\n isSuccessStatusCode,\n isTextContentType,\n parseJsonContentType,\n} from '../is.js';\nimport type { ResponsesConfig } from '../options.js';\nimport type { ProcessingPlugin } from '../processing.js';\nimport type { IR, TunedOperationObject } from '../types.js';\n\nfunction normalizeOperationResponses(\n spec: IR,\n operationId: string,\n operation: OperationObject,\n responsesConfig?: ResponsesConfig,\n) {\n const responses = operation.responses ?? {};\n operation.responses ??= {};\n let foundSuccessResponse = false;\n for (const status in responses) {\n operation.responses[status] = structuredClone(\n resolveRef<ResponseObject>(spec, responses[status]),\n );\n\n if (status !== 'default' && isSuccessStatusCode(status)) {\n foundSuccessResponse = true;\n }\n }\n\n if (!foundSuccessResponse) {\n operation.responses['200'] = {\n description: 'OK',\n content: {\n 'application/json': {\n schema: {},\n },\n },\n };\n }\n\n for (const status in operation.responses) {\n const response = operation.responses[status] as ResponseObject;\n const statusCode = +status;\n\n if (\n !responsesConfig?.flattenErrorResponses &&\n !isSuccessStatusCode(status)\n ) {\n continue;\n }\n\n if (isEmpty(response.content)) {\n response.content = {\n 'application/octet-stream': {},\n };\n }\n\n let responseName: string | undefined;\n for (const [contentType, mediaType] of Object.entries(\n response.content as Record<string, MediaTypeObject>,\n )) {\n if (isRef(mediaType.schema)) {\n const { model } = parseRef(mediaType.schema.$ref);\n Object.assign(spec.components.schemas[model], {\n 'x-responsebody': true,\n });\n responseName ??= model;\n continue;\n }\n const outputName =\n statusCode !== 200\n ? findUniqueSchemaName(spec, `${pascalcase(operationId)}${status}`, [\n 'output',\n 'payload',\n 'result',\n ])\n : findUniqueSchemaName(spec, operationId, [\n 'output',\n 'payload',\n 'result',\n ]);\n responseName ??= outputName;\n const isSse = isSseContentType(contentType);\n const normalizedContentType = normalizeContentType(contentType);\n const hasContentDisposition = hasHeader(\n response.headers,\n 'Content-Disposition',\n );\n const isBinary =\n isBinaryContentType(contentType) ||\n (isStreamingContentType(normalizedContentType) &&\n hasContentDisposition);\n const isText = isTextContentType(contentType);\n\n if (parseJsonContentType(contentType)) {\n if (isEmpty(mediaType.schema)) {\n spec.components.schemas[outputName] = {\n type: 'object',\n additionalProperties: true,\n };\n }\n } else {\n if (isEmpty(mediaType.schema) && (isText || isBinary)) {\n mediaType.schema = {\n type: 'string',\n ...(isBinary ? { format: 'binary' } : {}),\n };\n }\n spec.components.schemas[outputName] = {\n ...spec.components.schemas[outputName],\n 'x-stream': isSse || (!isText && !isBinary),\n ...(isSse ? { 'x-sse': true } : {}),\n };\n }\n\n spec.components.schemas[outputName] = {\n ...spec.components.schemas[outputName],\n ...mediaType.schema,\n 'x-responsebody': true,\n 'x-response-group': operationId,\n };\n operation.responses[status].content[contentType].schema = {\n $ref: `#/components/schemas/${outputName}`,\n };\n }\n if (responseName) {\n response['x-response-name'] = responseName;\n }\n }\n\n return operation.responses;\n}\n\nfunction normalizeContentType(contentType: string) {\n try {\n return parseContentType(contentType)?.type?.toLowerCase();\n } catch {\n return contentType.split(';')[0]?.trim().toLowerCase();\n }\n}\n\nfunction hasHeader(headers: ResponseObject['headers'], name: string) {\n if (!headers) {\n return false;\n }\n const target = name.toLowerCase();\n return Object.keys(headers).some((key) => key.toLowerCase() === target);\n}\n\nexport function normalizeResponses(): ProcessingPlugin {\n return {\n name: 'normalize-responses',\n process({ spec, options, report }) {\n for (const { entry, operation } of iterateOperations(spec)) {\n if (!operation.operationId) {\n throw new Error(\n `Cannot normalize responses before assigning an operation ID for ${entry.method.toUpperCase()} ${entry.path}`,\n );\n }\n const hadSuccessResponse = Object.keys(operation.responses ?? {}).some(\n isSuccessStatusCode,\n );\n (operation as TunedOperationObject).responses =\n normalizeOperationResponses(\n spec,\n operation.operationId,\n operation,\n options.responses,\n );\n if (!hadSuccessResponse) {\n report({\n severity: 'warning',\n code: 'success-response-added',\n message: 'Added a default 200 success response',\n path: `${entry.method.toUpperCase()} ${entry.path}`,\n });\n }\n }\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,SAAS,wBAAwB;AAO1C,SAAS,OAAO,UAAU,kBAAkB;AAC5C,SAAS,SAAS,kBAAkB;AAEpC,SAAS,4BAA4B;AACrC,SAAS,yBAAyB;AAClC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAKP,SAAS,4BACP,MACA,aACA,WACA,iBACA;AACA,QAAM,YAAY,UAAU,aAAa,CAAC;AAC1C,YAAU,cAAc,CAAC;AACzB,MAAI,uBAAuB;AAC3B,aAAW,UAAU,WAAW;AAC9B,cAAU,UAAU,MAAM,IAAI;AAAA,MAC5B,WAA2B,MAAM,UAAU,MAAM,CAAC;AAAA,IACpD;AAEA,QAAI,WAAW,aAAa,oBAAoB,MAAM,GAAG;AACvD,6BAAuB;AAAA,IACzB;AAAA,EACF;AAEA,MAAI,CAAC,sBAAsB;AACzB,cAAU,UAAU,KAAK,IAAI;AAAA,MAC3B,aAAa;AAAA,MACb,SAAS;AAAA,QACP,oBAAoB;AAAA,UAClB,QAAQ,CAAC;AAAA,QACX;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,aAAW,UAAU,UAAU,WAAW;AACxC,UAAM,WAAW,UAAU,UAAU,MAAM;AAC3C,UAAM,aAAa,CAAC;AAEpB,QACE,CAAC,iBAAiB,yBAClB,CAAC,oBAAoB,MAAM,GAC3B;AACA;AAAA,IACF;AAEA,QAAI,QAAQ,SAAS,OAAO,GAAG;AAC7B,eAAS,UAAU;AAAA,QACjB,4BAA4B,CAAC;AAAA,MAC/B;AAAA,IACF;AAEA,QAAI;AACJ,eAAW,CAAC,aAAa,SAAS,KAAK,OAAO;AAAA,MAC5C,SAAS;AAAA,IACX,GAAG;AACD,UAAI,MAAM,UAAU,MAAM,GAAG;AAC3B,cAAM,EAAE,MAAM,IAAI,SAAS,UAAU,OAAO,IAAI;AAChD,eAAO,OAAO,KAAK,WAAW,QAAQ,KAAK,GAAG;AAAA,UAC5C,kBAAkB;AAAA,QACpB,CAAC;AACD,yBAAiB;AACjB;AAAA,MACF;AACA,YAAM,aACJ,eAAe,MACX,qBAAqB,MAAM,GAAG,WAAW,WAAW,CAAC,GAAG,MAAM,IAAI;AAAA,QAChE;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC,IACD,qBAAqB,MAAM,aAAa;AAAA,QACtC;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AACP,uBAAiB;AACjB,YAAM,QAAQ,iBAAiB,WAAW;AAC1C,YAAM,wBAAwB,qBAAqB,WAAW;AAC9D,YAAM,wBAAwB;AAAA,QAC5B,SAAS;AAAA,QACT;AAAA,MACF;AACA,YAAM,WACJ,oBAAoB,WAAW,KAC9B,uBAAuB,qBAAqB,KAC3C;AACJ,YAAM,SAAS,kBAAkB,WAAW;AAE5C,UAAI,qBAAqB,WAAW,GAAG;AACrC,YAAI,QAAQ,UAAU,MAAM,GAAG;AAC7B,eAAK,WAAW,QAAQ,UAAU,IAAI;AAAA,YACpC,MAAM;AAAA,YACN,sBAAsB;AAAA,UACxB;AAAA,QACF;AAAA,MACF,OAAO;AACL,YAAI,QAAQ,UAAU,MAAM,MAAM,UAAU,WAAW;AACrD,oBAAU,SAAS;AAAA,YACjB,MAAM;AAAA,YACN,GAAI,WAAW,EAAE,QAAQ,SAAS,IAAI,CAAC;AAAA,UACzC;AAAA,QACF;AACA,aAAK,WAAW,QAAQ,UAAU,IAAI;AAAA,UACpC,GAAG,KAAK,WAAW,QAAQ,UAAU;AAAA,UACrC,YAAY,SAAU,CAAC,UAAU,CAAC;AAAA,UAClC,GAAI,QAAQ,EAAE,SAAS,KAAK,IAAI,CAAC;AAAA,QACnC;AAAA,MACF;AAEA,WAAK,WAAW,QAAQ,UAAU,IAAI;AAAA,QACpC,GAAG,KAAK,WAAW,QAAQ,UAAU;AAAA,QACrC,GAAG,UAAU;AAAA,QACb,kBAAkB;AAAA,QAClB,oBAAoB;AAAA,MACtB;AACA,gBAAU,UAAU,MAAM,EAAE,QAAQ,WAAW,EAAE,SAAS;AAAA,QACxD,MAAM,wBAAwB,UAAU;AAAA,MAC1C;AAAA,IACF;AACA,QAAI,cAAc;AAChB,eAAS,iBAAiB,IAAI;AAAA,IAChC;AAAA,EACF;AAEA,SAAO,UAAU;AACnB;AAEA,SAAS,qBAAqB,aAAqB;AACjD,MAAI;AACF,WAAO,iBAAiB,WAAW,GAAG,MAAM,YAAY;AAAA,EAC1D,QAAQ;AACN,WAAO,YAAY,MAAM,GAAG,EAAE,CAAC,GAAG,KAAK,EAAE,YAAY;AAAA,EACvD;AACF;AAEA,SAAS,UAAU,SAAoC,MAAc;AACnE,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AACA,QAAM,SAAS,KAAK,YAAY;AAChC,SAAO,OAAO,KAAK,OAAO,EAAE,KAAK,CAAC,QAAQ,IAAI,YAAY,MAAM,MAAM;AACxE;AAEO,SAAS,qBAAuC;AACrD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,QAAQ,EAAE,MAAM,SAAS,OAAO,GAAG;AACjC,iBAAW,EAAE,OAAO,UAAU,KAAK,kBAAkB,IAAI,GAAG;AAC1D,YAAI,CAAC,UAAU,aAAa;AAC1B,gBAAM,IAAI;AAAA,YACR,mEAAmE,MAAM,OAAO,YAAY,CAAC,IAAI,MAAM,IAAI;AAAA,UAC7G;AAAA,QACF;AACA,cAAM,qBAAqB,OAAO,KAAK,UAAU,aAAa,CAAC,CAAC,EAAE;AAAA,UAChE;AAAA,QACF;AACA,QAAC,UAAmC,YAClC;AAAA,UACE;AAAA,UACA,UAAU;AAAA,UACV;AAAA,UACA,QAAQ;AAAA,QACV;AACF,YAAI,CAAC,oBAAoB;AACvB,iBAAO;AAAA,YACL,UAAU;AAAA,YACV,MAAM;AAAA,YACN,SAAS;AAAA,YACT,MAAM,GAAG,MAAM,OAAO,YAAY,CAAC,IAAI,MAAM,IAAI;AAAA,UACnD,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalize-schemas.d.ts","sourceRoot":"","sources":["../../../src/lib/processing-plugins/normalize-schemas.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"normalize-schemas.d.ts","sourceRoot":"","sources":["../../../src/lib/processing-plugins/normalize-schemas.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAmLzD,wBAAgB,gBAAgB,IAAI,gBAAgB,CAOnD"}
|
|
@@ -1,9 +1,166 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { merge, uniq } from "lodash-es";
|
|
2
|
+
import assert from "node:assert";
|
|
3
|
+
import { isEmpty, isRef, notRef, resolveRef, snakecase } from "@sdk-it/core";
|
|
4
|
+
import { findVarients } from "../find-polymorphic-varients.js";
|
|
5
|
+
import { formatName } from "../format-name.js";
|
|
6
|
+
import { isPrimitiveSchema } from "../is-primitive-schema.js";
|
|
7
|
+
function normalizeSchemaObjects(spec, schemas, visited = /* @__PURE__ */ new Set()) {
|
|
8
|
+
for (const schema of schemas) {
|
|
9
|
+
if (isRef(schema)) continue;
|
|
10
|
+
if (!isEmpty(schema.properties)) {
|
|
11
|
+
schema.type = "object";
|
|
12
|
+
delete schema.oneOf;
|
|
13
|
+
delete schema.anyOf;
|
|
14
|
+
normalizeSchemaObjects(spec, Object.values(schema.properties), visited);
|
|
15
|
+
for (const [key, value] of Object.entries(schema.properties)) {
|
|
16
|
+
if (notRef(value) && isPrimitiveSchema(value)) {
|
|
17
|
+
value.default ??= schema.default?.[key];
|
|
18
|
+
delete schema.default?.[key];
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
delete schema.default;
|
|
22
|
+
}
|
|
23
|
+
if (!isEmpty(schema["x-properties"])) {
|
|
24
|
+
normalizeSchemaObjects(
|
|
25
|
+
spec,
|
|
26
|
+
Object.values(schema["x-properties"]),
|
|
27
|
+
visited
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
if (!isEmpty(schema.items)) {
|
|
31
|
+
delete schema.oneOf;
|
|
32
|
+
delete schema.anyOf;
|
|
33
|
+
schema.type = "array";
|
|
34
|
+
normalizeSchemaObjects(spec, [schema.items], visited);
|
|
35
|
+
const items = resolveRef(spec, schema.items);
|
|
36
|
+
if (Array.isArray(items.default)) {
|
|
37
|
+
schema.default ??= structuredClone(items.default);
|
|
38
|
+
}
|
|
39
|
+
delete items.default;
|
|
40
|
+
}
|
|
41
|
+
if (!isEmpty(schema.anyOf) && !isEmpty(schema.oneOf)) {
|
|
42
|
+
delete schema.anyOf;
|
|
43
|
+
}
|
|
44
|
+
if (isEmpty(schema.enum)) {
|
|
45
|
+
delete schema.enum;
|
|
46
|
+
}
|
|
47
|
+
if (!isEmpty(schema.enum)) {
|
|
48
|
+
if (schema.enum.length === 1) {
|
|
49
|
+
schema.const = schema.enum[0];
|
|
50
|
+
delete schema.enum;
|
|
51
|
+
} else {
|
|
52
|
+
const valuesSet = /* @__PURE__ */ new Set();
|
|
53
|
+
const valuesList = [];
|
|
54
|
+
for (const value of schema.enum) {
|
|
55
|
+
const formattedValue = formatName(snakecase(formatName(value)));
|
|
56
|
+
if (!valuesSet.has(formattedValue)) {
|
|
57
|
+
valuesSet.add(formattedValue);
|
|
58
|
+
valuesList.push(value);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
schema.enum = valuesList;
|
|
62
|
+
}
|
|
63
|
+
delete schema.allOf;
|
|
64
|
+
}
|
|
65
|
+
if (schema.const !== void 0) {
|
|
66
|
+
schema.default = schema.const;
|
|
67
|
+
}
|
|
68
|
+
if (!isEmpty(schema.allOf)) {
|
|
69
|
+
const schemas2 = schema.allOf;
|
|
70
|
+
const resolved = schemas2.map(
|
|
71
|
+
(item) => resolveRef(spec, item)
|
|
72
|
+
);
|
|
73
|
+
const hasObjects = resolved.some((item) => item.type === "object");
|
|
74
|
+
const hasOtherTypes = resolved.some(
|
|
75
|
+
(item) => item.type && item.type !== "object"
|
|
76
|
+
);
|
|
77
|
+
if (hasObjects && hasOtherTypes) {
|
|
78
|
+
assert(false, `allOf must be an object`);
|
|
79
|
+
}
|
|
80
|
+
merge(
|
|
81
|
+
schema,
|
|
82
|
+
...resolved.map((resolvedSchema, index) => {
|
|
83
|
+
const sourceSchema = schemas2[index];
|
|
84
|
+
if (isRef(sourceSchema)) {
|
|
85
|
+
if (visited.has(sourceSchema.$ref)) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
`Circular allOf reference detected: ${[
|
|
88
|
+
...visited,
|
|
89
|
+
sourceSchema.$ref
|
|
90
|
+
].join(" -> ")}`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
normalizeSchemaObjects(
|
|
94
|
+
spec,
|
|
95
|
+
[resolvedSchema],
|
|
96
|
+
new Set(visited).add(sourceSchema.$ref)
|
|
97
|
+
);
|
|
98
|
+
} else {
|
|
99
|
+
normalizeSchemaObjects(spec, [resolvedSchema], visited);
|
|
100
|
+
}
|
|
101
|
+
return resolvedSchema;
|
|
102
|
+
})
|
|
103
|
+
);
|
|
104
|
+
delete schema.allOf;
|
|
105
|
+
} else {
|
|
106
|
+
delete schema.allOf;
|
|
107
|
+
}
|
|
108
|
+
if (schema.type === "object" && isEmpty(schema.properties) && typeof schema.additionalProperties === "object" && !isEmpty(schema.additionalProperties) && notRef(schema.additionalProperties) && !isEmpty(schema.additionalProperties.properties)) {
|
|
109
|
+
normalizeSchemaObjects(
|
|
110
|
+
spec,
|
|
111
|
+
Object.values(schema.additionalProperties.properties),
|
|
112
|
+
visited
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
for (const kind of ["oneOf", "anyOf"]) {
|
|
116
|
+
if (!isEmpty(schema[kind])) {
|
|
117
|
+
delete schema.type;
|
|
118
|
+
normalizeSchemaObjects(spec, schema[kind], visited);
|
|
119
|
+
if (isEmpty(schema[kind])) {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
let enumSchemaIndex = -1;
|
|
123
|
+
const enumValues = [];
|
|
124
|
+
for (let index = 0; index < schema[kind].length; index++) {
|
|
125
|
+
const item = schema[kind][index];
|
|
126
|
+
if (notRef(item) && item.type === "string") {
|
|
127
|
+
if (item.enum && item.enum.length > 1) {
|
|
128
|
+
enumValues.push(...item.enum);
|
|
129
|
+
if (enumSchemaIndex === -1) {
|
|
130
|
+
enumSchemaIndex = index;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (enumSchemaIndex !== -1) {
|
|
136
|
+
const enumSchema = schema[kind][enumSchemaIndex];
|
|
137
|
+
if (notRef(enumSchema)) {
|
|
138
|
+
enumSchema.enum = uniq(enumValues);
|
|
139
|
+
}
|
|
140
|
+
schema[kind] = schema[kind].filter(
|
|
141
|
+
(item, index) => index === enumSchemaIndex || isRef(item)
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
const otherTypes = schema[kind].filter(
|
|
145
|
+
(item) => resolveRef(spec, item).type !== "null"
|
|
146
|
+
);
|
|
147
|
+
if (otherTypes.length === 1) {
|
|
148
|
+
Object.assign(schema, otherTypes[0]);
|
|
149
|
+
delete schema[kind];
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
schema["x-varients"] = findVarients(spec, schema[kind]);
|
|
153
|
+
} else {
|
|
154
|
+
delete schema[kind];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
2
159
|
function normalizeSchemas() {
|
|
3
160
|
return {
|
|
4
161
|
name: "normalize-schemas",
|
|
5
162
|
process({ spec }) {
|
|
6
|
-
|
|
163
|
+
normalizeSchemaObjects(spec, Object.values(spec.components.schemas));
|
|
7
164
|
}
|
|
8
165
|
};
|
|
9
166
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/processing-plugins/normalize-schemas.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ProcessingPlugin } from '../processing.js';\nimport {
|
|
5
|
-
"mappings": "AACA,SAAS,eAAe;
|
|
6
|
-
"names": []
|
|
4
|
+
"sourcesContent": ["import { merge, uniq } from 'lodash-es';\nimport assert from 'node:assert';\nimport type { ReferenceObject, SchemaObject } from 'openapi3-ts/oas31';\n\nimport { isEmpty, isRef, notRef, resolveRef, snakecase } from '@sdk-it/core';\n\nimport { findVarients } from '../find-polymorphic-varients.js';\nimport { formatName } from '../format-name.js';\nimport { isPrimitiveSchema } from '../is-primitive-schema.js';\nimport type { ProcessingPlugin } from '../processing.js';\nimport type { IR } from '../types.js';\n\nfunction normalizeSchemaObjects(\n spec: IR,\n schemas: (SchemaObject | ReferenceObject)[],\n visited = new Set<string>(),\n) {\n for (const schema of schemas) {\n if (isRef(schema)) continue;\n\n if (!isEmpty(schema.properties)) {\n schema.type = 'object';\n delete schema.oneOf;\n delete schema.anyOf;\n normalizeSchemaObjects(spec, Object.values(schema.properties), visited);\n for (const [key, value] of Object.entries(schema.properties)) {\n if (notRef(value) && isPrimitiveSchema(value)) {\n value.default ??= schema.default?.[key];\n delete schema.default?.[key];\n }\n }\n delete schema.default;\n }\n\n if (!isEmpty(schema['x-properties'])) {\n normalizeSchemaObjects(\n spec,\n Object.values(schema['x-properties']),\n visited,\n );\n }\n\n if (!isEmpty(schema.items)) {\n delete schema.oneOf;\n delete schema.anyOf;\n schema.type = 'array';\n normalizeSchemaObjects(spec, [schema.items], visited);\n const items = resolveRef<SchemaObject>(spec, schema.items);\n if (Array.isArray(items.default)) {\n schema.default ??= structuredClone(items.default);\n }\n delete items.default;\n }\n\n if (!isEmpty(schema.anyOf) && !isEmpty(schema.oneOf)) {\n delete schema.anyOf;\n }\n\n if (isEmpty(schema.enum)) {\n delete schema.enum;\n }\n\n if (!isEmpty(schema.enum)) {\n if (schema.enum.length === 1) {\n schema.const = schema.enum[0];\n delete schema.enum;\n } else {\n const valuesSet = new Set<string>();\n const valuesList = [];\n for (const value of schema.enum) {\n const formattedValue = formatName(snakecase(formatName(value)));\n if (!valuesSet.has(formattedValue)) {\n valuesSet.add(formattedValue);\n valuesList.push(value);\n }\n }\n schema.enum = valuesList;\n }\n delete schema.allOf;\n }\n\n if (schema.const !== undefined) {\n schema.default = schema.const;\n }\n\n if (!isEmpty(schema.allOf)) {\n const schemas = schema.allOf;\n const resolved = schemas.map((item) =>\n resolveRef<SchemaObject>(spec, item),\n );\n const hasObjects = resolved.some((item) => item.type === 'object');\n const hasOtherTypes = resolved.some(\n (item) => item.type && item.type !== 'object',\n );\n if (hasObjects && hasOtherTypes) {\n assert(false, `allOf must be an object`);\n }\n merge(\n schema,\n ...resolved.map((resolvedSchema, index) => {\n const sourceSchema = schemas[index];\n if (isRef(sourceSchema)) {\n if (visited.has(sourceSchema.$ref)) {\n throw new Error(\n `Circular allOf reference detected: ${[\n ...visited,\n sourceSchema.$ref,\n ].join(' -> ')}`,\n );\n }\n normalizeSchemaObjects(\n spec,\n [resolvedSchema],\n new Set(visited).add(sourceSchema.$ref),\n );\n } else {\n normalizeSchemaObjects(spec, [resolvedSchema], visited);\n }\n return resolvedSchema;\n }),\n );\n delete schema.allOf;\n } else {\n delete schema.allOf;\n }\n\n if (\n schema.type === 'object' &&\n isEmpty(schema.properties) &&\n typeof schema.additionalProperties === 'object' &&\n !isEmpty(schema.additionalProperties) &&\n notRef(schema.additionalProperties) &&\n !isEmpty(schema.additionalProperties.properties)\n ) {\n normalizeSchemaObjects(\n spec,\n Object.values(schema.additionalProperties.properties),\n visited,\n );\n }\n\n for (const kind of ['oneOf', 'anyOf'] as const) {\n if (!isEmpty(schema[kind])) {\n delete schema.type;\n normalizeSchemaObjects(spec, schema[kind], visited);\n if (isEmpty(schema[kind])) {\n continue;\n }\n\n let enumSchemaIndex = -1;\n const enumValues: string[] = [];\n for (let index = 0; index < schema[kind].length; index++) {\n const item = schema[kind][index];\n if (notRef(item) && item.type === 'string') {\n if (item.enum && item.enum.length > 1) {\n enumValues.push(...item.enum);\n if (enumSchemaIndex === -1) {\n enumSchemaIndex = index;\n }\n }\n }\n }\n if (enumSchemaIndex !== -1) {\n const enumSchema = schema[kind][enumSchemaIndex];\n if (notRef(enumSchema)) {\n enumSchema.enum = uniq(enumValues);\n }\n schema[kind] = schema[kind].filter(\n (item, index) => index === enumSchemaIndex || isRef(item),\n );\n }\n const otherTypes = schema[kind].filter(\n (item) => resolveRef<SchemaObject>(spec, item).type !== 'null',\n );\n if (otherTypes.length === 1) {\n Object.assign(schema, otherTypes[0]);\n delete schema[kind];\n continue;\n }\n\n schema['x-varients'] = findVarients(spec, schema[kind]);\n } else {\n delete schema[kind];\n }\n }\n }\n}\n\nexport function normalizeSchemas(): ProcessingPlugin {\n return {\n name: 'normalize-schemas',\n process({ spec }) {\n normalizeSchemaObjects(spec, Object.values(spec.components.schemas));\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,OAAO,YAAY;AAC5B,OAAO,YAAY;AAGnB,SAAS,SAAS,OAAO,QAAQ,YAAY,iBAAiB;AAE9D,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;AAC3B,SAAS,yBAAyB;AAIlC,SAAS,uBACP,MACA,SACA,UAAU,oBAAI,IAAY,GAC1B;AACA,aAAW,UAAU,SAAS;AAC5B,QAAI,MAAM,MAAM,EAAG;AAEnB,QAAI,CAAC,QAAQ,OAAO,UAAU,GAAG;AAC/B,aAAO,OAAO;AACd,aAAO,OAAO;AACd,aAAO,OAAO;AACd,6BAAuB,MAAM,OAAO,OAAO,OAAO,UAAU,GAAG,OAAO;AACtE,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,UAAU,GAAG;AAC5D,YAAI,OAAO,KAAK,KAAK,kBAAkB,KAAK,GAAG;AAC7C,gBAAM,YAAY,OAAO,UAAU,GAAG;AACtC,iBAAO,OAAO,UAAU,GAAG;AAAA,QAC7B;AAAA,MACF;AACA,aAAO,OAAO;AAAA,IAChB;AAEA,QAAI,CAAC,QAAQ,OAAO,cAAc,CAAC,GAAG;AACpC;AAAA,QACE;AAAA,QACA,OAAO,OAAO,OAAO,cAAc,CAAC;AAAA,QACpC;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,QAAQ,OAAO,KAAK,GAAG;AAC1B,aAAO,OAAO;AACd,aAAO,OAAO;AACd,aAAO,OAAO;AACd,6BAAuB,MAAM,CAAC,OAAO,KAAK,GAAG,OAAO;AACpD,YAAM,QAAQ,WAAyB,MAAM,OAAO,KAAK;AACzD,UAAI,MAAM,QAAQ,MAAM,OAAO,GAAG;AAChC,eAAO,YAAY,gBAAgB,MAAM,OAAO;AAAA,MAClD;AACA,aAAO,MAAM;AAAA,IACf;AAEA,QAAI,CAAC,QAAQ,OAAO,KAAK,KAAK,CAAC,QAAQ,OAAO,KAAK,GAAG;AACpD,aAAO,OAAO;AAAA,IAChB;AAEA,QAAI,QAAQ,OAAO,IAAI,GAAG;AACxB,aAAO,OAAO;AAAA,IAChB;AAEA,QAAI,CAAC,QAAQ,OAAO,IAAI,GAAG;AACzB,UAAI,OAAO,KAAK,WAAW,GAAG;AAC5B,eAAO,QAAQ,OAAO,KAAK,CAAC;AAC5B,eAAO,OAAO;AAAA,MAChB,OAAO;AACL,cAAM,YAAY,oBAAI,IAAY;AAClC,cAAM,aAAa,CAAC;AACpB,mBAAW,SAAS,OAAO,MAAM;AAC/B,gBAAM,iBAAiB,WAAW,UAAU,WAAW,KAAK,CAAC,CAAC;AAC9D,cAAI,CAAC,UAAU,IAAI,cAAc,GAAG;AAClC,sBAAU,IAAI,cAAc;AAC5B,uBAAW,KAAK,KAAK;AAAA,UACvB;AAAA,QACF;AACA,eAAO,OAAO;AAAA,MAChB;AACA,aAAO,OAAO;AAAA,IAChB;AAEA,QAAI,OAAO,UAAU,QAAW;AAC9B,aAAO,UAAU,OAAO;AAAA,IAC1B;AAEA,QAAI,CAAC,QAAQ,OAAO,KAAK,GAAG;AAC1B,YAAMA,WAAU,OAAO;AACvB,YAAM,WAAWA,SAAQ;AAAA,QAAI,CAAC,SAC5B,WAAyB,MAAM,IAAI;AAAA,MACrC;AACA,YAAM,aAAa,SAAS,KAAK,CAAC,SAAS,KAAK,SAAS,QAAQ;AACjE,YAAM,gBAAgB,SAAS;AAAA,QAC7B,CAAC,SAAS,KAAK,QAAQ,KAAK,SAAS;AAAA,MACvC;AACA,UAAI,cAAc,eAAe;AAC/B,eAAO,OAAO,yBAAyB;AAAA,MACzC;AACA;AAAA,QACE;AAAA,QACA,GAAG,SAAS,IAAI,CAAC,gBAAgB,UAAU;AACzC,gBAAM,eAAeA,SAAQ,KAAK;AAClC,cAAI,MAAM,YAAY,GAAG;AACvB,gBAAI,QAAQ,IAAI,aAAa,IAAI,GAAG;AAClC,oBAAM,IAAI;AAAA,gBACR,sCAAsC;AAAA,kBACpC,GAAG;AAAA,kBACH,aAAa;AAAA,gBACf,EAAE,KAAK,MAAM,CAAC;AAAA,cAChB;AAAA,YACF;AACA;AAAA,cACE;AAAA,cACA,CAAC,cAAc;AAAA,cACf,IAAI,IAAI,OAAO,EAAE,IAAI,aAAa,IAAI;AAAA,YACxC;AAAA,UACF,OAAO;AACL,mCAAuB,MAAM,CAAC,cAAc,GAAG,OAAO;AAAA,UACxD;AACA,iBAAO;AAAA,QACT,CAAC;AAAA,MACH;AACA,aAAO,OAAO;AAAA,IAChB,OAAO;AACL,aAAO,OAAO;AAAA,IAChB;AAEA,QACE,OAAO,SAAS,YAChB,QAAQ,OAAO,UAAU,KACzB,OAAO,OAAO,yBAAyB,YACvC,CAAC,QAAQ,OAAO,oBAAoB,KACpC,OAAO,OAAO,oBAAoB,KAClC,CAAC,QAAQ,OAAO,qBAAqB,UAAU,GAC/C;AACA;AAAA,QACE;AAAA,QACA,OAAO,OAAO,OAAO,qBAAqB,UAAU;AAAA,QACpD;AAAA,MACF;AAAA,IACF;AAEA,eAAW,QAAQ,CAAC,SAAS,OAAO,GAAY;AAC9C,UAAI,CAAC,QAAQ,OAAO,IAAI,CAAC,GAAG;AAC1B,eAAO,OAAO;AACd,+BAAuB,MAAM,OAAO,IAAI,GAAG,OAAO;AAClD,YAAI,QAAQ,OAAO,IAAI,CAAC,GAAG;AACzB;AAAA,QACF;AAEA,YAAI,kBAAkB;AACtB,cAAM,aAAuB,CAAC;AAC9B,iBAAS,QAAQ,GAAG,QAAQ,OAAO,IAAI,EAAE,QAAQ,SAAS;AACxD,gBAAM,OAAO,OAAO,IAAI,EAAE,KAAK;AAC/B,cAAI,OAAO,IAAI,KAAK,KAAK,SAAS,UAAU;AAC1C,gBAAI,KAAK,QAAQ,KAAK,KAAK,SAAS,GAAG;AACrC,yBAAW,KAAK,GAAG,KAAK,IAAI;AAC5B,kBAAI,oBAAoB,IAAI;AAC1B,kCAAkB;AAAA,cACpB;AAAA,YACF;AAAA,UACF;AAAA,QACF;AACA,YAAI,oBAAoB,IAAI;AAC1B,gBAAM,aAAa,OAAO,IAAI,EAAE,eAAe;AAC/C,cAAI,OAAO,UAAU,GAAG;AACtB,uBAAW,OAAO,KAAK,UAAU;AAAA,UACnC;AACA,iBAAO,IAAI,IAAI,OAAO,IAAI,EAAE;AAAA,YAC1B,CAAC,MAAM,UAAU,UAAU,mBAAmB,MAAM,IAAI;AAAA,UAC1D;AAAA,QACF;AACA,cAAM,aAAa,OAAO,IAAI,EAAE;AAAA,UAC9B,CAAC,SAAS,WAAyB,MAAM,IAAI,EAAE,SAAS;AAAA,QAC1D;AACA,YAAI,WAAW,WAAW,GAAG;AAC3B,iBAAO,OAAO,QAAQ,WAAW,CAAC,CAAC;AACnC,iBAAO,OAAO,IAAI;AAClB;AAAA,QACF;AAEA,eAAO,YAAY,IAAI,aAAa,MAAM,OAAO,IAAI,CAAC;AAAA,MACxD,OAAO;AACL,eAAO,OAAO,IAAI;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AACF;AAEO,SAAS,mBAAqC;AACnD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,QAAQ,EAAE,KAAK,GAAG;AAChB,6BAAuB,MAAM,OAAO,OAAO,KAAK,WAAW,OAAO,CAAC;AAAA,IACrE;AAAA,EACF;AACF;",
|
|
6
|
+
"names": ["schemas"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sdk-it/spec",
|
|
3
|
-
"version": "0.46.
|
|
3
|
+
"version": "0.46.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"!**/*.test.*"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@sdk-it/core": "0.46.
|
|
30
|
+
"@sdk-it/core": "0.46.2",
|
|
31
31
|
"openapi3-ts": "4.5.0",
|
|
32
32
|
"pluralize": "^8.0.0",
|
|
33
33
|
"stringcase": "^4.3.1",
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { OperationObject, ParameterObject, SchemaObject, SecurityRequirementObject } from 'openapi3-ts/oas31';
|
|
2
|
-
import type { IR, OurRequestBodyObject } from './types.js';
|
|
3
|
-
export declare function patchParameters(spec: IR, schema: SchemaObject, parameters: ParameterObject[], security: SecurityRequirementObject[]): void;
|
|
4
|
-
export declare function tuneRequestBody(spec: IR, operationId: string, operation: OperationObject, parameters: ParameterObject[], security: SecurityRequirementObject[]): OurRequestBodyObject;
|
|
5
|
-
//# sourceMappingURL=tune-request-body.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tune-request-body.d.ts","sourceRoot":"","sources":["../../src/lib/tune-request-body.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EAEf,YAAY,EACZ,yBAAyB,EAC1B,MAAM,mBAAmB,CAAC;AAO3B,OAAO,KAAK,EAAE,EAAE,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAE3D,wBAAgB,eAAe,CAC7B,IAAI,EAAE,EAAE,EACR,MAAM,EAAE,YAAY,EACpB,UAAU,EAAE,eAAe,EAAE,EAC7B,QAAQ,EAAE,yBAAyB,EAAE,QAiCtC;AAED,wBAAgB,eAAe,CAC7B,IAAI,EAAE,EAAE,EACR,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,eAAe,EAC1B,UAAU,EAAE,eAAe,EAAE,EAC7B,QAAQ,EAAE,yBAAyB,EAAE,GACpC,oBAAoB,CAuEtB"}
|