@technicity/openapi-sdk-generator 2.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.
@@ -0,0 +1,763 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const path = require("path");
4
+ const fs = require("fs");
5
+ const os = require("os");
6
+ const child_process = require("child_process");
7
+ const fetch = require("node-fetch");
8
+ const json_schema_to_typescript_1 = require("json-schema-to-typescript");
9
+ const SwaggerParser = require("@apidevtools/swagger-parser");
10
+ const Ajv = require("ajv");
11
+ const toJsonSchema = require("@openapi-contrib/openapi-schema-to-json-schema");
12
+ const fse = require("fs-extra");
13
+ const traverse = require("json-schema-traverse");
14
+ const { json2ts } = require("json-ts");
15
+ const prettier = require("prettier");
16
+ const prependFile = require("prepend-file");
17
+ exports.schema = {
18
+ type: "object",
19
+ properties: {
20
+ def: {
21
+ type: "string",
22
+ description: "Path or URL to OpenAPI definition",
23
+ },
24
+ outdir: {
25
+ type: "string",
26
+ description: "Directory in which to generate files",
27
+ },
28
+ preProcessDef: {
29
+ type: "string",
30
+ description: "String for JS function to run on OpenAPI def before prior to validation and de-referencing",
31
+ },
32
+ cacheType: {
33
+ type: "string",
34
+ enum: ["memory", "none"],
35
+ default: "memory",
36
+ description: "'memory' | 'none'",
37
+ },
38
+ throwOnNotOkayRes: {
39
+ type: "boolean",
40
+ default: false,
41
+ description: "Whether a SDK method should throw when the response status code is not okay",
42
+ },
43
+ packageName: {
44
+ type: "string",
45
+ },
46
+ packageAuthor: {
47
+ type: "string",
48
+ },
49
+ packageDescription: {
50
+ type: "string",
51
+ },
52
+ module: {
53
+ type: "string",
54
+ enum: ["CommonJS", "ES2020"],
55
+ default: "CommonJS",
56
+ description: "module type for generated SDK",
57
+ },
58
+ },
59
+ additionalProperties: false,
60
+ required: ["def", "outdir"],
61
+ };
62
+ const ajv = new Ajv({ allErrors: true, useDefaults: true, coerceTypes: true });
63
+ async function generate(opts) {
64
+ const valid = ajv.validate(exports.schema, opts);
65
+ if (!valid) {
66
+ console.log(ajv.errors);
67
+ process.exit(1);
68
+ }
69
+ const isUrl = opts.def.startsWith("http://") || opts.def.startsWith("https://");
70
+ if (!isUrl && !fs.existsSync(path.resolve(opts.def))) {
71
+ throw new Error("Invalid path.");
72
+ }
73
+ let doc = isUrl
74
+ ? await fetch(opts.def, {}).then((res) => res.json())
75
+ : JSON.parse(fs.readFileSync(path.resolve(opts.def), { encoding: "utf8" }));
76
+ if (opts.preProcessDef) {
77
+ const fn = Function("doc", opts.preProcessDef);
78
+ doc = fn(doc);
79
+ }
80
+ // https://apitools.dev/swagger-parser/docs/options.html
81
+ const api = await SwaggerParser.validate(doc);
82
+ // Ignore defs without operationId
83
+ for (let [p, v1] of Object.entries(api.paths)) {
84
+ for (let [m, v2] of Object.entries(v1)) {
85
+ if (!getOperationId(v2) ||
86
+ opts.filterDef?.({ pathname: p, method: m }) === false) {
87
+ delete api.paths[p][m];
88
+ }
89
+ }
90
+ }
91
+ const optsTypeGet = "{headers?: {[k: string]: string}, strategy?: 'network'}";
92
+ const optsType = "{headers?: {[k: string]: string}, clearCache?: boolean}";
93
+ let routes = await Promise.all(Object.keys(api.paths)
94
+ .sort()
95
+ .map(async (path) => {
96
+ let output = "";
97
+ if (api.paths[path].get) {
98
+ let responseType = await createResponseBodyType(api.paths[path], "get", opts.throwOnNotOkayRes);
99
+ let queryType = await createQueryType(api.paths[path].get.parameters);
100
+ const hasUrlParameters = (api.paths[path].get.parameters || []).some((x) => x.in === "path");
101
+ let getFcn = `${getOperationId(api.paths[path].get)}(
102
+ params${hasUrlParameters ? "" : "?"}: ${createParamType(path).type},
103
+ query?: ${queryType},
104
+ opts?: ${optsTypeGet}
105
+ ) : Promise<${responseType}> {
106
+ let path = "${convertPath(path)}";
107
+ return this._get(path, params, query, opts);
108
+ };`;
109
+ output += getFcn;
110
+ }
111
+ if (api.paths[path].post) {
112
+ const method = "post";
113
+ let requestBodyType = await createRequestBodyType(api.paths[path], method);
114
+ const hasNoBody = requestBodyType.type === "undefined";
115
+ const requestBodyContentType = api.paths[path][method]?.requestBody
116
+ ? getRequestBodyContentType(api.paths[path], method)
117
+ : undefined;
118
+ let responseType = await createResponseBodyType(api.paths[path], method, opts.throwOnNotOkayRes);
119
+ // https://stackoverflow.com/a/35799817
120
+ let fcn = `${getOperationId(api.paths[path][method])}(
121
+ params: ${createParamType(path).type},
122
+ data${hasNoBody ? "?" : ""}: ${requestBodyType.type},
123
+ query?: ${await createQueryType(api.paths[path][method].parameters)},
124
+ opts?: ${optsType}
125
+ ) : Promise<${responseType}> {
126
+ let path = "${convertPath(path)}";
127
+ return this._${method}(path, params, data, query, opts, ${requestBodyContentType === undefined ||
128
+ requestBodyContentType === "multipart/form-data"
129
+ ? "undefined"
130
+ : `"${requestBodyContentType}"`});
131
+ };`;
132
+ output += fcn;
133
+ }
134
+ if (api.paths[path].patch) {
135
+ const method = "patch";
136
+ let requestBodyType = await createRequestBodyType(api.paths[path], method);
137
+ const hasNoBody = requestBodyType.type === "undefined";
138
+ const requestBodyContentType = api.paths[path][method]?.requestBody
139
+ ? getRequestBodyContentType(api.paths[path], method)
140
+ : undefined;
141
+ let responseType = await createResponseBodyType(api.paths[path], method, opts.throwOnNotOkayRes);
142
+ // https://stackoverflow.com/a/35799817
143
+ let fcn = `${getOperationId(api.paths[path][method])}(
144
+ params: ${createParamType(path).type},
145
+ data${hasNoBody ? "?" : ""}: ${requestBodyType.type},
146
+ query?: ${await createQueryType(api.paths[path][method].parameters)},
147
+ opts?: ${optsType}
148
+ ) : Promise<${responseType}> {
149
+ let path = "${convertPath(path)}";
150
+ return this._${method}(path, params, data, query, opts, ${requestBodyContentType === undefined ||
151
+ requestBodyContentType === "multipart/form-data"
152
+ ? "undefined"
153
+ : `"${requestBodyContentType}"`});
154
+ };`;
155
+ output += fcn;
156
+ }
157
+ if (api.paths[path].put) {
158
+ const method = "put";
159
+ let requestBodyType = await createRequestBodyType(api.paths[path], method);
160
+ const hasNoBody = requestBodyType.type === "undefined";
161
+ const requestBodyContentType = api.paths[path][method]?.requestBody
162
+ ? getRequestBodyContentType(api.paths[path], method)
163
+ : undefined;
164
+ let responseType = await createResponseBodyType(api.paths[path], method, opts.throwOnNotOkayRes);
165
+ // https://stackoverflow.com/a/35799817
166
+ let fcn = `${getOperationId(api.paths[path][method])}(
167
+ params: ${createParamType(path).type},
168
+ data${hasNoBody ? "?" : ""}: ${requestBodyType.type},
169
+ query?: ${await createQueryType(api.paths[path][method].parameters)},
170
+ opts?: ${optsType}
171
+ ) : Promise<${responseType}> {
172
+ let path = "${convertPath(path)}";
173
+ return this._${method}(path, params, data, query, opts, ${requestBodyContentType === undefined ||
174
+ requestBodyContentType === "multipart/form-data"
175
+ ? "undefined"
176
+ : `"${requestBodyContentType}"`});
177
+ };`;
178
+ output += fcn;
179
+ }
180
+ if (api.paths[path].delete) {
181
+ let responseType = await createResponseBodyType(api.paths[path], "delete", opts.throwOnNotOkayRes);
182
+ const hasUrlParameters = (api.paths[path].delete.parameters || []).some((x) => x.in === "path");
183
+ let deleteFcn = `${getOperationId(api.paths[path].delete)}(
184
+ params${hasUrlParameters ? "" : "?"}: ${createParamType(path).type},
185
+ query?: ${await createQueryType(api.paths[path].delete.parameters)},
186
+ opts?: ${optsType}
187
+ ) : Promise<${responseType}> {
188
+ let path = "${convertPath(path)}";
189
+ return this._delete(path, params, query, opts);
190
+ };`;
191
+ output += deleteFcn;
192
+ }
193
+ return output;
194
+ }));
195
+ const code = prettier.format(getSDKCode(routes.join(" "), opts.throwOnNotOkayRes, opts.cacheType), { parser: "typescript" });
196
+ const tsConfigJSON = {
197
+ compilerOptions: {
198
+ target: "ES2020",
199
+ module: opts.module,
200
+ moduleResolution: "node",
201
+ declaration: true,
202
+ outDir: "./dist",
203
+ forceConsistentCasingInFileNames: true,
204
+ },
205
+ include: ["index.ts"],
206
+ };
207
+ const typeScriptVersion = "4.5.5";
208
+ const packageJSON = {
209
+ name: "temp",
210
+ version: "1.0.0",
211
+ dependencies: {
212
+ "cross-fetch": "^3.1.5",
213
+ "node-cache": "^4.2.1",
214
+ qs: "^6.9.4",
215
+ "@types/qs": "^6.9.5",
216
+ },
217
+ devDependencies: {
218
+ "@types/node": "13.9.1",
219
+ typescript: typeScriptVersion,
220
+ },
221
+ };
222
+ const tmpDirPath = path.join(os.tmpdir(), `osg-${Date.now()}`);
223
+ fse.mkdirpSync(tmpDirPath);
224
+ fs.writeFileSync(path.join(tmpDirPath, "index.ts"), code);
225
+ fs.writeFileSync(path.join(tmpDirPath, "package.json"), JSON.stringify(packageJSON, null, 2));
226
+ fs.writeFileSync(path.join(tmpDirPath, "tsconfig.json"), JSON.stringify(tsConfigJSON, null, 2));
227
+ child_process.execSync("npm i", { cwd: tmpDirPath, stdio: "inherit" });
228
+ const buildOutputPath = path.join(tmpDirPath, "dist");
229
+ // const nccVersion = "0.33.1";
230
+ // child_process.execSync(
231
+ // `npx --yes -p @vercel/ncc@${nccVersion} ncc build ./index.ts -o dist`,
232
+ // { cwd: tmpDirPath, stdio: "inherit" }
233
+ // );
234
+ // TODO - remove if we get ncc build output to work with CRA build
235
+ child_process.execSync(`npx -p typescript@${typeScriptVersion} tsc`, {
236
+ cwd: tmpDirPath,
237
+ stdio: "inherit",
238
+ });
239
+ // Disable ESLint for the compiled file. Mainly for CRA.
240
+ prependFile.sync(path.join(buildOutputPath, "index.js"), `/* eslint-disable */\n\n`);
241
+ const outdir = path.resolve(opts.outdir);
242
+ if (!fs.existsSync(outdir)) {
243
+ fse.mkdirpSync(outdir);
244
+ }
245
+ const isGeneratePackageMode = opts.packageName != null;
246
+ const distOutputPath = isGeneratePackageMode
247
+ ? path.join(outdir, "dist")
248
+ : outdir;
249
+ fse.copySync(buildOutputPath, distOutputPath);
250
+ fse.removeSync(tmpDirPath);
251
+ if (isGeneratePackageMode) {
252
+ const packageJSON = {
253
+ name: opts.packageName,
254
+ version: "1.0.0",
255
+ author: opts.packageAuthor ?? "",
256
+ license: "MIT",
257
+ description: opts.packageDescription ?? "",
258
+ main: "./dist/index.js",
259
+ types: "./dist/index.d.ts",
260
+ };
261
+ const gitignoreSource = `/node_modules
262
+ /.pnp
263
+ .pnp.js
264
+
265
+ npm-debug.log*
266
+ yarn-debug.log*
267
+ yarn-error.log*
268
+
269
+ .vscode
270
+ `;
271
+ fs.writeFileSync(path.join(outdir, "package.json"), JSON.stringify(packageJSON, null, 2));
272
+ fs.writeFileSync(path.join(outdir, ".gitignore"), gitignoreSource);
273
+ }
274
+ }
275
+ exports.generate = generate;
276
+ function getSDKCode(methods, throwOnNotOkayRes, cacheType) {
277
+ const useMemoryCache = cacheType === "memory";
278
+ return `import "cross-fetch/polyfill";
279
+ import * as qs from "qs";
280
+ ${useMemoryCache ? `const NodeCache = require("node-cache");` : ""}
281
+
282
+ type Headers = { [k: string]: string };
283
+
284
+ ${throwOnNotOkayRes
285
+ ? `class CustomError extends Error {
286
+ constructor(message) {
287
+ super(message);
288
+ this.name = this.constructor.name;
289
+ }
290
+ };
291
+
292
+ export class SDKResponseError extends CustomError {
293
+ error: any;
294
+ status: number;
295
+
296
+ constructor(error, status) {
297
+ super("Bad response");
298
+ this.error = error;
299
+ this.status = status;
300
+ }
301
+ }
302
+ `
303
+ : ""}
304
+
305
+ type QueryStringOpts = Parameters<typeof qs.stringify>[1]
306
+
307
+ export class SDK {
308
+ _baseUrl?: string;
309
+ _headers?: Headers;
310
+ _queryStringOpts?: QueryStringOpts;
311
+ ${useMemoryCache ? `_cache: InstanceType<typeof NodeCache>;` : ""}
312
+
313
+ constructor(opts: { baseUrl: string; headers?: Headers, queryStringOpts?: QueryStringOpts }) {
314
+ this.__setBaseUrl(opts.baseUrl);
315
+ this._queryStringOpts = opts.queryStringOpts;
316
+ if (opts?.headers) {
317
+ this._headers = opts.headers ?? {};
318
+ }
319
+ ${useMemoryCache
320
+ ? `this._cache = new NodeCache({
321
+ // 10 min
322
+ stdTTL: 600,
323
+ // 5 min
324
+ checkperiod: 300,
325
+ });`
326
+ : ""}
327
+ }
328
+
329
+ __setBaseUrl(baseUrl: string) {
330
+ this._baseUrl = baseUrl;
331
+ }
332
+
333
+ __setHeaders(fn: any) {
334
+ this._headers = fn(this._headers);
335
+ }
336
+
337
+ __clearCache() {
338
+ ${useMemoryCache ? `this._cache.flushAll();` : ""}
339
+ }
340
+
341
+ ${methods}
342
+
343
+ async _get(path, params, query, opts) {
344
+ const { hydratedPath } = findParamArguments(path, params);
345
+ const url = \`\${this._baseUrl}\${hydratedPath}\${generateQueryString(query, this._queryStringOpts)}\`;
346
+ const cacheKey = \`GET\${url}\`;
347
+
348
+ ${useMemoryCache
349
+ ? `if (opts?.strategy !== "network") {
350
+ const cached = this._cache.get(cacheKey);
351
+ if (cached !== undefined) {
352
+ return cached;
353
+ }
354
+ }`
355
+ : ""}
356
+
357
+ let headers = { "Content-Type": "application/json" };
358
+ if (this._headers) {
359
+ headers = { ...headers, ...this._headers };
360
+ }
361
+ if (opts?.headers) {
362
+ headers = { ...headers, ...opts.headers };
363
+ }
364
+
365
+ let res = await fetch(url, { headers });
366
+
367
+ const json = await res.json();
368
+
369
+ if (!res.ok) {
370
+ ${throwOnNotOkayRes
371
+ ? `throw new SDKResponseError(json, res.status);`
372
+ : `return { error: json, status: res.status };`}
373
+ }
374
+
375
+ const out = { data: json, status: res.status };
376
+ ${useMemoryCache ? `this._cache.set(cacheKey, out);` : ""}
377
+
378
+ return out;
379
+ }
380
+
381
+ async _post(path, params, data, query, opts, requestBodyContentType) {
382
+ const { hydratedPath } = findParamArguments(path, params);
383
+
384
+ let headers = !requestBodyContentType ? {} : { "Content-Type": requestBodyContentType };
385
+ if (this._headers) {
386
+ headers = { ...headers, ...this._headers };
387
+ }
388
+ if (opts?.headers) {
389
+ headers = { ...headers, ...opts.headers };
390
+ }
391
+
392
+ let res = await fetch(
393
+ \`\${this._baseUrl}\${hydratedPath}\${generateQueryString(query, this._queryStringOpts)}\`,
394
+ {
395
+ method: "POST",
396
+ headers,
397
+ body: requestBodyContentType === "application/json" ? JSON.stringify(data) : data,
398
+ }
399
+ );
400
+
401
+ if (res.status === 204) {
402
+ ${useMemoryCache
403
+ ? `if (opts?.clearCache !== false) {
404
+ this._cache.flushAll();
405
+ }`
406
+ : ""}
407
+ return { data: undefined, status: res.status };
408
+ }
409
+
410
+ const json = await res.json();
411
+
412
+ if (!res.ok) {
413
+ ${throwOnNotOkayRes
414
+ ? `throw new SDKResponseError(json, res.status);`
415
+ : `return { error: json, status: res.status };`}
416
+ }
417
+
418
+ ${useMemoryCache
419
+ ? `if (opts?.clearCache !== false) {
420
+ this._cache.flushAll();
421
+ }`
422
+ : ""}
423
+
424
+ return { data: json, status: res.status };
425
+ }
426
+
427
+ async _patch(path, params, data, query, opts, requestBodyContentType) {
428
+ const { hydratedPath } = findParamArguments(path, params);
429
+
430
+ let headers = !requestBodyContentType ? {} : { "Content-Type": requestBodyContentType };
431
+ if (this._headers) {
432
+ headers = { ...headers, ...this._headers };
433
+ }
434
+ if (opts?.headers) {
435
+ headers = { ...headers, ...opts.headers };
436
+ }
437
+
438
+ let res = await fetch(
439
+ \`\${this._baseUrl}\${hydratedPath}\${generateQueryString(query, this._queryStringOpts)}\`,
440
+ {
441
+ method: "PATCH",
442
+ headers,
443
+ body: requestBodyContentType === "application/json" ? JSON.stringify(data) : data,
444
+ }
445
+ );
446
+
447
+ if (res.status === 204) {
448
+ ${useMemoryCache
449
+ ? `if (opts?.clearCache !== false) {
450
+ this._cache.flushAll();
451
+ }`
452
+ : ""}
453
+ return { data: undefined, status: res.status };
454
+ }
455
+
456
+ const json = await res.json();
457
+
458
+ if (!res.ok) {
459
+ ${throwOnNotOkayRes
460
+ ? `throw new SDKResponseError(json, res.status);`
461
+ : `return { error: json, status: res.status };`}
462
+ }
463
+
464
+ ${useMemoryCache
465
+ ? `if (opts?.clearCache !== false) {
466
+ this._cache.flushAll();
467
+ }`
468
+ : ""}
469
+
470
+ return { data: json, status: res.status };
471
+ }
472
+
473
+ async _put(path, params, data, query, opts, requestBodyContentType) {
474
+ const { hydratedPath } = findParamArguments(path, params);
475
+
476
+ let headers = !requestBodyContentType ? {} : { "Content-Type": requestBodyContentType };
477
+ if (this._headers) {
478
+ headers = { ...headers, ...this._headers };
479
+ }
480
+ if (opts?.headers) {
481
+ headers = { ...headers, ...opts.headers };
482
+ }
483
+
484
+ let res = await fetch(
485
+ \`\${this._baseUrl}\${hydratedPath}\${generateQueryString(query, this._queryStringOpts)}\`,
486
+ {
487
+ method: "PUT",
488
+ headers,
489
+ body: requestBodyContentType === "application/json" ? JSON.stringify(data) : data,
490
+ }
491
+ );
492
+
493
+ if (res.status === 204) {
494
+ ${useMemoryCache
495
+ ? `if (opts?.clearCache !== false) {
496
+ this._cache.flushAll();
497
+ }`
498
+ : ""}
499
+ return { data: undefined, status: res.status };
500
+ }
501
+
502
+ const json = await res.json();
503
+
504
+ if (!res.ok) {
505
+ ${throwOnNotOkayRes
506
+ ? `throw new SDKResponseError(json, res.status);`
507
+ : `return { error: json, status: res.status };`}
508
+ }
509
+
510
+ ${useMemoryCache
511
+ ? `if (opts?.clearCache !== false) {
512
+ this._cache.flushAll();
513
+ }`
514
+ : ""}
515
+
516
+ return { data: json, status: res.status };
517
+ }
518
+
519
+ async _delete(path, params, query, opts) {
520
+ const { hydratedPath } = findParamArguments(path, params);
521
+
522
+ let headers = { "Content-Type": "application/json" };
523
+ if (this._headers) {
524
+ headers = { ...headers, ...this._headers };
525
+ }
526
+ if (opts?.headers) {
527
+ headers = { ...headers, ...opts.headers };
528
+ }
529
+
530
+ let res = await fetch(
531
+ \`\${this._baseUrl}\${hydratedPath}\${generateQueryString(query, this._queryStringOpts)}\`,
532
+ { method: "DELETE", headers }
533
+ );
534
+
535
+ if (res.status === 204) {
536
+ ${useMemoryCache
537
+ ? `if (opts?.clearCache !== false) {
538
+ this._cache.flushAll();
539
+ }`
540
+ : ""}
541
+ return { data: undefined, status: res.status };
542
+ }
543
+
544
+ const json = await res.json();
545
+
546
+ if (!res.ok) {
547
+ ${throwOnNotOkayRes
548
+ ? `throw new SDKResponseError(json, res.status);`
549
+ : `return { error: json, status: res.status };`}
550
+ }
551
+
552
+ ${useMemoryCache
553
+ ? `if (opts?.clearCache !== false) {
554
+ this._cache.flushAll();
555
+ }`
556
+ : ""}
557
+
558
+ return { data: json, status: res.status };
559
+ }
560
+ }
561
+
562
+ function findParamArguments(path, obj) {
563
+ let parts = path.split(/\\//);
564
+ let params = parts.filter((p) => p.length > 0 && p[0] === ":");
565
+ let args = params.map((p) => p.substring(1, p.length));
566
+ let out = {};
567
+ let hydratedPath = path;
568
+ if (obj) {
569
+ args.forEach((e) => {
570
+ out[e] = obj[e];
571
+ hydratedPath = hydratedPath.replace(\`:\${e}\`, obj[e]);
572
+ });
573
+ }
574
+
575
+ return { args, out, hydratedPath };
576
+ }
577
+
578
+ function generateQueryString(obj, _opts) {
579
+ let opts = { addQueryPrefix: true, encode: true };
580
+ if (_opts) {
581
+ opts = {...opts, ..._opts};
582
+ }
583
+ return qs.stringify(obj, opts);
584
+ }
585
+ `;
586
+ }
587
+ function getRequestBodyContentType(operationDef, method) {
588
+ const content = operationDef?.[method]?.requestBody?.content;
589
+ if (content == null) {
590
+ throw new Error("No content: " + getOperationId(operationDef));
591
+ }
592
+ const keys = Object.keys(content);
593
+ if (keys.length === 0) {
594
+ throw new Error("No content type: " + getOperationId(operationDef));
595
+ }
596
+ if (keys.length > 1) {
597
+ throw new Error("More than 1 content type. Not allowed: " + getOperationId(operationDef));
598
+ }
599
+ return keys[0];
600
+ }
601
+ async function createRequestBodyType(operationDef, method) {
602
+ let typeName = capitalize(getOperationId(operationDef[method])) + "Body";
603
+ if (operationDef?.[method]?.requestBody == null) {
604
+ return { type: "undefined", name: "" };
605
+ }
606
+ if (operationDef?.[method]?.requestBody?.content?.["application/json"] == null) {
607
+ return { type: "any", name: "" };
608
+ }
609
+ if (operationDef?.[method]?.requestBody?.content?.["application/json"]
610
+ ?.schema == null ||
611
+ operationDef[method].requestBody.content["application/json"].schema
612
+ .length === 0) {
613
+ return { type: "object", name: "" };
614
+ }
615
+ const schema = toJsonSchema(operationDef[method].requestBody.content["application/json"].schema);
616
+ // Delete title, since if there's a title, json-schema-to-typescript
617
+ // generates references.
618
+ traverse(schema, {
619
+ cb: (schema) => {
620
+ if (schema.title) {
621
+ delete schema.title;
622
+ }
623
+ },
624
+ });
625
+ return {
626
+ type: (await json_schema_to_typescript_1.compile(schema, "IRootObject", {
627
+ bannerComment: "",
628
+ declareExternallyReferenced: false,
629
+ }))
630
+ .replace(/export interface IRootObject/g, "")
631
+ .replace(/export type IRootObject =/g, "")
632
+ .replace(/};/g, "}")
633
+ .replace(`/**\n * The request body is an empty object.\n */\n{}\n`, "object"),
634
+ name: typeName,
635
+ };
636
+ }
637
+ function createParamType(path) {
638
+ // TODO - use `parameters` instead
639
+ let params = findParamArguments(path);
640
+ if (params.args.length === 0) {
641
+ return { type: "null", name: "" };
642
+ }
643
+ return {
644
+ type: json2ts(JSON.stringify(params.out)).replace("interface IRootObject ", ""),
645
+ name: "",
646
+ };
647
+ }
648
+ async function createQueryType(parameters) {
649
+ if (parameters == null) {
650
+ return "object";
651
+ }
652
+ const queryParameters = parameters.filter((x) => x.in === "query");
653
+ if (queryParameters.length === 0) {
654
+ return "object";
655
+ }
656
+ const schema = queryParameters.reduce((acc, v) => {
657
+ acc.properties[v.name] = v.schema;
658
+ if (v.required) {
659
+ acc.required.push(v.name);
660
+ }
661
+ return acc;
662
+ }, { properties: {}, required: [] });
663
+ // Delete title, since if there's a title, json-schema-to-typescript
664
+ // generates references.
665
+ traverse(schema, {
666
+ cb: (schema) => {
667
+ if (schema.title) {
668
+ delete schema.title;
669
+ }
670
+ },
671
+ });
672
+ return (await json_schema_to_typescript_1.compile(schema, "IRootObject", {
673
+ bannerComment: "",
674
+ declareExternallyReferenced: false,
675
+ }))
676
+ .replace("export interface IRootObject ", "")
677
+ .replace(`/**\n * The request body is an empty object.\n */\n{}\n`, "object")
678
+ .replace("[k: string]: any;", "");
679
+ }
680
+ async function createResponseBodyType(operationDef, method, throwOnNotOkayRes) {
681
+ let responses = operationDef[method]?.responses ?? {};
682
+ let out = "";
683
+ for (let [status, response] of Object.entries(responses)) {
684
+ const _schema = response?.content?.["application/json"]?.schema;
685
+ const schema = _schema == null ? _schema : toJsonSchema(_schema, { strictMode: false });
686
+ // Delete title, since if there's a title, json-schema-to-typescript
687
+ // generates references.
688
+ if (schema != null) {
689
+ traverse(schema, {
690
+ cb: (schema) => {
691
+ if (schema.title) {
692
+ delete schema.title;
693
+ }
694
+ },
695
+ });
696
+ }
697
+ let type = schema == null
698
+ ? schema
699
+ : (await json_schema_to_typescript_1.compile(schema, "IRootObject", {
700
+ bannerComment: "",
701
+ declareExternallyReferenced: false,
702
+ }))
703
+ .replace(/export interface IRootObject /g, "")
704
+ .replace("export type IRootObject =", "")
705
+ .trim();
706
+ if (type?.endsWith(";")) {
707
+ type = type.slice(0, -1);
708
+ }
709
+ const notOk = parseInt(status) >= 400;
710
+ if (throwOnNotOkayRes) {
711
+ if (notOk) {
712
+ continue;
713
+ }
714
+ else {
715
+ out += `| {data: ${type}, status: number}`;
716
+ }
717
+ }
718
+ else {
719
+ if (notOk) {
720
+ out += `| {error: ${type}, status: number}`;
721
+ }
722
+ else {
723
+ out += `| {data: ${type}, error?: undefined, status: number}`;
724
+ }
725
+ }
726
+ }
727
+ if (!throwOnNotOkayRes) {
728
+ // TODO?
729
+ // if (!Object.keys(responses).some(x => parseInt(x) >= 400)) {
730
+ out += "| {error: {[k: string]: any}, status: number}";
731
+ // }
732
+ }
733
+ return out;
734
+ }
735
+ function getOperationId(x) {
736
+ return x?.["x-technicity-sdk-name"] ?? x?.["operationId"];
737
+ }
738
+ function findParamArguments(path) {
739
+ let parts = path.split(/\//);
740
+ let params = parts
741
+ .map((p) => (p.startsWith("{") ? `:${p.slice(1, p.length - 1)}` : p))
742
+ .filter((p) => p.length > 0 && p[0] === ":");
743
+ let args = params.map((p) => p.substring(1, p.length));
744
+ let out = {};
745
+ let hydratedPath = path;
746
+ args.forEach((e) => {
747
+ out[e] = e;
748
+ hydratedPath = hydratedPath.replace(`:${e}`, e);
749
+ });
750
+ return { args, out, hydratedPath };
751
+ }
752
+ function convertPath(p) {
753
+ return p
754
+ .split(/\//)
755
+ .map((p) => (p.startsWith("{") ? `:${p.slice(1, p.length - 1)}` : p))
756
+ .join("/");
757
+ }
758
+ function capitalize(s) {
759
+ if (typeof s !== "string")
760
+ return "";
761
+ return s.charAt(0).toUpperCase() + s.slice(1);
762
+ }
763
+ //# sourceMappingURL=generate.js.map