@sdk-it/spec 0.39.0 → 0.41.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.
package/dist/lib/is.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export declare function isStreamingContentType(contentType: string | null | undefined): boolean;
|
|
2
|
+
export declare function isBinaryContentType(contentType: string | null | undefined): boolean;
|
|
2
3
|
export declare function isSuccessStatusCode(statusCode: number | string): boolean;
|
|
3
4
|
export declare function isErrorStatusCode(statusCode: number | string): boolean;
|
|
4
5
|
export declare function parseJsonContentType(contentType: string | null | undefined): string | null;
|
package/dist/lib/is.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"is.d.ts","sourceRoot":"","sources":["../../src/lib/is.ts"],"names":[],"mappings":"AAAA,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACrC,OAAO,CAET;AAED,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAQxE;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CActE;AAED,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,iBAuB1E;AAED,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACrC,OAAO,CAiBT;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACrC,OAAO,CAoBT"}
|
|
1
|
+
{"version":3,"file":"is.d.ts","sourceRoot":"","sources":["../../src/lib/is.ts"],"names":[],"mappings":"AAAA,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACrC,OAAO,CAET;AAED,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACrC,OAAO,CAoET;AAED,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAQxE;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CActE;AAED,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,iBAuB1E;AAED,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACrC,OAAO,CAiBT;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACrC,OAAO,CAoBT"}
|
package/dist/lib/is.js
CHANGED
|
@@ -1,6 +1,66 @@
|
|
|
1
1
|
function isStreamingContentType(contentType) {
|
|
2
2
|
return contentType === "application/octet-stream";
|
|
3
3
|
}
|
|
4
|
+
function isBinaryContentType(contentType) {
|
|
5
|
+
if (!contentType) {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
let mainType = contentType.trim();
|
|
9
|
+
const semicolonIndex = mainType.indexOf(";");
|
|
10
|
+
if (semicolonIndex !== -1) {
|
|
11
|
+
mainType = mainType.substring(0, semicolonIndex).trim();
|
|
12
|
+
}
|
|
13
|
+
mainType = mainType.toLowerCase();
|
|
14
|
+
if (mainType.startsWith("text/")) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
if (mainType.endsWith("/json") || mainType.endsWith("+json")) {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
if (mainType.endsWith("/xml") || mainType.endsWith("+xml")) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
if (mainType === "application/xml" || mainType === "text/xml") {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
if (mainType === "application/x-www-form-urlencoded" || mainType === "multipart/form-data") {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
if (mainType.startsWith("image/")) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
if (mainType.startsWith("audio/")) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
if (mainType.startsWith("video/")) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
if (mainType === "application/pdf") {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
if (mainType === "application/zip") {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
if (mainType === "application/gzip") {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
if (mainType === "application/x-7z-compressed") {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
if (mainType === "application/x-tar") {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
if (mainType.startsWith("application/vnd.openxmlformats-officedocument.")) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
if (mainType.startsWith("application/vnd.ms-")) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
if (mainType === "application/msword") {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
4
64
|
function isSuccessStatusCode(statusCode) {
|
|
5
65
|
if (typeof statusCode === "string") {
|
|
6
66
|
const statusGroup = +statusCode.slice(0, 1);
|
|
@@ -61,6 +121,7 @@ function isSseContentType(contentType) {
|
|
|
61
121
|
return mainType === "text/event-stream";
|
|
62
122
|
}
|
|
63
123
|
export {
|
|
124
|
+
isBinaryContentType,
|
|
64
125
|
isErrorStatusCode,
|
|
65
126
|
isSseContentType,
|
|
66
127
|
isStreamingContentType,
|
package/dist/lib/is.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/is.ts"],
|
|
4
|
-
"sourcesContent": ["export function isStreamingContentType(\n contentType: string | null | undefined,\n): boolean {\n return contentType === 'application/octet-stream';\n}\n\nexport function isSuccessStatusCode(statusCode: number | string): boolean {\n if (typeof statusCode === 'string') {\n const statusGroup = +statusCode.slice(0, 1);\n const status = Number(statusCode);\n return (status >= 200 && status < 300) || (status >= 2 && statusGroup <= 3);\n }\n statusCode = Number(statusCode);\n return statusCode >= 200 && statusCode < 300;\n}\n\nexport function isErrorStatusCode(statusCode: number | string): boolean {\n if (typeof statusCode === 'string') {\n const statusGroup = +statusCode.slice(0, 1);\n const status = Number(statusCode);\n return (\n status < 200 ||\n status >= 300 ||\n statusGroup >= 4 ||\n statusGroup === 0 ||\n statusGroup === 1\n );\n }\n statusCode = Number(statusCode);\n return statusCode < 200 || statusCode >= 300;\n}\n\nexport function parseJsonContentType(contentType: string | null | undefined) {\n if (!contentType) {\n return null;\n }\n\n // 1. Trim whitespace\n let mainType = contentType.trim();\n\n // 2. Remove parameters (anything after the first ';')\n const semicolonIndex = mainType.indexOf(';');\n if (semicolonIndex !== -1) {\n mainType = mainType.substring(0, semicolonIndex).trim(); // Trim potential space before ';'\n }\n\n // 3. Convert to lowercase for case-insensitive comparison\n mainType = mainType.toLowerCase();\n\n if (mainType.endsWith('/json')) {\n return mainType.split('/')[1];\n } else if (mainType.endsWith('+json')) {\n return mainType.split('+')[1];\n }\n return null;\n}\n\nexport function isTextContentType(\n contentType: string | null | undefined,\n): boolean {\n if (!contentType) {\n return false; // Handle null, undefined, or empty string\n }\n\n // 1. Trim whitespace from the input string\n let mainType = contentType.trim();\n // 2. Find the position of the first semicolon (if any) to remove parameters\n const semicolonIndex = mainType.indexOf(';');\n if (semicolonIndex !== -1) {\n // Extract the part before the semicolon and trim potential space\n mainType = mainType.substring(0, semicolonIndex).trim();\n }\n // 3. Convert the main type part to lowercase for case-insensitive comparison\n mainType = mainType.toLowerCase();\n // 4. Compare against the standard text MIME types\n return mainType.startsWith('text/'); // Catch-all for other text/* types\n}\n\n/**\n * Checks if a given content type string represents Server-Sent Events (SSE).\n * Handles case-insensitivity, parameters (like charset), and leading/trailing whitespace.\n *\n * @param contentType The content type string to check (e.g., from a Content-Type header).\n * @returns True if the content type is 'text/event-stream', false otherwise.\n */\nexport function isSseContentType(\n contentType: string | null | undefined,\n): boolean {\n if (!contentType) {\n return false; // Handle null, undefined, or empty string\n }\n\n // 1. Trim whitespace from the input string\n let mainType = contentType.trim();\n\n // 2. Find the position of the first semicolon (if any) to remove parameters\n const semicolonIndex = mainType.indexOf(';');\n if (semicolonIndex !== -1) {\n // Extract the part before the semicolon and trim potential space\n mainType = mainType.substring(0, semicolonIndex).trim();\n }\n\n // 3. Convert the main type part to lowercase for case-insensitive comparison\n mainType = mainType.toLowerCase();\n\n // 4. Compare against the standard SSE MIME type\n return mainType === 'text/event-stream';\n}\n"],
|
|
5
|
-
"mappings": "AAAO,SAAS,uBACd,aACS;AACT,SAAO,gBAAgB;AACzB;AAEO,SAAS,oBAAoB,YAAsC;AACxE,MAAI,OAAO,eAAe,UAAU;AAClC,UAAM,cAAc,CAAC,WAAW,MAAM,GAAG,CAAC;AAC1C,UAAM,SAAS,OAAO,UAAU;AAChC,WAAQ,UAAU,OAAO,SAAS,OAAS,UAAU,KAAK,eAAe;AAAA,EAC3E;AACA,eAAa,OAAO,UAAU;AAC9B,SAAO,cAAc,OAAO,aAAa;AAC3C;AAEO,SAAS,kBAAkB,YAAsC;AACtE,MAAI,OAAO,eAAe,UAAU;AAClC,UAAM,cAAc,CAAC,WAAW,MAAM,GAAG,CAAC;AAC1C,UAAM,SAAS,OAAO,UAAU;AAChC,WACE,SAAS,OACT,UAAU,OACV,eAAe,KACf,gBAAgB,KAChB,gBAAgB;AAAA,EAEpB;AACA,eAAa,OAAO,UAAU;AAC9B,SAAO,aAAa,OAAO,cAAc;AAC3C;AAEO,SAAS,qBAAqB,aAAwC;AAC3E,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,EACT;AAGA,MAAI,WAAW,YAAY,KAAK;AAGhC,QAAM,iBAAiB,SAAS,QAAQ,GAAG;AAC3C,MAAI,mBAAmB,IAAI;AACzB,eAAW,SAAS,UAAU,GAAG,cAAc,EAAE,KAAK;AAAA,EACxD;AAGA,aAAW,SAAS,YAAY;AAEhC,MAAI,SAAS,SAAS,OAAO,GAAG;AAC9B,WAAO,SAAS,MAAM,GAAG,EAAE,CAAC;AAAA,EAC9B,WAAW,SAAS,SAAS,OAAO,GAAG;AACrC,WAAO,SAAS,MAAM,GAAG,EAAE,CAAC;AAAA,EAC9B;AACA,SAAO;AACT;AAEO,SAAS,kBACd,aACS;AACT,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,EACT;AAGA,MAAI,WAAW,YAAY,KAAK;AAEhC,QAAM,iBAAiB,SAAS,QAAQ,GAAG;AAC3C,MAAI,mBAAmB,IAAI;AAEzB,eAAW,SAAS,UAAU,GAAG,cAAc,EAAE,KAAK;AAAA,EACxD;AAEA,aAAW,SAAS,YAAY;AAEhC,SAAO,SAAS,WAAW,OAAO;AACpC;AASO,SAAS,iBACd,aACS;AACT,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,EACT;AAGA,MAAI,WAAW,YAAY,KAAK;AAGhC,QAAM,iBAAiB,SAAS,QAAQ,GAAG;AAC3C,MAAI,mBAAmB,IAAI;AAEzB,eAAW,SAAS,UAAU,GAAG,cAAc,EAAE,KAAK;AAAA,EACxD;AAGA,aAAW,SAAS,YAAY;AAGhC,SAAO,aAAa;AACtB;",
|
|
4
|
+
"sourcesContent": ["export function isStreamingContentType(\n contentType: string | null | undefined,\n): boolean {\n return contentType === 'application/octet-stream';\n}\n\nexport function isBinaryContentType(\n contentType: string | null | undefined,\n): boolean {\n if (!contentType) {\n return false;\n }\n\n let mainType = contentType.trim();\n const semicolonIndex = mainType.indexOf(';');\n if (semicolonIndex !== -1) {\n mainType = mainType.substring(0, semicolonIndex).trim();\n }\n mainType = mainType.toLowerCase();\n\n if (mainType.startsWith('text/')) {\n return false;\n }\n if (mainType.endsWith('/json') || mainType.endsWith('+json')) {\n return false;\n }\n if (mainType.endsWith('/xml') || mainType.endsWith('+xml')) {\n return false;\n }\n if (mainType === 'application/xml' || mainType === 'text/xml') {\n return false;\n }\n if (\n mainType === 'application/x-www-form-urlencoded' ||\n mainType === 'multipart/form-data'\n ) {\n return false;\n }\n\n if (mainType.startsWith('image/')) {\n return true;\n }\n if (mainType.startsWith('audio/')) {\n return true;\n }\n if (mainType.startsWith('video/')) {\n return true;\n }\n if (mainType === 'application/pdf') {\n return true;\n }\n if (mainType === 'application/zip') {\n return true;\n }\n if (mainType === 'application/gzip') {\n return true;\n }\n if (mainType === 'application/x-7z-compressed') {\n return true;\n }\n if (mainType === 'application/x-tar') {\n return true;\n }\n if (\n mainType.startsWith('application/vnd.openxmlformats-officedocument.')\n ) {\n return true;\n }\n if (mainType.startsWith('application/vnd.ms-')) {\n return true;\n }\n if (mainType === 'application/msword') {\n return true;\n }\n\n return false;\n}\n\nexport function isSuccessStatusCode(statusCode: number | string): boolean {\n if (typeof statusCode === 'string') {\n const statusGroup = +statusCode.slice(0, 1);\n const status = Number(statusCode);\n return (status >= 200 && status < 300) || (status >= 2 && statusGroup <= 3);\n }\n statusCode = Number(statusCode);\n return statusCode >= 200 && statusCode < 300;\n}\n\nexport function isErrorStatusCode(statusCode: number | string): boolean {\n if (typeof statusCode === 'string') {\n const statusGroup = +statusCode.slice(0, 1);\n const status = Number(statusCode);\n return (\n status < 200 ||\n status >= 300 ||\n statusGroup >= 4 ||\n statusGroup === 0 ||\n statusGroup === 1\n );\n }\n statusCode = Number(statusCode);\n return statusCode < 200 || statusCode >= 300;\n}\n\nexport function parseJsonContentType(contentType: string | null | undefined) {\n if (!contentType) {\n return null;\n }\n\n // 1. Trim whitespace\n let mainType = contentType.trim();\n\n // 2. Remove parameters (anything after the first ';')\n const semicolonIndex = mainType.indexOf(';');\n if (semicolonIndex !== -1) {\n mainType = mainType.substring(0, semicolonIndex).trim(); // Trim potential space before ';'\n }\n\n // 3. Convert to lowercase for case-insensitive comparison\n mainType = mainType.toLowerCase();\n\n if (mainType.endsWith('/json')) {\n return mainType.split('/')[1];\n } else if (mainType.endsWith('+json')) {\n return mainType.split('+')[1];\n }\n return null;\n}\n\nexport function isTextContentType(\n contentType: string | null | undefined,\n): boolean {\n if (!contentType) {\n return false; // Handle null, undefined, or empty string\n }\n\n // 1. Trim whitespace from the input string\n let mainType = contentType.trim();\n // 2. Find the position of the first semicolon (if any) to remove parameters\n const semicolonIndex = mainType.indexOf(';');\n if (semicolonIndex !== -1) {\n // Extract the part before the semicolon and trim potential space\n mainType = mainType.substring(0, semicolonIndex).trim();\n }\n // 3. Convert the main type part to lowercase for case-insensitive comparison\n mainType = mainType.toLowerCase();\n // 4. Compare against the standard text MIME types\n return mainType.startsWith('text/'); // Catch-all for other text/* types\n}\n\n/**\n * Checks if a given content type string represents Server-Sent Events (SSE).\n * Handles case-insensitivity, parameters (like charset), and leading/trailing whitespace.\n *\n * @param contentType The content type string to check (e.g., from a Content-Type header).\n * @returns True if the content type is 'text/event-stream', false otherwise.\n */\nexport function isSseContentType(\n contentType: string | null | undefined,\n): boolean {\n if (!contentType) {\n return false; // Handle null, undefined, or empty string\n }\n\n // 1. Trim whitespace from the input string\n let mainType = contentType.trim();\n\n // 2. Find the position of the first semicolon (if any) to remove parameters\n const semicolonIndex = mainType.indexOf(';');\n if (semicolonIndex !== -1) {\n // Extract the part before the semicolon and trim potential space\n mainType = mainType.substring(0, semicolonIndex).trim();\n }\n\n // 3. Convert the main type part to lowercase for case-insensitive comparison\n mainType = mainType.toLowerCase();\n\n // 4. Compare against the standard SSE MIME type\n return mainType === 'text/event-stream';\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tune-response.d.ts","sourceRoot":"","sources":["../../src/lib/tune-response.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tune-response.d.ts","sourceRoot":"","sources":["../../src/lib/tune-response.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,eAAe,EAEhB,MAAM,mBAAmB,CAAC;AAc3B,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAErC,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,EAAE,EACR,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,eAAe,EAC1B,eAAe,CAAC,EAAE,eAAe,+CAuIlC"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import { parse as parseContentType } from "fast-content-type-parse";
|
|
1
2
|
import { isRef, parseRef, resolveRef } from "@sdk-it/core/ref.js";
|
|
2
3
|
import { isEmpty, pascalcase } from "@sdk-it/core/utils.js";
|
|
3
4
|
import { findUniqueSchemaName } from "./find-unique-schema-name.js";
|
|
4
5
|
import {
|
|
6
|
+
isBinaryContentType,
|
|
5
7
|
isSseContentType,
|
|
8
|
+
isStreamingContentType,
|
|
6
9
|
isSuccessStatusCode,
|
|
7
10
|
isTextContentType,
|
|
8
11
|
parseJsonContentType
|
|
@@ -67,9 +70,14 @@ function resolveResponses(spec, operationId, operation, responsesConfig) {
|
|
|
67
70
|
response["x-response-name"] = model;
|
|
68
71
|
continue;
|
|
69
72
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
const isSse = isSseContentType(contentType);
|
|
74
|
+
const normalizedContentType = normalizeContentType(contentType);
|
|
75
|
+
const hasContentDisposition = hasHeader(
|
|
76
|
+
response.headers,
|
|
77
|
+
"Content-Disposition"
|
|
78
|
+
);
|
|
79
|
+
const isBinary = isBinaryContentType(contentType) || isStreamingContentType(normalizedContentType) && hasContentDisposition;
|
|
80
|
+
const isText = isTextContentType(contentType);
|
|
73
81
|
if (parseJsonContentType(contentType)) {
|
|
74
82
|
if (isEmpty(mediaType.schema)) {
|
|
75
83
|
spec.components.schemas[outputName] = {
|
|
@@ -78,9 +86,16 @@ function resolveResponses(spec, operationId, operation, responsesConfig) {
|
|
|
78
86
|
};
|
|
79
87
|
}
|
|
80
88
|
} else {
|
|
89
|
+
if (isEmpty(mediaType.schema) && (isText || isBinary)) {
|
|
90
|
+
mediaType.schema = {
|
|
91
|
+
type: "string",
|
|
92
|
+
...isBinary ? { format: "binary" } : {}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
81
95
|
spec.components.schemas[outputName] = {
|
|
82
96
|
...spec.components.schemas[outputName],
|
|
83
|
-
"x-stream": !
|
|
97
|
+
"x-stream": isSse || !isText && !isBinary,
|
|
98
|
+
...isSse ? { "x-sse": true } : {}
|
|
84
99
|
};
|
|
85
100
|
}
|
|
86
101
|
spec.components.schemas[outputName] = {
|
|
@@ -96,6 +111,20 @@ function resolveResponses(spec, operationId, operation, responsesConfig) {
|
|
|
96
111
|
}
|
|
97
112
|
return operation.responses;
|
|
98
113
|
}
|
|
114
|
+
function normalizeContentType(contentType) {
|
|
115
|
+
try {
|
|
116
|
+
return parseContentType(contentType)?.type?.toLowerCase();
|
|
117
|
+
} catch {
|
|
118
|
+
return contentType.split(";")[0]?.trim().toLowerCase();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function hasHeader(headers, name) {
|
|
122
|
+
if (!headers) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
const target = name.toLowerCase();
|
|
126
|
+
return Object.keys(headers).some((key) => key.toLowerCase() === target);
|
|
127
|
+
}
|
|
99
128
|
export {
|
|
100
129
|
resolveResponses
|
|
101
130
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/tune-response.ts"],
|
|
4
|
-
"sourcesContent": ["import 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 {\n isSseContentType,\n isSuccessStatusCode,\n isTextContentType,\n parseJsonContentType,\n} from './is.js';\nimport { type ResponsesConfig } from './options.js';\nimport type { IR } from './types.js';\n\nexport function resolveResponses(\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 if (status === 'default') {\n delete responses[status]; // Skip default response\n continue;\n }\n // use structuredClone to avoid mutating a response object\n // that is referenced by multiple operations\n operation.responses[status] = structuredClone(\n resolveRef<ResponseObject>(spec, responses[status]),\n );\n\n if (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 const outputName =\n statusCode !== 200\n ? pascalcase(operationId) + status\n : findUniqueSchemaName(spec, operationId, [\n 'output',\n 'payload',\n 'result',\n ]);\n\n if (!responsesConfig?.flattenErrorResponses) {\n if (!isSuccessStatusCode(status)) {\n continue;\n }\n }\n\n if (isEmpty(response.content)) {\n response.content = {\n 'application/octet-stream': {},\n };\n }\n\n response['x-response-name'] = outputName;\n\n // if (isErrorStatusCode(status)) {\n // const mediaType = response.content?.['application/json'];\n // if (mediaType && isRef(mediaType.schema)) {\n // const { model } = parseRef(mediaType.schema.$ref);\n // Object.assign(config.spec.components.schemas[model], {\n // 'x-responsebody': true,\n // // do not assign response ref to a group\n // // because they are supposed to be in a separate file only inlined\n // // schemas are grouped by operationId\n // });\n // response['x-response-name'] = model;\n // }\n // continue;\n // }\n\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 // do not assign response ref to a group\n // because they are supposed to be in a separate file only inlined\n // schemas are grouped by operationId\n });\n response['x-response-name'] = model;\n continue;\n }\n
|
|
5
|
-
"mappings": "
|
|
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 {\n isBinaryContentType,\n isSseContentType,\n isStreamingContentType,\n isSuccessStatusCode,\n isTextContentType,\n parseJsonContentType,\n} from './is.js';\nimport { type ResponsesConfig } from './options.js';\nimport type { IR } from './types.js';\n\nexport function resolveResponses(\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 if (status === 'default') {\n delete responses[status]; // Skip default response\n continue;\n }\n // use structuredClone to avoid mutating a response object\n // that is referenced by multiple operations\n operation.responses[status] = structuredClone(\n resolveRef<ResponseObject>(spec, responses[status]),\n );\n\n if (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 const outputName =\n statusCode !== 200\n ? pascalcase(operationId) + status\n : findUniqueSchemaName(spec, operationId, [\n 'output',\n 'payload',\n 'result',\n ]);\n\n if (!responsesConfig?.flattenErrorResponses) {\n if (!isSuccessStatusCode(status)) {\n continue;\n }\n }\n\n if (isEmpty(response.content)) {\n response.content = {\n 'application/octet-stream': {},\n };\n }\n\n response['x-response-name'] = outputName;\n\n // if (isErrorStatusCode(status)) {\n // const mediaType = response.content?.['application/json'];\n // if (mediaType && isRef(mediaType.schema)) {\n // const { model } = parseRef(mediaType.schema.$ref);\n // Object.assign(config.spec.components.schemas[model], {\n // 'x-responsebody': true,\n // // do not assign response ref to a group\n // // because they are supposed to be in a separate file only inlined\n // // schemas are grouped by operationId\n // });\n // response['x-response-name'] = model;\n // }\n // continue;\n // }\n\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 // do not assign response ref to a group\n // because they are supposed to be in a separate file only inlined\n // schemas are grouped by operationId\n });\n response['x-response-name'] = model;\n continue;\n }\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 // add \"additionalProperties\" because we're certain this is a response body is of json type\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 }\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"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sdk-it/spec",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.41.0",
|
|
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.
|
|
30
|
+
"@sdk-it/core": "0.41.0",
|
|
31
31
|
"openapi3-ts": "4.5.0",
|
|
32
32
|
"pluralize": "^8.0.0",
|
|
33
33
|
"stringcase": "^4.3.1",
|