|
1 | 1 | import propertyMapper from "./property-mapper";
|
2 | 2 | import {
|
3 | 3 | OpenAPI3,
|
4 |
| - OpenAPI3Components, |
| 4 | + OpenAPI3Parameter, |
| 5 | + OpenAPI3Paths, |
5 | 6 | OpenAPI3SchemaObject,
|
6 | 7 | OpenAPI3Schemas,
|
7 | 8 | SwaggerToTSOptions,
|
@@ -34,16 +35,14 @@ export default function generateTypesV3(
|
34 | 35 | options?: SwaggerToTSOptions
|
35 | 36 | ): string {
|
36 | 37 | const { rawSchema = false } = options || {};
|
37 |
| - let components: OpenAPI3Components; |
| 38 | + let { paths = {}, components = { schemas: {} } } = input as OpenAPI3; |
38 | 39 |
|
39 | 40 | if (rawSchema) {
|
40 | 41 | components = { schemas: input };
|
41 | 42 | } else {
|
42 |
| - components = (input as OpenAPI3).components; |
43 |
| - |
44 |
| - if (!components || !components.schemas) { |
| 43 | + if (!input.components && !input.paths) { |
45 | 44 | throw new Error(
|
46 |
| - `⛔️ 'components' missing from schema https://swagger.io/specification` |
| 45 | + `No components or paths found. Specify --raw-schema to load a raw schema.` |
47 | 46 | );
|
48 | 47 | }
|
49 | 48 | }
|
@@ -111,7 +110,7 @@ export default function generateTypesV3(
|
111 | 110 | if (Array.isArray(node.items)) {
|
112 | 111 | return tsTupleOf(node.items.map(transform));
|
113 | 112 | } else {
|
114 |
| - return tsArrayOf(transform(node.items as any)); |
| 113 | + return tsArrayOf(node.items ? transform(node.items as any) : "any"); |
115 | 114 | }
|
116 | 115 | }
|
117 | 116 | }
|
@@ -154,27 +153,107 @@ export default function generateTypesV3(
|
154 | 153 | return output;
|
155 | 154 | }
|
156 | 155 |
|
157 |
| - if (rawSchema) { |
158 |
| - const schemas = createKeys(propertyMapped, Object.keys(propertyMapped)); |
| 156 | + function transformPaths(paths: OpenAPI3Paths): string { |
| 157 | + let output = ""; |
| 158 | + Object.entries(paths).forEach(([path, methods]) => { |
| 159 | + output += `"${path}": {\n`; |
| 160 | + Object.entries(methods).forEach(([method, responses]) => { |
| 161 | + if (responses.description) output += comment(responses.description); |
| 162 | + output += `"${method}": {\n`; |
| 163 | + |
| 164 | + // handle parameters |
| 165 | + if (responses.parameters) { |
| 166 | + output += `parameters: {\n`; |
| 167 | + const allParameters: Record< |
| 168 | + string, |
| 169 | + Record<string, OpenAPI3Parameter> |
| 170 | + > = {}; |
| 171 | + responses.parameters.forEach((p) => { |
| 172 | + if (!allParameters[p.in]) allParameters[p.in] = {}; |
| 173 | + // TODO: handle $ref parameters |
| 174 | + if (p.name) { |
| 175 | + allParameters[p.in][p.name] = p; |
| 176 | + } |
| 177 | + }); |
| 178 | + |
| 179 | + Object.entries(allParameters).forEach(([loc, locParams]) => { |
| 180 | + output += `"${loc}": {\n`; |
| 181 | + Object.entries(locParams).forEach(([paramName, paramProps]) => { |
| 182 | + if (paramProps.description) |
| 183 | + output += comment(paramProps.description); |
| 184 | + output += `"${paramName}"${ |
| 185 | + paramProps.required === true ? "" : "?" |
| 186 | + }: ${transform(paramProps.schema)};\n`; |
| 187 | + }); |
| 188 | + output += `}\n`; |
| 189 | + }); |
| 190 | + output += `}\n`; |
| 191 | + } |
159 | 192 |
|
| 193 | + // handle responses |
| 194 | + output += `responses: {\n`; |
| 195 | + Object.entries(responses.responses).forEach( |
| 196 | + ([statusCode, response]) => { |
| 197 | + if (response.description) output += comment(response.description); |
| 198 | + if (!response.content || !Object.keys(response.content).length) { |
| 199 | + output += `"${statusCode}": any;\n`; |
| 200 | + return; |
| 201 | + } |
| 202 | + output += `"${statusCode}": {\n`; |
| 203 | + Object.entries(response.content).forEach( |
| 204 | + ([contentType, encodedResponse]) => { |
| 205 | + output += `"${contentType}": ${transform( |
| 206 | + encodedResponse.schema |
| 207 | + )};\n`; |
| 208 | + } |
| 209 | + ); |
| 210 | + output += `}\n`; |
| 211 | + } |
| 212 | + ); |
| 213 | + output += `}\n`; |
| 214 | + output += `}\n`; |
| 215 | + }); |
| 216 | + output += `}\n`; |
| 217 | + }); |
| 218 | + return output; |
| 219 | + } |
| 220 | + |
| 221 | + if (rawSchema) { |
160 | 222 | return `export interface schemas {
|
161 |
| - ${schemas} |
162 |
| - }`; |
| 223 | + ${createKeys(propertyMapped, Object.keys(propertyMapped))} |
| 224 | +}`; |
163 | 225 | }
|
164 | 226 |
|
165 |
| - const schemas = `schemas: { |
166 |
| - ${createKeys(propertyMapped, Object.keys(propertyMapped))} |
167 |
| - }`; |
168 |
| - |
169 |
| - const responses = !components.responses |
170 |
| - ? `` |
171 |
| - : `responses: { |
172 |
| - ${createKeys(components.responses, Object.keys(components.responses))} |
173 |
| - }`; |
174 |
| - |
175 |
| - // note: make sure that base-level schemas are required |
176 |
| - return `export interface components { |
177 |
| - ${schemas} |
178 |
| - ${responses} |
179 |
| - }`; |
| 227 | + // now put everything together |
| 228 | + let finalOutput = ""; |
| 229 | + |
| 230 | + // handle paths |
| 231 | + if (Object.keys(paths).length) { |
| 232 | + finalOutput += `export interface paths { |
| 233 | + ${transformPaths(paths)} |
| 234 | +} |
| 235 | +
|
| 236 | +`; |
| 237 | + } |
| 238 | + |
| 239 | + finalOutput += "export interface components {\n"; |
| 240 | + |
| 241 | + // TODO: handle components.parameters |
| 242 | + |
| 243 | + if (Object.keys(propertyMapped).length) { |
| 244 | + finalOutput += `schemas: { |
| 245 | + ${createKeys(propertyMapped, Object.keys(propertyMapped))} |
| 246 | +}`; |
| 247 | + } |
| 248 | + if (components.responses && Object.keys(components.responses).length) { |
| 249 | + finalOutput += ` |
| 250 | +responses: { |
| 251 | + ${createKeys(components.responses, Object.keys(components.responses))} |
| 252 | +}`; |
| 253 | + } |
| 254 | + |
| 255 | + // close components wrapper |
| 256 | + finalOutput += "\n}"; |
| 257 | + |
| 258 | + return finalOutput; |
180 | 259 | }
|
0 commit comments