Skip to content

Commit bf009b7

Browse files
authored
feat: export operations interface (#353)
1 parent 8c7c1d8 commit bf009b7

File tree

8 files changed

+42672
-41503
lines changed

8 files changed

+42672
-41503
lines changed

src/types/OpenAPI3.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export interface OpenAPI3Paths {
1515
}
1616

1717
export interface OpenAPI3Operation {
18+
operationId?: string;
1819
description?: string;
1920
parameters?: Parameter[];
2021
requestBody?: OpenAPI3RequestBody;
@@ -57,6 +58,9 @@ export interface OpenAPI3 {
5758
openapi: string;
5859
paths?: OpenAPI3Paths; // technically required by spec, but this library tries to be lenient
5960
components?: OpenAPI3Components;
61+
operations?: {
62+
[key: string]: OpenAPI3Operation;
63+
};
6064
[key: string]: any; // handle other properties beyond this library’s concern
6165
}
6266

src/v3.ts

Lines changed: 66 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ export default function generateTypesV3(
5050
}
5151
}
5252

53+
const operations: Record<string, OpenAPI3Operation> = {};
54+
5355
// propertyMapper
5456
const propertyMapped = options
5557
? propertyMapper(components.schemas, options.propertyMapper)
@@ -211,6 +213,52 @@ export default function generateTypesV3(
211213
return output;
212214
}
213215

216+
function transformOperation(operation: OpenAPI3Operation): string {
217+
let output = "";
218+
output += `{\n`;
219+
220+
// handle operation parameters
221+
if (operation.parameters) {
222+
output += transformParameters(operation.parameters);
223+
}
224+
225+
// handle requestBody
226+
if (operation.requestBody) {
227+
output += `requestBody: {\n`;
228+
Object.entries(operation.requestBody.content).forEach(
229+
([contentType, { schema }]) => {
230+
output += `"${contentType}": ${transform(schema)};\n`;
231+
}
232+
);
233+
output += `}\n`;
234+
}
235+
236+
// handle responses
237+
output += `responses: {\n`;
238+
Object.entries(operation.responses).forEach(([statusCode, response]) => {
239+
if (response.description) output += comment(response.description);
240+
if (!response.content || !Object.keys(response.content).length) {
241+
const type =
242+
statusCode === "204" || Math.floor(+statusCode / 100) === 3
243+
? "never"
244+
: "unknown";
245+
output += `"${statusCode}": ${type};\n`;
246+
return;
247+
}
248+
output += `"${statusCode}": {\n`;
249+
Object.entries(response.content).forEach(
250+
([contentType, encodedResponse]) => {
251+
output += `"${contentType}": ${transform(encodedResponse.schema)};\n`;
252+
}
253+
);
254+
output += `}\n`;
255+
});
256+
output += `}\n`;
257+
output += `}\n`;
258+
259+
return output;
260+
}
261+
214262
function transformPaths(paths: OpenAPI3Paths): string {
215263
let output = "";
216264
Object.entries(paths).forEach(([path, methods]) => {
@@ -220,51 +268,16 @@ export default function generateTypesV3(
220268
// skip the parameters "method" for shared parameters - we'll handle it later
221269
if (method !== "parameters") {
222270
operation = operation as OpenAPI3Operation;
223-
if (operation.description) output += comment(operation.description);
224-
output += `"${method}": {\n`;
225-
226-
// handle operation parameters
227-
if (operation.parameters) {
228-
output += transformParameters(operation.parameters);
229-
}
230271

231-
// handle requestBody
232-
if (operation.requestBody) {
233-
output += `requestBody: {\n`;
234-
Object.entries(operation.requestBody.content).forEach(
235-
([contentType, { schema }]) => {
236-
output += `"${contentType}": ${transform(schema)};\n`;
237-
}
238-
);
239-
output += `}\n`;
272+
if (operation.operationId) {
273+
output += `"${method}": operations["${operation.operationId}"];\n`;
274+
operations[operation.operationId] = operation;
275+
} else {
276+
if (operation.description) output += comment(operation.description);
277+
output += `"${method}": ${transformOperation(
278+
operation as OpenAPI3Operation
279+
)}`;
240280
}
241-
242-
// handle responses
243-
output += `responses: {\n`;
244-
Object.entries(operation.responses).forEach(
245-
([statusCode, response]) => {
246-
if (response.description) output += comment(response.description);
247-
if (!response.content || !Object.keys(response.content).length) {
248-
const type =
249-
statusCode === "204" || Math.floor(+statusCode / 100) === 3
250-
? "never"
251-
: "unknown";
252-
output += `"${statusCode}": ${type};\n`;
253-
return;
254-
}
255-
output += `"${statusCode}": {\n`;
256-
Object.entries(response.content).forEach(
257-
([contentType, encodedResponse]) => {
258-
output += `"${contentType}": ${transform(
259-
encodedResponse.schema
260-
)};\n`;
261-
}
262-
);
263-
output += `}\n`;
264-
}
265-
);
266-
output += `}\n`;
267-
output += `}\n`;
268281
}
269282
});
270283

@@ -295,6 +308,16 @@ export default function generateTypesV3(
295308
`;
296309
}
297310

311+
finalOutput += "export interface operations {\n";
312+
for (const [operationId, operation] of Object.entries(operations)) {
313+
if (operation.description) finalOutput += comment(operation.description);
314+
finalOutput += `"${operationId}": ${transformOperation(
315+
operation as OpenAPI3Operation
316+
)}`;
317+
}
318+
// close operations wrapper
319+
finalOutput += "\n}\n\n";
320+
298321
finalOutput += "export interface components {\n";
299322

300323
if (components.parameters && Object.keys(components.parameters).length) {

0 commit comments

Comments
 (0)