@moccona/apicodegen 0.0.3 → 0.0.7

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/npm/index.cjs CHANGED
@@ -1,2417 +1,2191 @@
1
- "use strict";
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region \0rolldown/runtime.js
2
3
  var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
4
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
7
  var __getProtoOf = Object.getPrototypeOf;
7
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
9
  var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
19
18
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/index.ts
31
- var index_exports = {};
32
- __export(index_exports, {
33
- Adapter: () => Adapter,
34
- Adaptors: () => Adaptors,
35
- ArraySchemaType: () => ArraySchemaType,
36
- AxiosAdapter: () => AxiosAdapter,
37
- Base: () => Base,
38
- FetchAdapter: () => FetchAdapter,
39
- Generator: () => Generator,
40
- HttpMethods: () => HttpMethods,
41
- MediaTypes: () => MediaTypes,
42
- NonArraySchemaType: () => NonArraySchemaType,
43
- OpenAPIProvider: () => OpenAPIProvider,
44
- OpenAPIVersion: () => OpenAPIVersion,
45
- ParameterIn: () => ParameterIn,
46
- Provider: () => Provider,
47
- SchemaFormatType: () => SchemaFormatType,
48
- SchemaType: () => SchemaType,
49
- SuccessHttpStatusCode: () => SuccessHttpStatusCode,
50
- apiCodeGenPlugin: () => apiCodeGenPlugin,
51
- codeGen: () => codeGen,
52
- tsc: () => tsc
53
- });
54
- module.exports = __toCommonJS(index_exports);
55
-
56
- // src/core/base/Adaptor.ts
57
- var Adapter = class {
58
- };
59
-
60
- // src/core/constants/keywords.ts
61
- var typescriptKeywords = /* @__PURE__ */ new Set([
62
- "break",
63
- "case",
64
- "catch",
65
- "class",
66
- "const",
67
- "continue",
68
- "debugger",
69
- "default",
70
- "delete",
71
- "do",
72
- "else",
73
- "enum",
74
- "export",
75
- "extends",
76
- "false",
77
- "finally",
78
- "for",
79
- "function",
80
- "if",
81
- "import",
82
- "in",
83
- "instanceof",
84
- "new",
85
- "null",
86
- "return",
87
- "super",
88
- "switch",
89
- "this",
90
- "throw",
91
- "true",
92
- "try",
93
- "typeof",
94
- "var",
95
- "void",
96
- "while",
97
- "with",
98
- "as",
99
- "implements",
100
- "interface",
101
- "let",
102
- "package",
103
- "private",
104
- "protected",
105
- "public",
106
- "static",
107
- "yield",
108
- "abstract",
109
- "any",
110
- "async",
111
- "await",
112
- "constructor",
113
- "declare",
114
- "from",
115
- "get",
116
- "is",
117
- "module",
118
- "namespace",
119
- "never",
120
- "require",
121
- "set",
122
- "type",
123
- "unknown",
124
- "readonly",
125
- "of",
126
- "asserts",
127
- "infer",
128
- "keyof",
129
- "boolean",
130
- "number",
131
- "string",
132
- "symbol",
133
- "object",
134
- "undefined",
135
- "bigint"
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
24
+ let undici = require("undici");
25
+ let typescript = require("typescript");
26
+ let node_fs_promises = require("node:fs/promises");
27
+ let prettier = require("prettier");
28
+ let node_path = require("node:path");
29
+ node_path = __toESM(node_path, 1);
30
+ let fs_extra = require("fs-extra");
31
+ fs_extra = __toESM(fs_extra, 1);
32
+ let _moccona_logger = require("@moccona/logger");
33
+ //#region src/core/base/Adaptor.ts
34
+ /**
35
+ * Base adapter for tool
36
+ * This abstract class serves as the foundation for implementing adapters for different code generation tools
37
+ */
38
+ var Adapter = class {};
39
+ //#endregion
40
+ //#region src/core/constants/keywords.ts
41
+ const typescriptKeywords = new Set([
42
+ "break",
43
+ "case",
44
+ "catch",
45
+ "class",
46
+ "const",
47
+ "continue",
48
+ "debugger",
49
+ "default",
50
+ "delete",
51
+ "do",
52
+ "else",
53
+ "enum",
54
+ "export",
55
+ "extends",
56
+ "false",
57
+ "finally",
58
+ "for",
59
+ "function",
60
+ "if",
61
+ "import",
62
+ "in",
63
+ "instanceof",
64
+ "new",
65
+ "null",
66
+ "return",
67
+ "super",
68
+ "switch",
69
+ "this",
70
+ "throw",
71
+ "true",
72
+ "try",
73
+ "typeof",
74
+ "var",
75
+ "void",
76
+ "while",
77
+ "with",
78
+ "as",
79
+ "implements",
80
+ "interface",
81
+ "let",
82
+ "package",
83
+ "private",
84
+ "protected",
85
+ "public",
86
+ "static",
87
+ "yield",
88
+ "abstract",
89
+ "any",
90
+ "async",
91
+ "await",
92
+ "constructor",
93
+ "declare",
94
+ "from",
95
+ "get",
96
+ "is",
97
+ "module",
98
+ "namespace",
99
+ "never",
100
+ "require",
101
+ "set",
102
+ "type",
103
+ "unknown",
104
+ "readonly",
105
+ "of",
106
+ "asserts",
107
+ "infer",
108
+ "keyof",
109
+ "boolean",
110
+ "number",
111
+ "string",
112
+ "symbol",
113
+ "object",
114
+ "undefined",
115
+ "bigint"
136
116
  ]);
137
-
138
- // src/core/interface.ts
139
- var SchemaType = /* @__PURE__ */ ((SchemaType2) => {
140
- SchemaType2["schemas"] = "schemas";
141
- SchemaType2["parameters"] = "parameters";
142
- SchemaType2["responses"] = "responses";
143
- SchemaType2["requestBodies"] = "requestBodies";
144
- return SchemaType2;
145
- })(SchemaType || {});
146
- var NonArraySchemaType = /* @__PURE__ */ ((NonArraySchemaType2) => {
147
- NonArraySchemaType2["object"] = "object";
148
- NonArraySchemaType2["string"] = "string";
149
- NonArraySchemaType2["number"] = "number";
150
- NonArraySchemaType2["boolean"] = "boolean";
151
- NonArraySchemaType2["integer"] = "integer";
152
- NonArraySchemaType2["enum"] = "enum";
153
- NonArraySchemaType2["file"] = "file";
154
- return NonArraySchemaType2;
155
- })(NonArraySchemaType || {});
156
- var ArraySchemaType = /* @__PURE__ */ ((ArraySchemaType2) => {
157
- ArraySchemaType2["array"] = "array";
158
- return ArraySchemaType2;
159
- })(ArraySchemaType || {});
160
- var SchemaFormatType = /* @__PURE__ */ ((SchemaFormatType3) => {
161
- SchemaFormatType3["string"] = "string";
162
- SchemaFormatType3["number"] = "number";
163
- SchemaFormatType3["boolean"] = "boolean";
164
- SchemaFormatType3["file"] = "file";
165
- SchemaFormatType3["binary"] = "binary";
166
- SchemaFormatType3["blob"] = "blob";
167
- return SchemaFormatType3;
168
- })(SchemaFormatType || {});
169
- var ParameterIn = /* @__PURE__ */ ((ParameterIn3) => {
170
- ParameterIn3["header"] = "header";
171
- ParameterIn3["body"] = "body";
172
- ParameterIn3["query"] = "query";
173
- ParameterIn3["cookie"] = "cookie";
174
- ParameterIn3["path"] = "path";
175
- ParameterIn3["formData"] = "formData";
176
- return ParameterIn3;
177
- })(ParameterIn || {});
178
- var MediaTypes = /* @__PURE__ */ ((MediaTypes2) => {
179
- MediaTypes2["JSON"] = "application/json";
180
- MediaTypes2["TEXT"] = "text";
181
- MediaTypes2["IMAGE"] = "image";
182
- MediaTypes2["AUDIO"] = "audio";
183
- MediaTypes2["VIDEO"] = "video";
184
- return MediaTypes2;
185
- })(MediaTypes || {});
186
- var HttpMethods = /* @__PURE__ */ ((HttpMethods2) => {
187
- HttpMethods2["GET"] = "get";
188
- HttpMethods2["PUT"] = "put";
189
- HttpMethods2["POST"] = "post";
190
- HttpMethods2["DELETE"] = "delete";
191
- HttpMethods2["OPTIONS"] = "options";
192
- HttpMethods2["HEAD"] = "head";
193
- HttpMethods2["PATCH"] = "patch";
194
- HttpMethods2["TRACE"] = "trace";
195
- return HttpMethods2;
196
- })(HttpMethods || {});
197
- var Adaptors = /* @__PURE__ */ ((Adaptors2) => {
198
- Adaptors2["fetch"] = "fetch";
199
- Adaptors2["axios"] = "axios";
200
- return Adaptors2;
201
- })(Adaptors || {});
202
-
203
- // src/core/base/Base.ts
204
- var import_undici = require("undici");
205
- var SuccessHttpStatusCode = {
206
- "200": "200",
207
- // OK
208
- "201": "201",
209
- // Created
210
- "202": "202",
211
- // Accepted
212
- "203": "203",
213
- // Non-Authoritative Information
214
- "204": "204",
215
- // No Content
216
- "205": "205",
217
- // Reset Content
218
- "206": "206",
219
- // Partial Content
220
- "207": "207",
221
- // Multi_Status
222
- "208": "208",
223
- // Already_Reported
224
- "226": "226"
225
- // IM Used
117
+ //#endregion
118
+ //#region src/core/interface.ts
119
+ let SchemaType = /* @__PURE__ */ function(SchemaType) {
120
+ SchemaType["schemas"] = "schemas";
121
+ SchemaType["parameters"] = "parameters";
122
+ SchemaType["responses"] = "responses";
123
+ SchemaType["requestBodies"] = "requestBodies";
124
+ return SchemaType;
125
+ }({});
126
+ let NonArraySchemaType = /* @__PURE__ */ function(NonArraySchemaType) {
127
+ NonArraySchemaType["object"] = "object";
128
+ NonArraySchemaType["string"] = "string";
129
+ NonArraySchemaType["number"] = "number";
130
+ NonArraySchemaType["boolean"] = "boolean";
131
+ NonArraySchemaType["integer"] = "integer";
132
+ NonArraySchemaType["enum"] = "enum";
133
+ NonArraySchemaType["file"] = "file";
134
+ return NonArraySchemaType;
135
+ }({});
136
+ let ArraySchemaType = /* @__PURE__ */ function(ArraySchemaType) {
137
+ ArraySchemaType["array"] = "array";
138
+ return ArraySchemaType;
139
+ }({});
140
+ let SchemaFormatType = /* @__PURE__ */ function(SchemaFormatType) {
141
+ SchemaFormatType["string"] = "string";
142
+ SchemaFormatType["number"] = "number";
143
+ SchemaFormatType["boolean"] = "boolean";
144
+ SchemaFormatType["file"] = "file";
145
+ SchemaFormatType["binary"] = "binary";
146
+ SchemaFormatType["blob"] = "blob";
147
+ return SchemaFormatType;
148
+ }({});
149
+ let ParameterIn = /* @__PURE__ */ function(ParameterIn) {
150
+ ParameterIn["header"] = "header";
151
+ ParameterIn["body"] = "body";
152
+ ParameterIn["query"] = "query";
153
+ ParameterIn["cookie"] = "cookie";
154
+ ParameterIn["path"] = "path";
155
+ ParameterIn["formData"] = "formData";
156
+ return ParameterIn;
157
+ }({});
158
+ let MediaTypes = /* @__PURE__ */ function(MediaTypes) {
159
+ MediaTypes["JSON"] = "application/json";
160
+ MediaTypes["TEXT"] = "text";
161
+ MediaTypes["IMAGE"] = "image";
162
+ MediaTypes["AUDIO"] = "audio";
163
+ MediaTypes["VIDEO"] = "video";
164
+ return MediaTypes;
165
+ }({});
166
+ let HttpMethods = /* @__PURE__ */ function(HttpMethods) {
167
+ HttpMethods["GET"] = "get";
168
+ HttpMethods["PUT"] = "put";
169
+ HttpMethods["POST"] = "post";
170
+ HttpMethods["DELETE"] = "delete";
171
+ HttpMethods["OPTIONS"] = "options";
172
+ HttpMethods["HEAD"] = "head";
173
+ HttpMethods["PATCH"] = "patch";
174
+ HttpMethods["TRACE"] = "trace";
175
+ return HttpMethods;
176
+ }({});
177
+ let Adaptors = /* @__PURE__ */ function(Adaptors) {
178
+ Adaptors["fetch"] = "fetch";
179
+ Adaptors["axios"] = "axios";
180
+ return Adaptors;
181
+ }({});
182
+ //#endregion
183
+ //#region src/core/base/Base.ts
184
+ /**
185
+ * @file Base class implementation
186
+ * @author wp.l
187
+ * @description Base utility class providing common methods for code generation and API handling
188
+ */
189
+ /**
190
+ * Represents success HTTP status codes.
191
+ * Each key is a string representation of a success HTTP status code.
192
+ */
193
+ const SuccessHttpStatusCode = {
194
+ "200": "200",
195
+ "201": "201",
196
+ "202": "202",
197
+ "203": "203",
198
+ "204": "204",
199
+ "205": "205",
200
+ "206": "206",
201
+ "207": "207",
202
+ "208": "208",
203
+ "226": "226"
226
204
  };
227
- var Base = class _Base {
228
- constructor() {
229
- if (new.target === _Base) {
230
- throw new Error("Cannot instantiate abstract class");
231
- }
232
- }
233
- /**
234
- * Converts a reference string to a meaningful name.
235
- * @param ref - The reference string to process.
236
- * @param [doc] - Optional document reference for context.
237
- * @returns - The processed name.
238
- */
239
- static ref2name(ref, doc) {
240
- const paths = ref.replace(/^#/, "").split("/").filter(Boolean);
241
- if (!doc) {
242
- return paths.slice(-1)[0];
243
- }
244
- let temporary = doc;
245
- let lastPath = "";
246
- for (const path of paths) {
247
- const adjustedPath = path.replaceAll("~1", "/");
248
- temporary = temporary[adjustedPath];
249
- lastPath = adjustedPath;
250
- }
251
- if (!temporary) {
252
- return "unknown";
253
- }
254
- return temporary.$ref ? this.ref2name(temporary.$ref, doc) : lastPath;
255
- }
256
- /**
257
- * Converts an API path to a function name.
258
- * @param path - The API endpoint path.
259
- * @param [method] - The HTTP method (e.g., GET, POST).
260
- * @param [operationId] - Unique identifier for the operation.
261
- * @returns - The generated function name.
262
- */
263
- static pathToFnName(path, method, _operationId = "") {
264
- const name = this.normalize(this.camelCase(this.normalize(path)));
265
- const suffix = method ? this.capitalize(this.upperCamelCase(`using_${method}`)) : "";
266
- return name + suffix;
267
- }
268
- /**
269
- * Normalizes a string by replacing special characters and avoiding TypeScript keywords.
270
- * @param text - Input text to normalize.
271
- * @returns - The normalized string.
272
- */
273
- static normalize(text) {
274
- if (typescriptKeywords.has(text)) {
275
- text += "_";
276
- }
277
- return text.replace(/[/\-_{}():\s`,*<>$#.]/gm, "_").replace(/^\d./gm, "").replaceAll("...", "");
278
- }
279
- /**
280
- * Capitalizes the first character of a string.
281
- * @param text - Input string.
282
- * @returns - Capitalized string.
283
- */
284
- static capitalize(text) {
285
- text = text.trim();
286
- return `${text.charAt(0).toUpperCase()}${text.slice(1)}`;
287
- }
288
- /**
289
- * Converts a string to camelCase.
290
- * @param text - Input string.
291
- * @returns - CamelCase string.
292
- */
293
- static camelCase(text) {
294
- text = text.trim();
295
- return text.split("_").filter(Boolean).map((t4, index) => index === 0 ? t4 : this.capitalize(t4)).join("");
296
- }
297
- /**
298
- * Converts a string to UpperCamelCase.
299
- * @param text - Input string.
300
- * @returns - UpperCamelCase string.
301
- */
302
- static upperCamelCase(text) {
303
- return this.normalize(text).replaceAll("...", "").split("_").filter(Boolean).map(this.capitalize).join("");
304
- }
305
- /**
306
- * Fetches documentation from a given URL.
307
- * @param url - The URL to fetch the documentation from.
308
- * @param requestInit - Additional request parameters.
309
- * @returns - A promise resolving to the fetched documentation data.
310
- */
311
- static async fetchDoc(url, requestInit = {}) {
312
- const agent = new import_undici.Agent({
313
- connect: { rejectUnauthorized: false }
314
- });
315
- const { body, statusCode } = await (0, import_undici.request)(url, {
316
- method: "GET",
317
- dispatcher: agent,
318
- ...requestInit
319
- });
320
- if (statusCode >= 400) {
321
- throw new Error(
322
- `Failed to fetch OpenAPI documentation from ${url}: HTTP ${statusCode}`
323
- );
324
- }
325
- try {
326
- return body.json();
327
- } catch (error) {
328
- throw new Error(
329
- `Failed to parse JSON response from ${url}: ${error instanceof Error ? error.message : String(error)}`
330
- );
331
- }
332
- }
333
- /**
334
- * Determines the media type from a given media type string.
335
- * @param mediaType - The media type string to evaluate.
336
- * @returns - The matched MediaTypes or null.
337
- */
338
- static getMediaType(mediaType) {
339
- const mediaTypeValues = Object.values(MediaTypes);
340
- const found = mediaTypeValues.find(
341
- (type) => mediaType.includes(type)
342
- );
343
- return found;
344
- }
345
- /**
346
- * Checks if a schema is a valid enum type that isn't boolean.
347
- * @param a - The schema object to evaluate.
348
- * @returns - True if the schema is a valid non-boolean enum.
349
- */
350
- static isValidEnumType(a) {
351
- return a.type !== "boolean" && !this.isBooleanEnum(a);
352
- }
353
- /**
354
- * Checks if a schema represents a boolean enum.
355
- * @param a - The schema object to evaluate.
356
- * @returns - True if the schema is a boolean enum.
357
- */
358
- static isBooleanEnum(a) {
359
- return a.type === "boolean" || !!a.enum?.some(
360
- (member) => typeof member === "boolean"
361
- );
362
- }
363
- /**
364
- * Checks if two enum schemas are identical.
365
- * @param a - First enum schema to compare.
366
- * @param b - Second enum schema to compare.
367
- * @returns - True if the enums are identical.
368
- */
369
- static isSameEnum(a, b) {
370
- return a.enum.length === b.enum.length && a.enum.sort().every((v, index) => v === b.enum.sort()[index]);
371
- }
372
- /**
373
- * Filters out duplicate enum schemas from an array.
374
- * @param enums - Array of enum schemas to process.
375
- * @returns - Array of unique enum schemas.
376
- */
377
- static uniqueEnums(enums) {
378
- const enumMap = /* @__PURE__ */ new Map();
379
- for (const e of enums) {
380
- const existing = enumMap.get(e.name);
381
- if (existing) {
382
- for (const value of e.enum) {
383
- existing.add(value);
384
- }
385
- } else {
386
- enumMap.set(e.name, new Set(e.enum));
387
- }
388
- }
389
- return Array.from(enumMap.entries()).map(([name, values]) => ({
390
- name,
391
- enum: Array.from(values)
392
- }));
393
- }
394
- /**
395
- * Finds the first occurrence of a matching enum schema in an array.
396
- * @param a - The enum schema to find.
397
- * @param enums - Array of enum schemas to search.
398
- * @returns - The found schema or undefined.
399
- */
400
- static findSameSchema(a, enums) {
401
- return enums.find((b) => this.isSameEnum(b, a));
402
- }
403
- /**
404
- * Checks if an object is a reference object.
405
- * @param schema - The object to check.
406
- * @returns - True if the object is a reference.
407
- */
408
- static isRef(schema) {
409
- return typeof schema === "object" && schema !== null && "$ref" in schema && typeof schema.$ref === "string";
410
- }
205
+ /**
206
+ * Base abstract class providing common utility methods.
207
+ */
208
+ var Base = class Base {
209
+ constructor() {
210
+ if (new.target === Base) throw new Error("Cannot instantiate abstract class");
211
+ }
212
+ /**
213
+ * Converts a reference string to a meaningful name.
214
+ * @param ref - The reference string to process.
215
+ * @param [doc] - Optional document reference for context.
216
+ * @returns - The processed name.
217
+ */
218
+ static ref2name(ref, doc) {
219
+ const paths = ref.replace(/^#/, "").split("/").filter(Boolean);
220
+ if (!doc) return paths.slice(-1)[0];
221
+ let temporary = doc;
222
+ let lastPath = "";
223
+ for (const path of paths) {
224
+ const adjustedPath = path.replaceAll("~1", "/");
225
+ temporary = temporary[adjustedPath];
226
+ lastPath = adjustedPath;
227
+ }
228
+ if (!temporary) return "unknown";
229
+ return temporary.$ref ? Base.ref2name(temporary.$ref, doc) : lastPath;
230
+ }
231
+ /**
232
+ * Converts an API path to a function name.
233
+ * @param path - The API endpoint path.
234
+ * @param [method] - The HTTP method (e.g., GET, POST).
235
+ * @param [operationId] - Unique identifier for the operation.
236
+ * @returns - The generated function name.
237
+ */
238
+ static pathToFnName(path, method, _operationId = "") {
239
+ return Base.normalize(Base.camelCase(Base.normalize(path))) + (method ? Base.capitalize(Base.upperCamelCase(`using_${method}`)) : "");
240
+ }
241
+ /**
242
+ * Normalizes a string by replacing special characters and avoiding TypeScript keywords.
243
+ * @param text - Input text to normalize.
244
+ * @returns - The normalized string.
245
+ */
246
+ static normalize(text) {
247
+ if (typescriptKeywords.has(text)) text += "_";
248
+ return text.replace(/[/\-_{}():\s`,*<>$#.]/gm, "_").replace(/^\d./gm, "").replaceAll("...", "");
249
+ }
250
+ /**
251
+ * Capitalizes the first character of a string.
252
+ * @param text - Input string.
253
+ * @returns - Capitalized string.
254
+ */
255
+ static capitalize(text) {
256
+ text = text.trim();
257
+ return `${text.charAt(0).toUpperCase()}${text.slice(1)}`;
258
+ }
259
+ /**
260
+ * Converts a string to camelCase.
261
+ * @param text - Input string.
262
+ * @returns - CamelCase string.
263
+ */
264
+ static camelCase(text) {
265
+ text = text.trim();
266
+ const parts = text.split("_").filter(Boolean);
267
+ while (parts[0]?.match(/^\d/)) parts.shift();
268
+ return parts.map((t, index) => index === 0 ? t : Base.capitalize(t)).join("");
269
+ }
270
+ /**
271
+ * Converts a string to UpperCamelCase.
272
+ * @param text - Input string.
273
+ * @returns - UpperCamelCase string.
274
+ */
275
+ static upperCamelCase(text) {
276
+ return Base.normalize(text).replaceAll("...", "").split("_").filter(Boolean).map(Base.capitalize).join("");
277
+ }
278
+ /**
279
+ * Fetches documentation from a given URL.
280
+ * @param url - The URL to fetch the documentation from.
281
+ * @param requestInit - Additional request parameters.
282
+ * @returns - A promise resolving to the fetched documentation data.
283
+ */
284
+ static async fetchDoc(url, requestInit = {}) {
285
+ const { body, statusCode } = await (0, undici.request)(url, {
286
+ method: "GET",
287
+ dispatcher: new undici.Agent({ connect: { rejectUnauthorized: false } }),
288
+ ...requestInit
289
+ });
290
+ if (statusCode >= 400) throw new Error(`Failed to fetch OpenAPI documentation from ${url}: HTTP ${statusCode}`);
291
+ try {
292
+ return body.json();
293
+ } catch (error) {
294
+ throw new Error(`Failed to parse JSON response from ${url}: ${error instanceof Error ? error.message : String(error)}`);
295
+ }
296
+ }
297
+ /**
298
+ * Determines the media type from a given media type string.
299
+ * @param mediaType - The media type string to evaluate.
300
+ * @returns - The matched MediaTypes or null.
301
+ */
302
+ static getMediaType(mediaType) {
303
+ return Object.values(MediaTypes).find((type) => mediaType.includes(type));
304
+ }
305
+ /**
306
+ * Checks if a schema is a valid enum type that isn't boolean.
307
+ * @param a - The schema object to evaluate.
308
+ * @returns - True if the schema is a valid non-boolean enum.
309
+ */
310
+ static isValidEnumType(a) {
311
+ return a.type !== "boolean" && !Base.isBooleanEnum(a);
312
+ }
313
+ /**
314
+ * Checks if a schema represents a boolean enum.
315
+ * @param a - The schema object to evaluate.
316
+ * @returns - True if the schema is a boolean enum.
317
+ */
318
+ static isBooleanEnum(a) {
319
+ return a.type === "boolean" || !!a.enum?.some((member) => typeof member === "boolean");
320
+ }
321
+ /**
322
+ * Checks if two enum schemas are identical.
323
+ * @param a - First enum schema to compare.
324
+ * @param b - Second enum schema to compare.
325
+ * @returns - True if the enums are identical.
326
+ */
327
+ static isSameEnum(a, b) {
328
+ return a.enum.length === b.enum.length && a.enum.sort().every((v, index) => v === b.enum.sort()[index]);
329
+ }
330
+ /**
331
+ * Filters out duplicate enum schemas from an array.
332
+ * @param enums - Array of enum schemas to process.
333
+ * @returns - Array of unique enum schemas.
334
+ */
335
+ static uniqueEnums(enums) {
336
+ const enumMap = /* @__PURE__ */ new Map();
337
+ for (const e of enums) {
338
+ const existing = enumMap.get(e.name);
339
+ if (existing) for (const value of e.enum) existing.add(value);
340
+ else enumMap.set(e.name, new Set(e.enum));
341
+ }
342
+ return Array.from(enumMap.entries()).map(([name, values]) => ({
343
+ name,
344
+ enum: Array.from(values)
345
+ }));
346
+ }
347
+ /**
348
+ * Finds the first occurrence of a matching enum schema in an array.
349
+ * @param a - The enum schema to find.
350
+ * @param enums - Array of enum schemas to search.
351
+ * @returns - The found schema or undefined.
352
+ */
353
+ static findSameSchema(a, enums) {
354
+ return enums.find((b) => Base.isSameEnum(b, a));
355
+ }
356
+ /**
357
+ * Checks if an object is a reference object.
358
+ * @param schema - The object to check.
359
+ * @returns - True if the object is a reference.
360
+ */
361
+ static isRef(schema) {
362
+ return typeof schema === "object" && schema !== null && "$ref" in schema && typeof schema.$ref === "string";
363
+ }
411
364
  };
412
-
413
- // src/core/base/Provider.ts
365
+ //#endregion
366
+ //#region src/core/base/Provider.ts
367
+ /**
368
+ * Abstract Provider Class.
369
+ *
370
+ * The Provider class is designed to be extended by specific implementations (e.g., OpenAPI 2 provider, OpenAPI 3 provider).
371
+ * It handles the initialization of the provider and the parsing of documentation into structured data.
372
+ *
373
+ * @example
374
+ *
375
+ * ```ts
376
+ * /// Example of how this class might be used by a subclass:
377
+ * class OpenAPIProvider extends Provider {
378
+ * /// Implement the parse method to handle OpenAPI-specific documentation parsing.
379
+ * parse(doc: unknown): ProviderInitResult {
380
+ * /// Implementation details...
381
+ * }
382
+ * }
383
+ *
384
+ * /// Initializing a provider with configuration and documentation data:
385
+ * const initOptions: ProviderInitOptions = {
386
+ * docURL: "https://example.com/api/swagger.json",
387
+ * baseURL: "https://api.example.com",
388
+ * output: "./generated",
389
+ * requestOptions: {
390
+ * headers: { "Content-Type": "application/json" },
391
+ * },
392
+ * importClientSource: "generated/client",
393
+ * };
394
+ *
395
+ * const docData = fetchSwaggerDoc();
396
+ * const provider = new OpenAPIProvider(initOptions, docData);
397
+ * ```
398
+ */
414
399
  var Provider = class {
415
- /** collection of enum schemas */
416
- enums = [];
417
- /** collection of schemas indexed by name */
418
- schemas = {};
419
- /** collection of parameters indexed by name */
420
- parameters = {};
421
- /** collection of API responses indexed by name */
422
- responses = {};
423
- /** collection of request bodies indexed by name */
424
- requestBodies = {};
425
- /** collection of API endpoints (operations) indexed by path */
426
- apis = {};
427
- /** URL for fetching API documentation */
428
- docURL;
429
- /** base URL for API endpoints */
430
- baseURL;
431
- /** output directory for generated code */
432
- output;
433
- /** request options for API documentation fetch */
434
- requestOptions;
435
- /** source path for imported client */
436
- importClientSource;
437
- /**
438
- * Provider Constructor.
439
- * @param {ProviderInitOptions} initOptions - Initial configuration for the provider.
440
- * @param {unknown} doc - Raw API documentation data to be parsed.
441
- */
442
- constructor(initOptions, doc) {
443
- this.docURL = initOptions.docURL;
444
- this.baseURL = initOptions.baseURL ?? "";
445
- this.output = initOptions.output ?? ".";
446
- this.requestOptions = initOptions.requestOptions ?? {};
447
- this.importClientSource = initOptions.importClientSource ?? "";
448
- const { enums, schemas, requestBodies, responses, parameters, apis } = this.parse(doc);
449
- this.enums = enums;
450
- this.schemas = schemas;
451
- this.responses = responses;
452
- this.parameters = parameters;
453
- this.requestBodies = requestBodies;
454
- this.apis = apis;
455
- }
400
+ /** collection of enum schemas */
401
+ enums = [];
402
+ /** collection of schemas indexed by name */
403
+ schemas = {};
404
+ /** collection of parameters indexed by name */
405
+ parameters = {};
406
+ /** collection of API responses indexed by name */
407
+ responses = {};
408
+ /** collection of request bodies indexed by name */
409
+ requestBodies = {};
410
+ /** collection of API endpoints (operations) indexed by path */
411
+ apis = {};
412
+ /** URL for fetching API documentation */
413
+ docURL;
414
+ /** base URL for API endpoints */
415
+ baseURL;
416
+ /** output directory for generated code */
417
+ output;
418
+ /** request options for API documentation fetch */
419
+ requestOptions;
420
+ /** source path for imported client */
421
+ importClientSource;
422
+ /**
423
+ * Provider Constructor.
424
+ * @param {ProviderInitOptions} initOptions - Initial configuration for the provider.
425
+ * @param {unknown} doc - Raw API documentation data to be parsed.
426
+ */
427
+ constructor(initOptions, doc) {
428
+ this.docURL = initOptions.docURL;
429
+ this.baseURL = initOptions.baseURL ?? "";
430
+ this.output = initOptions.output ?? ".";
431
+ this.requestOptions = initOptions.requestOptions ?? {};
432
+ this.importClientSource = initOptions.importClientSource ?? "";
433
+ const { enums, schemas, requestBodies, responses, parameters, apis } = this.parse(doc);
434
+ this.enums = enums;
435
+ this.schemas = schemas;
436
+ this.responses = responses;
437
+ this.parameters = parameters;
438
+ this.requestBodies = requestBodies;
439
+ this.apis = apis;
440
+ }
456
441
  };
457
-
458
- // src/core/generator/index.ts
459
- var import_promises = require("fs/promises");
460
- var import_prettier = require("prettier");
461
- var import_typescript = require("typescript");
462
- var Generator = class _Generator {
463
- /**
464
- * Converts an array of TypeScript statements into a formatted string of code.
465
- *
466
- * @param statements - The array of TypeScript statement nodes.
467
- * @returns Formatted code as a string.
468
- * @throws {Error} If no valid statements are provided.
469
- */
470
- static toCode(statements) {
471
- if (statements.length === 0) {
472
- return "// No api declaration found.";
473
- }
474
- const sourceFile = import_typescript.factory.createSourceFile(
475
- statements,
476
- import_typescript.factory.createToken(import_typescript.SyntaxKind.EndOfFileToken),
477
- import_typescript.NodeFlags.None
478
- );
479
- return (0, import_typescript.createPrinter)().printFile(sourceFile);
480
- }
481
- static async write(code, filepath) {
482
- try {
483
- await (0, import_promises.writeFile)(filepath, code);
484
- } catch (error) {
485
- console.error(error);
486
- }
487
- }
488
- /**
489
- * Converts a path string with parameters into a TypeScript template expression.
490
- * Handles query parameters and path placeholders.
491
- *
492
- * @param path - The base path string containing placeholders.
493
- * @param parameters - Array of parameter objects defining the parameters.
494
- * @param basePath - Optional base path to prepend (default: "").
495
- * @returns A TypeScript template expressi
496
- */
497
- static toUrlTemplate(path, parameters, basePath = "") {
498
- const queryParameters = parameters.filter(
499
- (p) => p.in === "query" /* query */
500
- );
501
- if (queryParameters.length > 0) {
502
- const queryString = queryParameters.map(
503
- (qp, index) => `${index === 0 ? "?" : "&"}${encodeURIComponent(qp.name)}={${Base.camelCase(Base.normalize(qp.name))}}`
504
- ).join("");
505
- path += queryString;
506
- }
507
- const pathSegments = path.replaceAll("{", "${").split("$").filter(Boolean);
508
- if (pathSegments.length === 1) {
509
- return import_typescript.factory.createNoSubstitutionTemplateLiteral(basePath + path);
510
- }
511
- return import_typescript.factory.createTemplateExpression(
512
- import_typescript.factory.createTemplateHead(basePath + pathSegments[0]),
513
- pathSegments.slice(1).map((segment, index) => {
514
- const match = /^{(.+)}(.+)?/gm.exec(segment);
515
- const isLastSegment = index === pathSegments.length - 2;
516
- if (!match) {
517
- throw new Error(`Invalid path segment: ${segment}`);
518
- }
519
- return import_typescript.factory.createTemplateSpan(
520
- import_typescript.factory.createIdentifier(match[1]),
521
- !isLastSegment ? import_typescript.factory.createTemplateMiddle(match[2]) : import_typescript.factory.createTemplateTail(match[2] || "")
522
- );
523
- })
524
- );
525
- }
526
- /**
527
- * Adds synthetic comments to a TypeScript AST node.
528
- *
529
- * @param node - The target AST node.
530
- * @param comments - Array of comment objects to add.
531
- */
532
- static addComments(node, comments) {
533
- if (!Array.isArray(comments) || comments.filter(Boolean).length === 0)
534
- return;
535
- const formatComment = (comment) => {
536
- return comment.tag ? ` @${comment.tag} ${comment.comment ?? ""}` : ` ${comment.comment}`;
537
- };
538
- const formattedComments = "*\n" + comments.map(formatComment).join("\n").trim() + "\n";
539
- (0, import_typescript.addSyntheticLeadingComment)(
540
- node,
541
- import_typescript.SyntaxKind.MultiLineCommentTrivia,
542
- formattedComments,
543
- true
544
- );
545
- }
546
- /**
547
- * Checks if a schema represents a binary type.
548
- *
549
- * @param schema - The schema object to check.
550
- * @returns true if the schema is a binary type, false otherwise.
551
- */
552
- static isBinarySchema(schema) {
553
- if (schema.type === "array") {
554
- const arraySchema = schema;
555
- return this.isBinarySchema(arraySchema.items);
556
- }
557
- const nonArraySchema = schema;
558
- return nonArraySchema.format === "blob" /* blob */ || nonArraySchema.format === "binary" /* binary */ || nonArraySchema.type === "file" /* file */;
559
- }
560
- static toRequestBodyTypeNode(schema) {
561
- return import_typescript.factory.createParameterDeclaration(
562
- void 0,
563
- void 0,
564
- import_typescript.factory.createIdentifier("req"),
565
- void 0,
566
- this.toTypeNode(schema)
567
- );
568
- }
569
- static toTypeNode(schema) {
570
- const { type, ref } = schema;
571
- if (ref) {
572
- const identify = Base.ref2name(ref);
573
- return import_typescript.factory.createTypeReferenceNode(
574
- import_typescript.factory.createIdentifier(
575
- identify === "unknown" ? identify : Base.upperCamelCase(identify)
576
- )
577
- );
578
- }
579
- switch (type) {
580
- case "array" /* array */:
581
- const { items } = schema;
582
- return import_typescript.factory.createArrayTypeNode(this.toTypeNode(items));
583
- case "object" /* object */:
584
- const propsCount = Object.keys(schema.properties ?? {}).length;
585
- if (!schema.properties || propsCount === 0) {
586
- return import_typescript.factory.createTypeReferenceNode(import_typescript.factory.createIdentifier("Record"), [
587
- import_typescript.factory.createToken(import_typescript.SyntaxKind.StringKeyword),
588
- import_typescript.factory.createToken(import_typescript.SyntaxKind.UnknownKeyword)
589
- ]);
590
- }
591
- const props = Object.keys(schema.properties);
592
- return import_typescript.factory.createTypeLiteralNode(
593
- props.map((propKey) => {
594
- const propSchema = schema.properties[propKey];
595
- return import_typescript.factory.createPropertySignature(
596
- void 0,
597
- import_typescript.factory.createStringLiteral(propKey),
598
- // When field is required, a refrence or binary value, don't add question mark.
599
- schema.required || schema.ref || this.isBinarySchema(schema) ? void 0 : import_typescript.factory.createToken(import_typescript.SyntaxKind.QuestionToken),
600
- this.toTypeNode(propSchema)
601
- );
602
- })
603
- );
604
- case "integer" /* integer */:
605
- case "number" /* number */:
606
- if (schema.enum) {
607
- return import_typescript.factory.createUnionTypeNode(
608
- schema.enum.map(
609
- (e) => import_typescript.factory.createLiteralTypeNode(import_typescript.factory.createNumericLiteral(e))
610
- )
611
- );
612
- }
613
- return import_typescript.factory.createToken(import_typescript.SyntaxKind.NumberKeyword);
614
- // case NonArraySchemaType.string:
615
- case "boolean" /* boolean */:
616
- return import_typescript.factory.createToken(import_typescript.SyntaxKind.BooleanKeyword);
617
- case "file" /* file */:
618
- return import_typescript.factory.createTypeReferenceNode(import_typescript.factory.createIdentifier("Blob"));
619
- default:
620
- const {
621
- format: format2,
622
- oneOf,
623
- allOf,
624
- anyOf,
625
- type: type2,
626
- enum: enum_
627
- } = schema;
628
- switch (format2) {
629
- case "number" /* number */:
630
- return import_typescript.factory.createToken(import_typescript.SyntaxKind.NumberKeyword);
631
- case "string" /* string */:
632
- return import_typescript.factory.createToken(import_typescript.SyntaxKind.StringKeyword);
633
- case "boolean" /* boolean */:
634
- return import_typescript.factory.createToken(import_typescript.SyntaxKind.BooleanKeyword);
635
- case "blob" /* blob */:
636
- case "binary" /* binary */:
637
- return import_typescript.factory.createTypeReferenceNode(import_typescript.factory.createIdentifier("Blob"));
638
- default:
639
- }
640
- if (enum_) {
641
- return import_typescript.factory.createUnionTypeNode(
642
- enum_.map(
643
- (e) => import_typescript.factory.createLiteralTypeNode(import_typescript.factory.createStringLiteral(e))
644
- )
645
- );
646
- }
647
- if (type2 === "string" /* string */) {
648
- return import_typescript.factory.createToken(import_typescript.SyntaxKind.StringKeyword);
649
- }
650
- if (oneOf) {
651
- return import_typescript.factory.createUnionTypeNode(
652
- oneOf.map((schema2) => this.toTypeNode(schema2))
653
- );
654
- }
655
- if (anyOf) {
656
- return import_typescript.factory.createUnionTypeNode(
657
- anyOf.map((schema2) => this.toTypeNode(schema2))
658
- );
659
- }
660
- if (allOf) {
661
- return import_typescript.factory.createIntersectionTypeNode(
662
- allOf.map((schema2) => this.toTypeNode(schema2))
663
- );
664
- }
665
- if (type2 && typeof type2 === "string") {
666
- return import_typescript.factory.createTypeReferenceNode(
667
- type2 !== "unknown" && type2 !== "null" ? import_typescript.factory.createIdentifier(Base.upperCamelCase(type2)) : type2
668
- );
669
- }
670
- }
671
- return import_typescript.factory.createToken(import_typescript.SyntaxKind.UnknownKeyword);
672
- }
673
- static toDeclarationNodes(parameters) {
674
- const objectElements = [];
675
- const typeObjectElements = [];
676
- const refParameters = [];
677
- for (const parameter of parameters) {
678
- if (parameter.ref) {
679
- const refName = Base.ref2name(parameter.ref);
680
- refParameters.push(
681
- import_typescript.factory.createParameterDeclaration(
682
- void 0,
683
- void 0,
684
- import_typescript.factory.createIdentifier(Base.camelCase(Base.normalize(refName))),
685
- void 0,
686
- import_typescript.factory.createTypeReferenceNode(
687
- import_typescript.factory.createIdentifier(Base.upperCamelCase(Base.normalize(refName)))
688
- ),
689
- void 0
690
- )
691
- );
692
- } else {
693
- const { name, schema, required } = parameter;
694
- objectElements.push(
695
- import_typescript.factory.createBindingElement(
696
- void 0,
697
- void 0,
698
- import_typescript.factory.createIdentifier(Base.camelCase(Base.normalize(name)))
699
- )
700
- );
701
- typeObjectElements.push(
702
- import_typescript.factory.createPropertySignature(
703
- [],
704
- import_typescript.factory.createIdentifier(Base.camelCase(Base.normalize(name))),
705
- required ? void 0 : import_typescript.factory.createToken(import_typescript.SyntaxKind.QuestionToken),
706
- !schema ? import_typescript.factory.createToken(import_typescript.SyntaxKind.UnknownKeyword) : this.toTypeNode(schema)
707
- )
708
- );
709
- }
710
- }
711
- if (objectElements.length > 0) {
712
- const objectParam = import_typescript.factory.createParameterDeclaration(
713
- void 0,
714
- void 0,
715
- import_typescript.factory.createObjectBindingPattern(objectElements),
716
- void 0,
717
- import_typescript.factory.createTypeLiteralNode(typeObjectElements),
718
- void 0
719
- );
720
- return [objectParam, ...refParameters];
721
- }
722
- return refParameters;
723
- }
724
- static toFormDataStatement(parameters, requestBody) {
725
- const statements = [];
726
- const fdDeclaration = import_typescript.factory.createVariableStatement(
727
- void 0,
728
- import_typescript.factory.createVariableDeclarationList(
729
- [
730
- import_typescript.factory.createVariableDeclaration(
731
- import_typescript.factory.createIdentifier("fd"),
732
- void 0,
733
- void 0,
734
- import_typescript.factory.createNewExpression(
735
- import_typescript.factory.createIdentifier("FormData"),
736
- void 0,
737
- []
738
- )
739
- )
740
- ],
741
- import_typescript.NodeFlags.Const
742
- )
743
- );
744
- statements.push(fdDeclaration);
745
- parameters.forEach((parameter) => {
746
- statements.push(
747
- import_typescript.factory.createExpressionStatement(
748
- import_typescript.factory.createBinaryExpression(
749
- import_typescript.factory.createIdentifier(parameter.name),
750
- import_typescript.factory.createToken(import_typescript.SyntaxKind.AmpersandAmpersandToken),
751
- import_typescript.factory.createCallExpression(
752
- import_typescript.factory.createPropertyAccessExpression(
753
- import_typescript.factory.createIdentifier("fd"),
754
- import_typescript.factory.createIdentifier("append")
755
- ),
756
- void 0,
757
- [
758
- import_typescript.factory.createStringLiteral(parameter.name),
759
- import_typescript.factory.createIdentifier(parameter.name)
760
- ]
761
- )
762
- )
763
- )
764
- );
765
- });
766
- if (requestBody && requestBody.type === "object" && requestBody.properties && Object.keys(requestBody.properties).length !== 0) {
767
- Object.keys(requestBody.properties).forEach((key) => {
768
- const schemaByKey = requestBody.properties[key];
769
- if (schemaByKey.type === "array" /* array */ && this.isBinarySchema(schemaByKey)) {
770
- statements.push(
771
- import_typescript.factory.createForOfStatement(
772
- void 0,
773
- import_typescript.factory.createVariableDeclarationList(
774
- [import_typescript.factory.createVariableDeclaration("file")],
775
- import_typescript.NodeFlags.Const
776
- ),
777
- import_typescript.factory.createElementAccessExpression(
778
- import_typescript.factory.createIdentifier("req"),
779
- import_typescript.factory.createStringLiteral(key)
780
- ),
781
- import_typescript.factory.createBlock([
782
- import_typescript.factory.createExpressionStatement(
783
- import_typescript.factory.createCallExpression(
784
- import_typescript.factory.createPropertyAccessExpression(
785
- import_typescript.factory.createIdentifier("fd"),
786
- import_typescript.factory.createIdentifier("append")
787
- ),
788
- [],
789
- [
790
- import_typescript.factory.createStringLiteral(key),
791
- import_typescript.factory.createIdentifier("file"),
792
- import_typescript.factory.createPropertyAccessExpression(
793
- import_typescript.factory.createAsExpression(
794
- import_typescript.factory.createIdentifier("file"),
795
- import_typescript.factory.createTypeReferenceNode(
796
- import_typescript.factory.createIdentifier("File"),
797
- void 0
798
- )
799
- ),
800
- import_typescript.factory.createIdentifier("name")
801
- )
802
- ]
803
- )
804
- )
805
- ])
806
- )
807
- );
808
- } else {
809
- if (schemaByKey.required) {
810
- statements.push(
811
- import_typescript.factory.createExpressionStatement(
812
- import_typescript.factory.createCallExpression(
813
- import_typescript.factory.createPropertyAccessExpression(
814
- import_typescript.factory.createIdentifier("fd"),
815
- import_typescript.factory.createIdentifier("append")
816
- ),
817
- void 0,
818
- [
819
- import_typescript.factory.createStringLiteral(key),
820
- schemaByKey.type === "string" ? import_typescript.factory.createElementAccessExpression(
821
- import_typescript.factory.createIdentifier("req"),
822
- import_typescript.factory.createStringLiteral(key)
823
- ) : import_typescript.factory.createCallExpression(
824
- import_typescript.factory.createIdentifier("String"),
825
- void 0,
826
- [
827
- import_typescript.factory.createElementAccessExpression(
828
- import_typescript.factory.createIdentifier("req"),
829
- import_typescript.factory.createStringLiteral(key)
830
- )
831
- ]
832
- )
833
- ]
834
- )
835
- )
836
- );
837
- } else {
838
- statements.push(
839
- import_typescript.factory.createExpressionStatement(
840
- import_typescript.factory.createBinaryExpression(
841
- import_typescript.factory.createElementAccessExpression(
842
- import_typescript.factory.createIdentifier("req"),
843
- import_typescript.factory.createStringLiteral(key)
844
- ),
845
- import_typescript.factory.createToken(import_typescript.SyntaxKind.AmpersandAmpersandToken),
846
- import_typescript.factory.createCallExpression(
847
- import_typescript.factory.createPropertyAccessExpression(
848
- import_typescript.factory.createIdentifier("fd"),
849
- import_typescript.factory.createIdentifier("append")
850
- ),
851
- void 0,
852
- [
853
- import_typescript.factory.createStringLiteral(key),
854
- schemaByKey.type === "string" ? import_typescript.factory.createElementAccessExpression(
855
- import_typescript.factory.createIdentifier("req"),
856
- import_typescript.factory.createStringLiteral(key)
857
- ) : import_typescript.factory.createCallExpression(
858
- import_typescript.factory.createIdentifier("String"),
859
- void 0,
860
- [
861
- import_typescript.factory.createElementAccessExpression(
862
- import_typescript.factory.createIdentifier("req"),
863
- import_typescript.factory.createStringLiteral(key)
864
- )
865
- ]
866
- )
867
- ]
868
- )
869
- )
870
- )
871
- );
872
- }
873
- }
874
- });
875
- }
876
- return statements;
877
- }
878
- static bodyBlock(uri, method, parameters, requestBody, response, adapter) {
879
- const isFormDataRequest = requestBody && ["multipart/form-data", "application/x-www-form-urlencoded"].includes(
880
- requestBody.type
881
- );
882
- const shouldParseResponseToJSON = "application/json" === response?.type;
883
- const isRequestBodyBinary = requestBody?.schema && requestBody.schema.type === "array" /* array */ && this.isBinarySchema(requestBody.schema);
884
- const parametersShouldPutInFormData = parameters.filter(
885
- (p) => p.in === "formData" /* formData */ || p.schema && this.isBinarySchema(p.schema)
886
- );
887
- const parametersShouldNotPutInFormData = parameters.filter(
888
- (p) => !parametersShouldPutInFormData.includes(p)
889
- );
890
- const isRequestBodyContainsBinary = requestBody?.schema && "properties" in requestBody.schema && Object.values(requestBody.schema?.properties ?? {}).some(
891
- (p) => this.isBinarySchema(p)
892
- );
893
- const hasBinaryInParameters = parameters.some(
894
- (p) => p?.schema && this.isBinarySchema(p.schema)
895
- );
896
- const shouldPutParametersOrBodyInFormData = isFormDataRequest || isRequestBodyBinary || hasBinaryInParameters || isRequestBodyContainsBinary || parametersShouldPutInFormData.length > 0;
897
- return import_typescript.factory.createBlock([
898
- ...shouldPutParametersOrBodyInFormData ? this.toFormDataStatement(
899
- parametersShouldPutInFormData,
900
- requestBody?.schema
901
- ) : [],
902
- ...adapter.client(
903
- uri,
904
- method,
905
- parametersShouldNotPutInFormData,
906
- requestBody,
907
- response,
908
- adapter,
909
- shouldPutParametersOrBodyInFormData,
910
- shouldParseResponseToJSON
911
- )
912
- ]);
913
- }
914
- static schemaToStatemets(parsedDoc, adaptor, options) {
915
- const statements = [];
916
- const { apis, schemas = {}, enums } = parsedDoc;
917
- const enumNames = [];
918
- for (const enumObject of enums) {
919
- enumNames.push(Base.capitalize(enumObject.name));
920
- statements.push(
921
- import_typescript.factory.createEnumDeclaration(
922
- [import_typescript.factory.createToken(import_typescript.SyntaxKind.ExportKeyword)],
923
- import_typescript.factory.createIdentifier(Base.upperCamelCase(enumObject.name)),
924
- enumObject.enum.map((member) => {
925
- return import_typescript.factory.createEnumMember(
926
- import_typescript.factory.createStringLiteral(
927
- typeof member === "string" ? member : `${member}_`
928
- ),
929
- typeof member === "string" ? import_typescript.factory.createStringLiteral(member) : import_typescript.factory.createNumericLiteral(member)
930
- );
931
- })
932
- )
933
- );
934
- }
935
- for (const schemaKey in schemas) {
936
- if (Object.hasOwnProperty.call(schemas, schemaKey) && !enumNames.includes(Base.upperCamelCase(schemaKey))) {
937
- const schema = schemas[schemaKey];
938
- statements.push(
939
- import_typescript.factory.createTypeAliasDeclaration(
940
- [import_typescript.factory.createModifier(import_typescript.SyntaxKind.ExportKeyword)],
941
- import_typescript.factory.createIdentifier(Base.upperCamelCase(schemaKey)),
942
- void 0,
943
- this.toTypeNode(schema)
944
- )
945
- );
946
- }
947
- }
948
- for (const uri in apis) {
949
- const operations = apis[uri];
950
- for (const operation of operations) {
951
- const {
952
- method,
953
- operationId,
954
- requestBody = [],
955
- responses = [],
956
- summary,
957
- deprecated,
958
- description
959
- } = operation;
960
- let { parameters = [] } = operation;
961
- parameters = parameters.filter((p) => p.in !== "cookie");
962
- if (requestBody.length === 0) {
963
- requestBody.push({ type: "application/json" /* JSON */ });
964
- }
965
- const shouldAddExtraMethodNameSuffix = requestBody.length > 1;
966
- for (const req of requestBody) {
967
- const statement = import_typescript.factory.createFunctionDeclaration(
968
- [
969
- import_typescript.factory.createModifier(import_typescript.SyntaxKind.ExportKeyword),
970
- import_typescript.factory.createModifier(import_typescript.SyntaxKind.AsyncKeyword)
971
- ],
972
- void 0,
973
- Base.pathToFnName(uri, method, operationId) + (shouldAddExtraMethodNameSuffix ? Base.capitalize(req.type.split("/")[1]) : ""),
974
- void 0,
975
- [
976
- ...parameters.length > 0 ? _Generator.toDeclarationNodes(parameters) : [],
977
- ...req?.schema ? [_Generator.toRequestBodyTypeNode(req.schema)] : []
978
- ].filter(Boolean),
979
- void 0,
980
- this.bodyBlock(
981
- options.baseURL + uri,
982
- method,
983
- parameters,
984
- req,
985
- responses[0],
986
- adaptor
987
- )
988
- );
989
- this.addComments(
990
- statement,
991
- [
992
- description && {
993
- comment: description
994
- },
995
- summary && {
996
- comment: summary
997
- },
998
- deprecated && {
999
- tag: "deprecated"
1000
- }
1001
- ].filter(Boolean)
1002
- );
1003
- statements.push(statement);
1004
- }
1005
- }
1006
- }
1007
- return statements;
1008
- }
1009
- static async prettier(code) {
1010
- return await (0, import_prettier.format)(code, {
1011
- parser: "typescript"
1012
- });
1013
- }
1014
- static async genCode(schema, initOptions, adaptor) {
1015
- const { importClientSource } = initOptions;
1016
- const statements = this.schemaToStatemets(schema, adaptor, {
1017
- baseURL: initOptions.baseURL ?? ""
1018
- });
1019
- let code = this.toCode(statements);
1020
- if (importClientSource) {
1021
- code = importClientSource + "\n\n" + code;
1022
- }
1023
- return await this.prettier(code);
1024
- }
442
+ //#endregion
443
+ //#region src/core/generator/index.ts
444
+ var Generator = class Generator {
445
+ /**
446
+ * Converts an array of TypeScript statements into a formatted string of code.
447
+ *
448
+ * @param statements - The array of TypeScript statement nodes.
449
+ * @returns Formatted code as a string.
450
+ * @throws {Error} If no valid statements are provided.
451
+ */
452
+ static toCode(statements) {
453
+ if (statements.length === 0) return "// No api declaration found.";
454
+ const sourceFile = typescript.factory.createSourceFile(statements, typescript.factory.createToken(typescript.SyntaxKind.EndOfFileToken), typescript.NodeFlags.None);
455
+ return (0, typescript.createPrinter)().printFile(sourceFile);
456
+ }
457
+ static async write(code, filepath) {
458
+ try {
459
+ await (0, node_fs_promises.writeFile)(filepath, code);
460
+ } catch (error) {
461
+ console.error(error);
462
+ }
463
+ }
464
+ /**
465
+ * Converts a path string with parameters into a TypeScript template expression.
466
+ * Handles query parameters and path placeholders.
467
+ *
468
+ * @param path - The base path string containing placeholders.
469
+ * @param parameters - Array of parameter objects defining the parameters.
470
+ * @param basePath - Optional base path to prepend (default: "").
471
+ * @returns A TypeScript template expressi
472
+ */
473
+ static toUrlTemplate(path, parameters, basePath = "") {
474
+ const queryParameters = parameters.filter((p) => p.in === "query");
475
+ if (queryParameters.length > 0) {
476
+ const queryString = queryParameters.map((qp, index) => `${index === 0 ? "?" : "&"}${encodeURIComponent(qp.name)}={${Base.camelCase(Base.normalize(qp.name))}}`).join("");
477
+ path += queryString;
478
+ }
479
+ const pathSegments = path.replaceAll("{", "${").split("$").filter(Boolean);
480
+ if (pathSegments.length === 1) return typescript.factory.createNoSubstitutionTemplateLiteral(basePath + path);
481
+ return typescript.factory.createTemplateExpression(typescript.factory.createTemplateHead(basePath + pathSegments[0]), pathSegments.slice(1).map((segment, index) => {
482
+ const match = /^{(.+)}(.+)?/gm.exec(segment);
483
+ const isLastSegment = index === pathSegments.length - 2;
484
+ if (!match) throw new Error(`Invalid path segment: ${segment}`);
485
+ return typescript.factory.createTemplateSpan(typescript.factory.createIdentifier(match[1]), !isLastSegment ? typescript.factory.createTemplateMiddle(match[2]) : typescript.factory.createTemplateTail(match[2] || ""));
486
+ }));
487
+ }
488
+ /**
489
+ * Adds synthetic comments to a TypeScript AST node.
490
+ *
491
+ * @param node - The target AST node.
492
+ * @param comments - Array of comment objects to add.
493
+ */
494
+ static addComments(node, comments) {
495
+ if (!Array.isArray(comments) || comments.filter(Boolean).length === 0) return;
496
+ const formatComment = (comment) => {
497
+ if (comment.tag === "returns") return `* @returns {${comment.type}} ${comment.comment ?? ""}`;
498
+ if (comment.tag === "param") return comment.comment ? `* @param ${comment.paramName} - ${comment.comment}` : `* @param ${comment.paramName}`;
499
+ if (comment.tag) return `* @${comment.tag} ${comment.comment ?? ""}`;
500
+ return `* ${comment.comment}`;
501
+ };
502
+ const formattedComments = comments.map(formatComment).join("\n").trim() + "\n";
503
+ (0, typescript.addSyntheticLeadingComment)(node, typescript.SyntaxKind.MultiLineCommentTrivia, formattedComments, true);
504
+ }
505
+ /**
506
+ * Checks if a schema represents a binary type.
507
+ *
508
+ * @param schema - The schema object to check.
509
+ * @returns true if the schema is a binary type, false otherwise.
510
+ */
511
+ static isBinarySchema(schema) {
512
+ if (schema.type === "array") {
513
+ const arraySchema = schema;
514
+ return Generator.isBinarySchema(arraySchema.items);
515
+ }
516
+ const nonArraySchema = schema;
517
+ return nonArraySchema.format === "blob" || nonArraySchema.format === "binary" || nonArraySchema.type === "file";
518
+ }
519
+ static schemaToTypeString(schema) {
520
+ if (schema.type === "array") {
521
+ const arraySchema = schema;
522
+ return arraySchema.items ? `${Generator.schemaToTypeString(arraySchema.items)}[]` : "unknown";
523
+ }
524
+ const singleSchema = schema;
525
+ if (schema.type === "string") return "string";
526
+ if (schema.type === "number" || schema.type === "integer") return "number";
527
+ if (schema.type === "boolean") return "boolean";
528
+ if (schema.type === "object" || schema.properties) return "object";
529
+ if (singleSchema.format === "binary" || singleSchema.type === "file") return "Blob";
530
+ if (singleSchema.format === "blob") return "Blob";
531
+ if (singleSchema.ref) return singleSchema.ref;
532
+ return "unknown";
533
+ }
534
+ static generateParamTags(parameters, requestBody) {
535
+ const tags = [];
536
+ for (const p of parameters) {
537
+ const paramName = Base.camelCase(Base.normalize(p.name));
538
+ let paramType = "unknown";
539
+ if (p.schema) paramType = Generator.schemaToTypeString(p.schema);
540
+ const isOptional = p.required === false;
541
+ tags.push({
542
+ tag: "param",
543
+ paramName,
544
+ type: `${paramType}${isOptional ? " | undefined" : ""}`,
545
+ comment: p.description ?? ""
546
+ });
547
+ }
548
+ if (requestBody?.schema && "properties" in requestBody.schema) {
549
+ const properties = requestBody.schema.properties;
550
+ const required = requestBody.schema.required;
551
+ const requiredArray = Array.isArray(required) ? required : [];
552
+ for (const [key, schema] of Object.entries(properties ?? {})) {
553
+ const paramName = `req.${key}`;
554
+ const paramType = Generator.schemaToTypeString(schema);
555
+ const isOptional = !requiredArray.includes(key);
556
+ tags.push({
557
+ tag: "param",
558
+ paramName,
559
+ type: `${paramType}${isOptional ? " | undefined" : ""}`,
560
+ comment: schema.description ?? ""
561
+ });
562
+ }
563
+ }
564
+ return tags;
565
+ }
566
+ static toRequestBodyTypeNode(schema) {
567
+ return typescript.factory.createParameterDeclaration(void 0, void 0, typescript.factory.createIdentifier("req"), void 0, Generator.toTypeNode(schema));
568
+ }
569
+ static toTypeNode(schema) {
570
+ const { type, ref } = schema;
571
+ if (ref) {
572
+ const identify = Base.ref2name(ref);
573
+ return typescript.factory.createTypeReferenceNode(typescript.factory.createIdentifier(identify === "unknown" ? identify : Base.upperCamelCase(identify)));
574
+ }
575
+ switch (type) {
576
+ case "array": {
577
+ const { items } = schema;
578
+ return typescript.factory.createArrayTypeNode(Generator.toTypeNode(items));
579
+ }
580
+ case "object": {
581
+ const propsCount = Object.keys(schema.properties ?? {}).length;
582
+ if (!schema.properties || propsCount === 0) return typescript.factory.createTypeReferenceNode(typescript.factory.createIdentifier("Record"), [typescript.factory.createToken(typescript.SyntaxKind.StringKeyword), typescript.factory.createToken(typescript.SyntaxKind.UnknownKeyword)]);
583
+ const props = Object.keys(schema.properties);
584
+ return typescript.factory.createTypeLiteralNode(props.map((propKey) => {
585
+ const propSchema = schema.properties[propKey];
586
+ return typescript.factory.createPropertySignature(void 0, typescript.factory.createStringLiteral(propKey), schema.required || schema.ref || Generator.isBinarySchema(schema) ? void 0 : typescript.factory.createToken(typescript.SyntaxKind.QuestionToken), Generator.toTypeNode(propSchema));
587
+ }));
588
+ }
589
+ case "integer":
590
+ case "number":
591
+ if (schema.enum) return typescript.factory.createUnionTypeNode(schema.enum.map((e) => typescript.factory.createLiteralTypeNode(typescript.factory.createNumericLiteral(e))));
592
+ return typescript.factory.createToken(typescript.SyntaxKind.NumberKeyword);
593
+ case "boolean": return typescript.factory.createToken(typescript.SyntaxKind.BooleanKeyword);
594
+ case "file": return typescript.factory.createTypeReferenceNode(typescript.factory.createIdentifier("Blob"));
595
+ default: {
596
+ const { format, oneOf, allOf, anyOf, type, enum: enum_ } = schema;
597
+ switch (format) {
598
+ case "number": return typescript.factory.createToken(typescript.SyntaxKind.NumberKeyword);
599
+ case "string": return typescript.factory.createToken(typescript.SyntaxKind.StringKeyword);
600
+ case "boolean": return typescript.factory.createToken(typescript.SyntaxKind.BooleanKeyword);
601
+ case "blob":
602
+ case "binary": return typescript.factory.createTypeReferenceNode(typescript.factory.createIdentifier("Blob"));
603
+ default:
604
+ }
605
+ if (enum_) return typescript.factory.createUnionTypeNode(enum_.map((e) => typescript.factory.createLiteralTypeNode(typescript.factory.createStringLiteral(e))));
606
+ if (type === "string") return typescript.factory.createToken(typescript.SyntaxKind.StringKeyword);
607
+ if (oneOf) return typescript.factory.createUnionTypeNode(oneOf.map((schema) => Generator.toTypeNode(schema)));
608
+ if (anyOf) return typescript.factory.createUnionTypeNode(anyOf.map((schema) => Generator.toTypeNode(schema)));
609
+ if (allOf) return typescript.factory.createIntersectionTypeNode(allOf.map((schema) => Generator.toTypeNode(schema)));
610
+ if (type && typeof type === "string") return typescript.factory.createTypeReferenceNode(type !== "unknown" && type !== "null" ? typescript.factory.createIdentifier(Base.upperCamelCase(type)) : type);
611
+ }
612
+ }
613
+ return typescript.factory.createToken(typescript.SyntaxKind.UnknownKeyword);
614
+ }
615
+ static toDeclarationNodes(parameters) {
616
+ const objectElements = [];
617
+ const typeObjectElements = [];
618
+ const refParameters = [];
619
+ for (const parameter of parameters) if (parameter.ref) {
620
+ const refName = Base.ref2name(parameter.ref);
621
+ refParameters.push(typescript.factory.createParameterDeclaration(void 0, void 0, typescript.factory.createIdentifier(Base.camelCase(Base.normalize(refName))), void 0, typescript.factory.createTypeReferenceNode(typescript.factory.createIdentifier(Base.upperCamelCase(Base.normalize(refName)))), void 0));
622
+ } else {
623
+ const { name, schema, required } = parameter;
624
+ objectElements.push(typescript.factory.createBindingElement(void 0, void 0, typescript.factory.createIdentifier(Base.camelCase(Base.normalize(name)))));
625
+ typeObjectElements.push(typescript.factory.createPropertySignature([], typescript.factory.createIdentifier(Base.camelCase(Base.normalize(name))), required ? void 0 : typescript.factory.createToken(typescript.SyntaxKind.QuestionToken), !schema ? typescript.factory.createToken(typescript.SyntaxKind.UnknownKeyword) : Generator.toTypeNode(schema)));
626
+ }
627
+ if (objectElements.length > 0) return [typescript.factory.createParameterDeclaration(void 0, void 0, typescript.factory.createObjectBindingPattern(objectElements), void 0, typescript.factory.createTypeLiteralNode(typeObjectElements), void 0), ...refParameters];
628
+ return refParameters;
629
+ }
630
+ static toFormDataStatement(parameters, requestBody) {
631
+ const statements = [];
632
+ const fdDeclaration = typescript.factory.createVariableStatement(void 0, typescript.factory.createVariableDeclarationList([typescript.factory.createVariableDeclaration(typescript.factory.createIdentifier("fd"), void 0, void 0, typescript.factory.createNewExpression(typescript.factory.createIdentifier("FormData"), void 0, []))], typescript.NodeFlags.Const));
633
+ statements.push(fdDeclaration);
634
+ parameters.forEach((parameter) => {
635
+ statements.push(typescript.factory.createExpressionStatement(typescript.factory.createBinaryExpression(typescript.factory.createIdentifier(parameter.name), typescript.factory.createToken(typescript.SyntaxKind.AmpersandAmpersandToken), typescript.factory.createCallExpression(typescript.factory.createPropertyAccessExpression(typescript.factory.createIdentifier("fd"), typescript.factory.createIdentifier("append")), void 0, [typescript.factory.createStringLiteral(parameter.name), typescript.factory.createIdentifier(parameter.name)]))));
636
+ });
637
+ if (requestBody && requestBody.type === "object" && requestBody.properties && Object.keys(requestBody.properties).length !== 0) Object.keys(requestBody.properties).forEach((key) => {
638
+ const schemaByKey = requestBody.properties[key];
639
+ if (schemaByKey.type === "array" && Generator.isBinarySchema(schemaByKey)) statements.push(typescript.factory.createForOfStatement(void 0, typescript.factory.createVariableDeclarationList([typescript.factory.createVariableDeclaration("file")], typescript.NodeFlags.Const), typescript.factory.createElementAccessExpression(typescript.factory.createIdentifier("req"), typescript.factory.createStringLiteral(key)), typescript.factory.createBlock([typescript.factory.createExpressionStatement(typescript.factory.createCallExpression(typescript.factory.createPropertyAccessExpression(typescript.factory.createIdentifier("fd"), typescript.factory.createIdentifier("append")), [], [
640
+ typescript.factory.createStringLiteral(key),
641
+ typescript.factory.createIdentifier("file"),
642
+ typescript.factory.createPropertyAccessExpression(typescript.factory.createAsExpression(typescript.factory.createIdentifier("file"), typescript.factory.createTypeReferenceNode(typescript.factory.createIdentifier("File"), void 0)), typescript.factory.createIdentifier("name"))
643
+ ]))])));
644
+ else if (schemaByKey.required) statements.push(typescript.factory.createExpressionStatement(typescript.factory.createCallExpression(typescript.factory.createPropertyAccessExpression(typescript.factory.createIdentifier("fd"), typescript.factory.createIdentifier("append")), void 0, [typescript.factory.createStringLiteral(key), schemaByKey.type === "string" || Generator.isBinarySchema(schemaByKey) || schemaByKey.isRef ? typescript.factory.createElementAccessExpression(typescript.factory.createIdentifier("req"), typescript.factory.createStringLiteral(key)) : schemaByKey.type === "array" || schemaByKey.type === "object" ? typescript.factory.createCallExpression(typescript.factory.createPropertyAccessExpression(typescript.factory.createIdentifier("JSON"), typescript.factory.createIdentifier("stringify")), void 0, [typescript.factory.createElementAccessExpression(typescript.factory.createIdentifier("req"), typescript.factory.createStringLiteral(key))]) : typescript.factory.createCallExpression(typescript.factory.createIdentifier("String"), void 0, [typescript.factory.createElementAccessExpression(typescript.factory.createIdentifier("req"), typescript.factory.createStringLiteral(key))])])));
645
+ else statements.push(typescript.factory.createExpressionStatement(typescript.factory.createBinaryExpression(typescript.factory.createElementAccessExpression(typescript.factory.createIdentifier("req"), typescript.factory.createStringLiteral(key)), typescript.factory.createToken(typescript.SyntaxKind.AmpersandAmpersandToken), typescript.factory.createCallExpression(typescript.factory.createPropertyAccessExpression(typescript.factory.createIdentifier("fd"), typescript.factory.createIdentifier("append")), void 0, [typescript.factory.createStringLiteral(key), schemaByKey.type === "string" || Generator.isBinarySchema(schemaByKey) || schemaByKey.isRef ? typescript.factory.createElementAccessExpression(typescript.factory.createIdentifier("req"), typescript.factory.createStringLiteral(key)) : schemaByKey.type === "array" || schemaByKey.type === "object" ? typescript.factory.createCallExpression(typescript.factory.createPropertyAccessExpression(typescript.factory.createIdentifier("JSON"), typescript.factory.createIdentifier("stringify")), void 0, [typescript.factory.createElementAccessExpression(typescript.factory.createIdentifier("req"), typescript.factory.createStringLiteral(key))]) : typescript.factory.createCallExpression(typescript.factory.createIdentifier("String"), void 0, [typescript.factory.createElementAccessExpression(typescript.factory.createIdentifier("req"), typescript.factory.createStringLiteral(key))])]))));
646
+ });
647
+ return statements;
648
+ }
649
+ static bodyBlock(uri, method, parameters, requestBody, response, adapter) {
650
+ const isFormDataRequest = requestBody && ["multipart/form-data", "application/x-www-form-urlencoded"].includes(requestBody.type);
651
+ const shouldParseResponseToJSON = "application/json" === response?.type;
652
+ const isRequestBodyBinary = requestBody?.schema && requestBody.schema.type === "array" && Generator.isBinarySchema(requestBody.schema);
653
+ const parametersShouldPutInFormData = parameters.filter((p) => p.in === "formData" || p.schema && Generator.isBinarySchema(p.schema));
654
+ const parametersShouldNotPutInFormData = parameters.filter((p) => !parametersShouldPutInFormData.includes(p));
655
+ const isRequestBodyContainsBinary = requestBody?.schema && "properties" in requestBody.schema && Object.values(requestBody.schema?.properties ?? {}).some((p) => Generator.isBinarySchema(p));
656
+ const hasBinaryInParameters = parameters.some((p) => p?.schema && Generator.isBinarySchema(p.schema));
657
+ const shouldPutParametersOrBodyInFormData = !!isFormDataRequest && (isRequestBodyBinary || hasBinaryInParameters || isRequestBodyContainsBinary || parametersShouldPutInFormData.length > 0);
658
+ return typescript.factory.createBlock([...shouldPutParametersOrBodyInFormData ? Generator.toFormDataStatement(parametersShouldPutInFormData, requestBody?.schema) : [], ...adapter.client(uri, method, parametersShouldNotPutInFormData, requestBody, response, adapter, shouldPutParametersOrBodyInFormData, shouldParseResponseToJSON)]);
659
+ }
660
+ static schemaToStatemets(parsedDoc, adaptor, options) {
661
+ const statements = [];
662
+ const { apis, schemas = {}, enums } = parsedDoc;
663
+ const enumNames = [];
664
+ for (const enumObject of enums) {
665
+ enumNames.push(Base.upperCamelCase(enumObject.name));
666
+ statements.push(typescript.factory.createEnumDeclaration([typescript.factory.createToken(typescript.SyntaxKind.ExportKeyword)], typescript.factory.createIdentifier(Base.upperCamelCase(enumObject.name)), enumObject.enum.map((member) => {
667
+ return typescript.factory.createEnumMember(typescript.factory.createStringLiteral(typeof member === "string" ? member : `${member}_`), typeof member === "string" ? typescript.factory.createStringLiteral(member) : typescript.factory.createNumericLiteral(member));
668
+ })));
669
+ }
670
+ for (const schemaKey in schemas) if (Object.hasOwn(schemas, schemaKey) && !enumNames.includes(Base.upperCamelCase(schemaKey))) {
671
+ const schema = schemas[schemaKey];
672
+ statements.push(typescript.factory.createTypeAliasDeclaration([typescript.factory.createModifier(typescript.SyntaxKind.ExportKeyword)], typescript.factory.createIdentifier(Base.upperCamelCase(schemaKey)), void 0, Generator.toTypeNode(schema)));
673
+ }
674
+ for (const uri in apis) {
675
+ const operations = apis[uri];
676
+ for (const operation of operations) {
677
+ const { method, operationId, requestBody = [], responses = [], summary, deprecated, description } = operation;
678
+ let { parameters = [] } = operation;
679
+ parameters = parameters.filter((p) => p.in !== "cookie");
680
+ if (requestBody.length === 0) requestBody.push({ type: "application/json" });
681
+ const shouldAddExtraMethodNameSuffix = requestBody.length > 1;
682
+ for (const req of requestBody) {
683
+ const statement = typescript.factory.createFunctionDeclaration([typescript.factory.createModifier(typescript.SyntaxKind.ExportKeyword), typescript.factory.createModifier(typescript.SyntaxKind.AsyncKeyword)], void 0, Base.pathToFnName(uri, method, operationId) + (shouldAddExtraMethodNameSuffix ? Base.capitalize(req.type.split("/")[1]) : ""), void 0, [...parameters.length > 0 ? Generator.toDeclarationNodes(parameters) : [], ...req?.schema ? [Generator.toRequestBodyTypeNode(req.schema)] : []].filter(Boolean), void 0, Generator.bodyBlock(options.baseURL + uri, method, parameters, req, responses[0], adaptor));
684
+ const mergedDescription = [description, summary].filter(Boolean).join(". ");
685
+ Generator.addComments(statement, [
686
+ mergedDescription && { comment: mergedDescription },
687
+ deprecated && { tag: "deprecated" },
688
+ ...Generator.generateParamTags(parameters, req)
689
+ ].filter(Boolean));
690
+ statements.push(statement);
691
+ }
692
+ }
693
+ }
694
+ return statements;
695
+ }
696
+ static async prettier(code) {
697
+ return await (0, prettier.format)(code, { parser: "typescript" });
698
+ }
699
+ static async genCode(schema, initOptions, adaptor) {
700
+ const { importClientSource } = initOptions;
701
+ const statements = Generator.schemaToStatemets(schema, adaptor, { baseURL: initOptions.baseURL ?? "" });
702
+ let code = Generator.toCode(statements);
703
+ if (importClientSource) code = importClientSource + "\n\n" + code;
704
+ return await Generator.prettier(code);
705
+ }
1025
706
  };
1026
-
1027
- // src/core/client/axios.ts
1028
- var import_typescript2 = require("typescript");
707
+ //#endregion
708
+ //#region src/core/client/axios.ts
709
+ /**
710
+ * Adapter class implementing support for generating code that makes use of the Axios HTTP client library.
711
+ * This class defines custom behavior and field mappings specific to the Axios client.
712
+ */
1029
713
  var AxiosAdapter = class extends Adapter {
1030
- /**
1031
- * Name of the field used to specify the HTTP method in the request configuration.
1032
- */
1033
- methodFieldName = "method";
1034
- /**
1035
- * Name of the field used to specify the request body (data) in the request configuration.
1036
- */
1037
- bodyFieldName = "data";
1038
- /**
1039
- * Name of the field used to specify the request headers in the request configuration.
1040
- */
1041
- headersFieldName = "headers";
1042
- /**
1043
- * Name of the field used to specify the query parameters in the request configuration.
1044
- */
1045
- queryFieldName = "params";
1046
- /**
1047
- * The name of the client this adapter is configured for, which is 'axios' in this case.
1048
- */
1049
- name = "axios";
1050
- /**
1051
- * Method that should generate and return the client-specific configuration statements.
1052
- *
1053
- * @returns {Statement[]} An array of TypeScript statements that define the client configuration.
1054
- *
1055
- * @throws {Error} Indicates that the method is not yet implemented and needs to be filled in.
1056
- */
1057
- client(uri, method, parameters, requestBody, response, adapter, shouldUseFormData) {
1058
- const statements = [];
1059
- const inBody = parameters.filter((p) => !p.in || p.in === "body");
1060
- const inHeader = parameters.filter((p) => p.in === "header");
1061
- const toLiterlExpression = () => {
1062
- return import_typescript2.factory.createObjectLiteralExpression(
1063
- [
1064
- // Set the HTTP method
1065
- import_typescript2.factory.createPropertyAssignment(
1066
- import_typescript2.factory.createIdentifier(adapter.methodFieldName),
1067
- import_typescript2.factory.createStringLiteral(method.toUpperCase())
1068
- )
1069
- ].concat(
1070
- // Add headers if there are any
1071
- inHeader.length > 0 ? import_typescript2.factory.createPropertyAssignment(
1072
- import_typescript2.factory.createIdentifier(adapter.headersFieldName),
1073
- import_typescript2.factory.createObjectLiteralExpression(
1074
- inHeader.map(
1075
- (p) => import_typescript2.factory.createPropertyAssignment(
1076
- import_typescript2.factory.createStringLiteral(p.name),
1077
- import_typescript2.factory.createCallExpression(
1078
- import_typescript2.factory.createIdentifier("encodeURIComponent"),
1079
- void 0,
1080
- [
1081
- import_typescript2.factory.createCallExpression(
1082
- import_typescript2.factory.createIdentifier("String"),
1083
- void 0,
1084
- [
1085
- import_typescript2.factory.createIdentifier(
1086
- Base.camelCase(Base.normalize(p.name))
1087
- )
1088
- ]
1089
- )
1090
- ]
1091
- )
1092
- )
1093
- )
1094
- )
1095
- ) : []
1096
- ).concat(
1097
- shouldUseFormData || inBody.length > 0 || requestBody?.schema ? import_typescript2.factory.createPropertyAssignment(
1098
- import_typescript2.factory.createIdentifier(adapter.bodyFieldName),
1099
- shouldUseFormData ? import_typescript2.factory.createIdentifier("fd") : inBody.length > 0 || requestBody?.schema && !Generator.isBinarySchema(requestBody.schema) ? import_typescript2.factory.createIdentifier("req") : import_typescript2.factory.createIdentifier("req")
1100
- ) : []
1101
- ),
1102
- true
1103
- );
1104
- };
1105
- statements.push(
1106
- import_typescript2.factory.createReturnStatement(
1107
- import_typescript2.factory.createCallExpression(
1108
- import_typescript2.factory.createIdentifier(adapter.name),
1109
- response?.schema ? [
1110
- Generator.toTypeNode(
1111
- response.schema
1112
- )
1113
- ] : void 0,
1114
- [Generator.toUrlTemplate(uri, parameters), toLiterlExpression()]
1115
- )
1116
- )
1117
- );
1118
- return statements;
1119
- }
714
+ /**
715
+ * Name of the field used to specify the HTTP method in the request configuration.
716
+ */
717
+ methodFieldName = "method";
718
+ /**
719
+ * Name of the field used to specify the request body (data) in the request configuration.
720
+ */
721
+ bodyFieldName = "data";
722
+ /**
723
+ * Name of the field used to specify the request headers in the request configuration.
724
+ */
725
+ headersFieldName = "headers";
726
+ /**
727
+ * Name of the field used to specify the query parameters in the request configuration.
728
+ */
729
+ queryFieldName = "params";
730
+ /**
731
+ * The name of the client this adapter is configured for, which is 'axios' in this case.
732
+ */
733
+ name = "axios";
734
+ /**
735
+ * Method that should generate and return the client-specific configuration statements.
736
+ *
737
+ * @returns {Statement[]} An array of TypeScript statements that define the client configuration.
738
+ *
739
+ * @throws {Error} Indicates that the method is not yet implemented and needs to be filled in.
740
+ */
741
+ client(uri, method, parameters, requestBody, response, adapter, shouldUseFormData) {
742
+ const statements = [];
743
+ const inBody = parameters.filter((p) => !p.in || p.in === "body");
744
+ const inHeader = parameters.filter((p) => p.in === "header");
745
+ /**
746
+ * Creates the literal object expression for fetch options
747
+ * including method, headers, and body.
748
+ * @returns - The constructed fetch options object
749
+ */
750
+ const toLiterlExpression = () => {
751
+ return typescript.factory.createObjectLiteralExpression([typescript.factory.createPropertyAssignment(typescript.factory.createIdentifier(adapter.methodFieldName), typescript.factory.createStringLiteral(method.toUpperCase()))].concat(inHeader.length > 0 ? typescript.factory.createPropertyAssignment(typescript.factory.createIdentifier(adapter.headersFieldName), typescript.factory.createObjectLiteralExpression(inHeader.map((p) => typescript.factory.createPropertyAssignment(typescript.factory.createStringLiteral(p.name), typescript.factory.createCallExpression(typescript.factory.createIdentifier("encodeURIComponent"), void 0, [typescript.factory.createCallExpression(typescript.factory.createIdentifier("String"), void 0, [typescript.factory.createIdentifier(Base.camelCase(Base.normalize(p.name)))])]))))) : []).concat(shouldUseFormData || inBody.length > 0 || requestBody?.schema ? typescript.factory.createPropertyAssignment(typescript.factory.createIdentifier(adapter.bodyFieldName), shouldUseFormData ? typescript.factory.createIdentifier("fd") : inBody.length > 0 || requestBody?.schema && !Generator.isBinarySchema(requestBody.schema) ? typescript.factory.createIdentifier("req") : typescript.factory.createIdentifier("req")) : []), true);
752
+ };
753
+ statements.push(typescript.factory.createReturnStatement(typescript.factory.createCallExpression(typescript.factory.createIdentifier(adapter.name), response?.schema ? [Generator.toTypeNode(response.schema)] : void 0, [Generator.toUrlTemplate(uri, parameters), toLiterlExpression()])));
754
+ return statements;
755
+ }
1120
756
  };
1121
-
1122
- // src/core/client/fetch.ts
1123
- var import_typescript3 = require("typescript");
757
+ //#endregion
758
+ //#region src/core/client/fetch.ts
759
+ /**
760
+ * FetchAdapter is an adapter class that generates client-side fetch requests.
761
+ * It handles parameters, headers, and request bodies to construct proper fetch calls.
762
+ */
1124
763
  var FetchAdapter = class extends Adapter {
1125
- methodFieldName = "method";
1126
- bodyFieldName = "body";
1127
- headersFieldName = "headers";
1128
- queryFieldName = "";
1129
- name = "fetch";
1130
- /**
1131
- * Generates client code for making API requests using the Fetch API.
1132
- * @param uri - The API endpoint URI
1133
- * @param method - The HTTP method (GET, POST, etc.)
1134
- * @param parameters - Array of parameters to include in the request
1135
- * @param requestBody - The request body media type definition
1136
- * @param response - The response media type definition
1137
- * @param adapter - The adapter instance
1138
- * @param shouldUseFormData - Flag to use FormData for the request body
1139
- * @param shouldUseJSONResponse - Flag to use JSON parsing for the response
1140
- * @return - An array of generated TypeScript statements
1141
- */
1142
- client(uri, method, parameters, requestBody, response, adapter, shouldUseFormData, shouldUseJSONResponse) {
1143
- const statements = [];
1144
- const inBody = parameters.filter((p) => !p.in || p.in === "body");
1145
- const inHeader = parameters.filter((p) => p.in === "header");
1146
- const toLiterlExpression = () => {
1147
- return import_typescript3.factory.createObjectLiteralExpression(
1148
- [
1149
- // Set the HTTP method
1150
- import_typescript3.factory.createPropertyAssignment(
1151
- import_typescript3.factory.createIdentifier(adapter.methodFieldName),
1152
- import_typescript3.factory.createStringLiteral(method.toUpperCase())
1153
- )
1154
- ].concat(
1155
- // Add headers if there are any
1156
- inHeader.length > 0 ? import_typescript3.factory.createPropertyAssignment(
1157
- import_typescript3.factory.createIdentifier(adapter.headersFieldName),
1158
- import_typescript3.factory.createObjectLiteralExpression(
1159
- inHeader.map(
1160
- (p) => import_typescript3.factory.createPropertyAssignment(
1161
- import_typescript3.factory.createStringLiteral(p.name),
1162
- import_typescript3.factory.createCallExpression(
1163
- import_typescript3.factory.createIdentifier("encodeURIComponent"),
1164
- void 0,
1165
- [
1166
- import_typescript3.factory.createCallExpression(
1167
- import_typescript3.factory.createIdentifier("String"),
1168
- void 0,
1169
- [
1170
- import_typescript3.factory.createIdentifier(
1171
- Base.camelCase(Base.normalize(p.name))
1172
- )
1173
- ]
1174
- )
1175
- ]
1176
- )
1177
- )
1178
- )
1179
- )
1180
- ) : []
1181
- ).concat(
1182
- shouldUseFormData || inBody.length > 0 || requestBody?.schema ? import_typescript3.factory.createPropertyAssignment(
1183
- import_typescript3.factory.createIdentifier(adapter.bodyFieldName),
1184
- shouldUseFormData ? import_typescript3.factory.createIdentifier("fd") : inBody.length > 0 || requestBody?.schema && !Generator.isBinarySchema(requestBody.schema) ? import_typescript3.factory.createCallExpression(
1185
- import_typescript3.factory.createPropertyAccessExpression(
1186
- import_typescript3.factory.createIdentifier("JSON"),
1187
- import_typescript3.factory.createIdentifier("stringify")
1188
- ),
1189
- [],
1190
- [
1191
- requestBody ? import_typescript3.factory.createIdentifier("req") : import_typescript3.factory.createObjectLiteralExpression(
1192
- inBody.map(
1193
- (b) => import_typescript3.factory.createShorthandPropertyAssignment(
1194
- import_typescript3.factory.createIdentifier(b.name)
1195
- )
1196
- ),
1197
- true
1198
- )
1199
- ]
1200
- ) : (
1201
- // One File parameter
1202
- import_typescript3.factory.createIdentifier("req")
1203
- )
1204
- ) : []
1205
- ),
1206
- true
1207
- );
1208
- };
1209
- statements.push(
1210
- import_typescript3.factory.createReturnStatement(
1211
- shouldUseJSONResponse ? (
1212
- // Handle JSON response with proper type checking
1213
- import_typescript3.factory.createCallExpression(
1214
- import_typescript3.factory.createPropertyAccessExpression(
1215
- import_typescript3.factory.createCallExpression(
1216
- import_typescript3.factory.createIdentifier(adapter.name),
1217
- void 0,
1218
- [
1219
- Generator.toUrlTemplate(uri, parameters),
1220
- toLiterlExpression()
1221
- ]
1222
- ),
1223
- import_typescript3.factory.createIdentifier("then")
1224
- ),
1225
- void 0,
1226
- [
1227
- import_typescript3.factory.createArrowFunction(
1228
- [import_typescript3.factory.createModifier(import_typescript3.SyntaxKind.AsyncKeyword)],
1229
- [],
1230
- [
1231
- import_typescript3.factory.createParameterDeclaration(
1232
- void 0,
1233
- void 0,
1234
- import_typescript3.factory.createIdentifier("response")
1235
- )
1236
- ],
1237
- void 0,
1238
- import_typescript3.factory.createToken(import_typescript3.SyntaxKind.EqualsGreaterThanToken),
1239
- response?.schema ? import_typescript3.factory.createAsExpression(
1240
- import_typescript3.factory.createParenthesizedExpression(
1241
- import_typescript3.factory.createAwaitExpression(
1242
- import_typescript3.factory.createCallExpression(
1243
- import_typescript3.factory.createPropertyAccessExpression(
1244
- import_typescript3.factory.createIdentifier("response"),
1245
- import_typescript3.factory.createIdentifier("json")
1246
- ),
1247
- void 0,
1248
- []
1249
- )
1250
- )
1251
- ),
1252
- response?.schema ? Generator.toTypeNode(response.schema) : import_typescript3.factory.createToken(import_typescript3.SyntaxKind.UnknownKeyword)
1253
- ) : import_typescript3.factory.createParenthesizedExpression(
1254
- import_typescript3.factory.createAwaitExpression(
1255
- import_typescript3.factory.createCallExpression(
1256
- import_typescript3.factory.createPropertyAccessExpression(
1257
- import_typescript3.factory.createIdentifier("response"),
1258
- import_typescript3.factory.createIdentifier("json")
1259
- ),
1260
- void 0,
1261
- []
1262
- )
1263
- )
1264
- )
1265
- )
1266
- ]
1267
- )
1268
- ) : (
1269
- // Simple fetch call without JSON parsing
1270
- import_typescript3.factory.createCallExpression(
1271
- import_typescript3.factory.createIdentifier(adapter.name),
1272
- void 0,
1273
- [Generator.toUrlTemplate(uri, parameters), toLiterlExpression()]
1274
- )
1275
- )
1276
- )
1277
- );
1278
- return statements;
1279
- }
764
+ methodFieldName = "method";
765
+ bodyFieldName = "body";
766
+ headersFieldName = "headers";
767
+ queryFieldName = "";
768
+ name = "fetch";
769
+ /**
770
+ * Generates client code for making API requests using the Fetch API.
771
+ * @param uri - The API endpoint URI
772
+ * @param method - The HTTP method (GET, POST, etc.)
773
+ * @param parameters - Array of parameters to include in the request
774
+ * @param requestBody - The request body media type definition
775
+ * @param response - The response media type definition
776
+ * @param adapter - The adapter instance
777
+ * @param shouldUseFormData - Flag to use FormData for the request body
778
+ * @param shouldUseJSONResponse - Flag to use JSON parsing for the response
779
+ * @return - An array of generated TypeScript statements
780
+ */
781
+ client(uri, method, parameters, requestBody, response, adapter, shouldUseFormData, shouldUseJSONResponse) {
782
+ const statements = [];
783
+ const inBody = parameters.filter((p) => !p.in || p.in === "body");
784
+ const inHeader = parameters.filter((p) => p.in === "header");
785
+ /**
786
+ * Creates the literal object expression for fetch options
787
+ * including method, headers, and body.
788
+ * @returns - The constructed fetch options object
789
+ */
790
+ const toLiterlExpression = () => {
791
+ return typescript.factory.createObjectLiteralExpression([typescript.factory.createPropertyAssignment(typescript.factory.createIdentifier(adapter.methodFieldName), typescript.factory.createStringLiteral(method.toUpperCase()))].concat(inHeader.length > 0 ? typescript.factory.createPropertyAssignment(typescript.factory.createIdentifier(adapter.headersFieldName), typescript.factory.createObjectLiteralExpression(inHeader.map((p) => typescript.factory.createPropertyAssignment(typescript.factory.createStringLiteral(p.name), typescript.factory.createCallExpression(typescript.factory.createIdentifier("encodeURIComponent"), void 0, [typescript.factory.createCallExpression(typescript.factory.createIdentifier("String"), void 0, [typescript.factory.createIdentifier(Base.camelCase(Base.normalize(p.name)))])]))))) : []).concat(shouldUseFormData || inBody.length > 0 || requestBody?.schema ? typescript.factory.createPropertyAssignment(typescript.factory.createIdentifier(adapter.bodyFieldName), shouldUseFormData ? typescript.factory.createIdentifier("fd") : inBody.length > 0 || requestBody?.schema && !Generator.isBinarySchema(requestBody.schema) ? typescript.factory.createCallExpression(typescript.factory.createPropertyAccessExpression(typescript.factory.createIdentifier("JSON"), typescript.factory.createIdentifier("stringify")), [], [requestBody ? typescript.factory.createIdentifier("req") : typescript.factory.createObjectLiteralExpression(inBody.map((b) => typescript.factory.createShorthandPropertyAssignment(typescript.factory.createIdentifier(b.name))), true)]) : typescript.factory.createIdentifier("req")) : []), true);
792
+ };
793
+ statements.push(typescript.factory.createReturnStatement(shouldUseJSONResponse ? typescript.factory.createCallExpression(typescript.factory.createPropertyAccessExpression(typescript.factory.createCallExpression(typescript.factory.createIdentifier(adapter.name), void 0, [Generator.toUrlTemplate(uri, parameters), toLiterlExpression()]), typescript.factory.createIdentifier("then")), void 0, [typescript.factory.createArrowFunction([typescript.factory.createModifier(typescript.SyntaxKind.AsyncKeyword)], [], [typescript.factory.createParameterDeclaration(void 0, void 0, typescript.factory.createIdentifier("response"))], void 0, typescript.factory.createToken(typescript.SyntaxKind.EqualsGreaterThanToken), response?.schema ? typescript.factory.createAsExpression(typescript.factory.createParenthesizedExpression(typescript.factory.createAwaitExpression(typescript.factory.createCallExpression(typescript.factory.createPropertyAccessExpression(typescript.factory.createIdentifier("response"), typescript.factory.createIdentifier("json")), void 0, []))), response?.schema ? Generator.toTypeNode(response.schema) : typescript.factory.createToken(typescript.SyntaxKind.UnknownKeyword)) : typescript.factory.createParenthesizedExpression(typescript.factory.createAwaitExpression(typescript.factory.createCallExpression(typescript.factory.createPropertyAccessExpression(typescript.factory.createIdentifier("response"), typescript.factory.createIdentifier("json")), void 0, []))))]) : typescript.factory.createCallExpression(typescript.factory.createIdentifier(adapter.name), void 0, [Generator.toUrlTemplate(uri, parameters), toLiterlExpression()])));
794
+ return statements;
795
+ }
1280
796
  };
1281
-
1282
- // src/openapi/index.ts
1283
- var import_logger = require("@moccona/logger");
1284
-
1285
- // src/openapi/V2.ts
797
+ //#endregion
798
+ //#region src/core/config.ts
799
+ /**
800
+ * Environment variable mappings
801
+ */
802
+ const ENV_MAPPINGS = {
803
+ APICODEGEN_SPEC: "spec",
804
+ APICODEGEN_OUTPUT: "output",
805
+ APICODEGEN_BASE_URL: "baseURL",
806
+ APICODEGEN_ADAPTOR: "adaptor",
807
+ APICODEGEN_VERBOSE: "verbose",
808
+ APICODEGEN_WATCH: "watch",
809
+ APICODEGEN_TYPE_CHECK: "typeCheck"
810
+ };
811
+ /**
812
+ * Load config from environment variables
813
+ */
814
+ function loadFromEnv() {
815
+ const config = {};
816
+ for (const [envKey, configKey] of Object.entries(ENV_MAPPINGS)) {
817
+ const value = process.env[envKey];
818
+ if (value !== void 0) switch (configKey) {
819
+ case "verbose":
820
+ case "watch":
821
+ case "typeCheck":
822
+ config[configKey] = value === "true" || value === "1";
823
+ break;
824
+ case "adaptor":
825
+ config[configKey] = value;
826
+ break;
827
+ default: config[configKey] = value;
828
+ }
829
+ }
830
+ return config;
831
+ }
832
+ /**
833
+ * Load config from a file
834
+ */
835
+ async function loadFromFile(filePath) {
836
+ const ext = node_path.default.extname(filePath).toLowerCase();
837
+ try {
838
+ if (ext === ".json" || ext === ".jsonc") {
839
+ const content = await fs_extra.default.readFile(filePath, "utf-8");
840
+ return JSON.parse(content);
841
+ }
842
+ if (ext === ".js" || ext === ".cjs" || ext === ".mjs") {
843
+ const mod = await import(filePath);
844
+ return mod.default || mod;
845
+ }
846
+ if (ext === ".ts") {
847
+ const content = await fs_extra.default.readFile(filePath, "utf-8");
848
+ try {
849
+ return JSON.parse(content);
850
+ } catch {
851
+ const jsonMatch = content.match(/export\s+default\s+(\{.+\})/s);
852
+ if (jsonMatch) return JSON.parse(jsonMatch[1]);
853
+ }
854
+ }
855
+ const content = await fs_extra.default.readFile(filePath, "utf-8");
856
+ return JSON.parse(content);
857
+ } catch (error) {
858
+ throw new Error(`Failed to load config from ${filePath}: ${error}`);
859
+ }
860
+ }
861
+ /**
862
+ * Find config file in project root
863
+ */
864
+ async function findConfigFile(cwd) {
865
+ for (const fileName of [
866
+ "apicodegen.config.json",
867
+ "apicodegen.config.js",
868
+ "apicodegen.config.mjs",
869
+ ".apicodegenrc",
870
+ ".apicodegenrc.json",
871
+ ".apicodegenrc.js",
872
+ ".apicodegenrc.mjs"
873
+ ]) {
874
+ const filePath = node_path.default.join(cwd, fileName);
875
+ if (await fs_extra.default.pathExists(filePath)) return filePath;
876
+ }
877
+ const packageJsonPath = node_path.default.join(cwd, "package.json");
878
+ if (await fs_extra.default.pathExists(packageJsonPath)) try {
879
+ const pkg = JSON.parse(await fs_extra.default.readFile(packageJsonPath, "utf-8"));
880
+ if (pkg.apicodegen && typeof pkg.apicodegen === "string") return node_path.default.resolve(cwd, pkg.apicodegen);
881
+ } catch {}
882
+ return null;
883
+ }
884
+ /**
885
+ * Merge multiple config sources with priority
886
+ * Priority: defaults < env vars < config file < CLI args
887
+ */
888
+ function mergeConfigs(base, ...sources) {
889
+ const result = { ...base };
890
+ for (const source of sources) {
891
+ if (!source) continue;
892
+ for (const [key, value] of Object.entries(source)) if (value !== void 0) result[key] = value;
893
+ }
894
+ return result;
895
+ }
896
+ /**
897
+ * Validate config has required fields
898
+ */
899
+ function validateConfig(config) {
900
+ if (!config.spec) throw new Error("Missing required field: spec (OpenAPI spec file path or URL)");
901
+ return true;
902
+ }
903
+ /**
904
+ * Load and resolve config from multiple sources
905
+ */
906
+ async function loadConfig(options = {}) {
907
+ const cwd = options.cwd || process.cwd();
908
+ const cliOptions = options.cliOptions || {};
909
+ const envConfig = loadFromEnv();
910
+ let fileConfig = {};
911
+ let configFilePath;
912
+ if (options.configFile) {
913
+ configFilePath = node_path.default.resolve(cwd, options.configFile);
914
+ fileConfig = await loadFromFile(configFilePath);
915
+ } else {
916
+ const foundPath = await findConfigFile(cwd);
917
+ if (foundPath) {
918
+ configFilePath = foundPath;
919
+ fileConfig = await loadFromFile(foundPath);
920
+ }
921
+ }
922
+ const packageJsonPath = node_path.default.join(cwd, "package.json");
923
+ let inlineConfig = {};
924
+ if (await fs_extra.default.pathExists(packageJsonPath)) try {
925
+ const pkg = JSON.parse(await fs_extra.default.readFile(packageJsonPath, "utf-8"));
926
+ if (pkg.apicodegen && typeof pkg.apicodegen === "object") inlineConfig = pkg.apicodegen;
927
+ } catch {}
928
+ const merged = mergeConfigs({
929
+ spec: "",
930
+ output: "./output.ts"
931
+ }, envConfig, inlineConfig, fileConfig, cliOptions);
932
+ validateConfig(merged);
933
+ const name = options.name || merged.baseURL || merged.spec;
934
+ return {
935
+ ...merged,
936
+ configFilePath,
937
+ name
938
+ };
939
+ }
940
+ /**
941
+ * Create CLI options from config for commander
942
+ */
943
+ function configToCLIOptions(config) {
944
+ const options = {};
945
+ if (config.spec) options.spec = config.spec;
946
+ if (config.output) options.output = config.output;
947
+ if (config.adaptor) options.adaptor = config.adaptor;
948
+ if (config.baseURL) options.baseURL = config.baseURL;
949
+ if (config.verbose) options.verbose = config.verbose;
950
+ if (config.watch) options.watch = config.watch;
951
+ if (config.importClientSource) options.importClientSource = config.importClientSource;
952
+ return options;
953
+ }
954
+ /**
955
+ * Convert resolved config to provider options format
956
+ */
957
+ function toProviderOptions(config) {
958
+ return {
959
+ docURL: config.spec,
960
+ output: config.output,
961
+ adaptor: config.adaptor,
962
+ baseURL: config.baseURL,
963
+ importClientSource: config.importClientSource,
964
+ verbose: config.verbose,
965
+ requestOptions: config.requestOptions
966
+ };
967
+ }
968
+ //#endregion
969
+ //#region src/core/errors.ts
970
+ /**
971
+ * Error handling utilities for api-codegen
972
+ */
973
+ const ErrorCodes = {
974
+ SPEC_NOT_FOUND: "E_SPEC_NOT_FOUND",
975
+ SPEC_FETCH_FAILED: "E_SPEC_FETCH_FAILED",
976
+ SPEC_PARSE_FAILED: "E_SPEC_PARSE_FAILED",
977
+ OUTPUT_DIR_MISSING: "E_OUTPUT_DIR_MISSING",
978
+ CONFIG_INVALID: "E_CONFIG_INVALID",
979
+ VALIDATION_FAILED: "E_VALIDATION_FAILED",
980
+ GENERATION_FAILED: "E_GENERATION_FAILED",
981
+ TYPE_CHECK_FAILED: "E_TYPE_CHECK_FAILED"
982
+ };
983
+ /**
984
+ * Custom error class for api-codegen with rich context
985
+ */
986
+ var ApicodegenError = class ApicodegenError extends Error {
987
+ code;
988
+ location;
989
+ line;
990
+ column;
991
+ path;
992
+ suggestions;
993
+ cause;
994
+ constructor(context) {
995
+ super(context.message);
996
+ this.name = "ApicodegenError";
997
+ this.code = context.code;
998
+ this.location = context.location;
999
+ this.line = context.line;
1000
+ this.column = context.column;
1001
+ this.path = context.path;
1002
+ this.suggestions = context.suggestions || [];
1003
+ this.cause = context.cause;
1004
+ if (Error.captureStackTrace) Error.captureStackTrace(this, ApicodegenError);
1005
+ }
1006
+ /**
1007
+ * Convert error to formatted string for CLI output
1008
+ */
1009
+ toString(verbose = false) {
1010
+ const lines = [];
1011
+ lines.push(`\x1b[1;31mError [${this.code}]\x1b[0m ${this.message}`);
1012
+ if (this.location) lines.push(` \x1b[36m→ Location:\x1b[0m ${this.location}`);
1013
+ if (this.path) lines.push(` \x1b[36m→ Path:\x1b[0m ${this.path}`);
1014
+ if (this.line !== void 0) {
1015
+ let lineInfo = ` \x1b[36m→ Line:\x1b[0m ${this.line}`;
1016
+ if (this.column !== void 0) lineInfo += `, Column: ${this.column}`;
1017
+ lines.push(lineInfo);
1018
+ }
1019
+ if (this.suggestions.length > 0) for (const suggestion of this.suggestions) lines.push(` \x1b[32m→ Suggestion:\x1b[0m ${suggestion}`);
1020
+ if (verbose && this.cause) {
1021
+ lines.push(`\n \x1b[90mOriginal Error:\x1b[0m ${this.cause.message}`);
1022
+ if (this.stack) {
1023
+ const stackLines = this.stack.split("\n").slice(1).join("\n");
1024
+ lines.push(`\x1b[90m${stackLines}\x1b[0m`);
1025
+ }
1026
+ }
1027
+ return lines.join("\n");
1028
+ }
1029
+ /**
1030
+ * Convert to JSON-serializable object
1031
+ */
1032
+ toJSON() {
1033
+ return {
1034
+ name: this.name,
1035
+ code: this.code,
1036
+ message: this.message,
1037
+ location: this.location,
1038
+ line: this.line,
1039
+ column: this.column,
1040
+ path: this.path,
1041
+ suggestions: this.suggestions,
1042
+ cause: this.cause?.message
1043
+ };
1044
+ }
1045
+ };
1046
+ /**
1047
+ * ANSI color codes for terminal output
1048
+ */
1049
+ const Colors = {
1050
+ reset: "\x1B[0m",
1051
+ bold: "\x1B[1m",
1052
+ red: "\x1B[31m",
1053
+ green: "\x1B[32m",
1054
+ yellow: "\x1B[33m",
1055
+ blue: "\x1B[34m",
1056
+ cyan: "\x1B[36m",
1057
+ gray: "\x1B[90m",
1058
+ brightRed: "\x1B[91m",
1059
+ brightGreen: "\x1B[92m"
1060
+ };
1061
+ /**
1062
+ * Format error for CLI output
1063
+ */
1064
+ function formatError(error, verbose = false) {
1065
+ if (error instanceof ApicodegenError) return error.toString(verbose);
1066
+ if (error instanceof Error) return `${Colors.red}${Colors.bold}Error${Colors.reset}: ${error.message}${verbose && error.stack ? `\n\n${Colors.gray}${error.stack}${Colors.reset}` : ""}`;
1067
+ return `${Colors.red}${Colors.bold}Error${Colors.reset}: ${String(error)}`;
1068
+ }
1069
+ /**
1070
+ * Print error to console with formatting
1071
+ */
1072
+ function printError(error, verbose = false, stream = process.stderr) {
1073
+ stream.write(formatError(error, verbose));
1074
+ stream.write("\n");
1075
+ }
1076
+ /**
1077
+ * Create error with common patterns
1078
+ */
1079
+ const createErrors = {
1080
+ specNotFound(path, cause) {
1081
+ return new ApicodegenError({
1082
+ code: ErrorCodes.SPEC_NOT_FOUND,
1083
+ message: "OpenAPI spec file not found",
1084
+ location: path,
1085
+ suggestions: [
1086
+ "Check if the file exists using 'ls -la'",
1087
+ "Use --spec to provide the correct path",
1088
+ "For remote specs, ensure the URL is accessible"
1089
+ ],
1090
+ cause
1091
+ });
1092
+ },
1093
+ specFetchFailed(url, statusCode, cause) {
1094
+ const message = statusCode ? `Failed to fetch OpenAPI spec (HTTP ${statusCode})` : "Failed to fetch OpenAPI spec from URL";
1095
+ return new ApicodegenError({
1096
+ code: ErrorCodes.SPEC_FETCH_FAILED,
1097
+ message,
1098
+ location: url,
1099
+ suggestions: [
1100
+ "Check if the URL is accessible in a browser",
1101
+ "Download the spec file locally and use the local path",
1102
+ "Verify CORS settings if fetching from a different origin"
1103
+ ],
1104
+ cause
1105
+ });
1106
+ },
1107
+ specParseFailed(path, line, column, cause) {
1108
+ return new ApicodegenError({
1109
+ code: ErrorCodes.SPEC_PARSE_FAILED,
1110
+ message: "Failed to parse OpenAPI spec (invalid JSON or YAML)",
1111
+ location: path,
1112
+ line,
1113
+ column,
1114
+ suggestions: [
1115
+ "Validate JSON syntax using jsonlint.com",
1116
+ "For YAML specs, ensure proper indentation",
1117
+ "Check for trailing commas or unquoted special characters"
1118
+ ],
1119
+ cause
1120
+ });
1121
+ },
1122
+ outputDirMissing(path, cause) {
1123
+ return new ApicodegenError({
1124
+ code: ErrorCodes.OUTPUT_DIR_MISSING,
1125
+ message: "Output directory does not exist",
1126
+ location: path,
1127
+ suggestions: ["Create the directory: mkdir -p $(dirname <output>)", "Check if the path is correct"],
1128
+ cause
1129
+ });
1130
+ },
1131
+ configInvalid(path, cause) {
1132
+ return new ApicodegenError({
1133
+ code: ErrorCodes.CONFIG_INVALID,
1134
+ message: "Invalid configuration file",
1135
+ location: path,
1136
+ suggestions: ["Validate JSON syntax in the config file", "Check for required fields (spec, output)"],
1137
+ cause
1138
+ });
1139
+ },
1140
+ validationFailed(path, details, cause) {
1141
+ return new ApicodegenError({
1142
+ code: ErrorCodes.VALIDATION_FAILED,
1143
+ message: "OpenAPI spec validation failed",
1144
+ location: path,
1145
+ path: details,
1146
+ suggestions: [
1147
+ "Check OpenAPI spec structure at the specified path",
1148
+ "Ensure all required fields are present",
1149
+ "Validate using swagger.io editor"
1150
+ ],
1151
+ cause
1152
+ });
1153
+ },
1154
+ generationFailed(cause) {
1155
+ return new ApicodegenError({
1156
+ code: ErrorCodes.GENERATION_FAILED,
1157
+ message: "Code generation failed",
1158
+ suggestions: [
1159
+ "Check for unsupported OpenAPI features",
1160
+ "Ensure spec follows OpenAPI 2.0, 3.0, or 3.1 specification",
1161
+ "Use --verbose for more details"
1162
+ ],
1163
+ cause
1164
+ });
1165
+ },
1166
+ typeCheckFailed(path, _errors, cause) {
1167
+ return new ApicodegenError({
1168
+ code: ErrorCodes.TYPE_CHECK_FAILED,
1169
+ message: "TypeScript type check failed",
1170
+ location: path,
1171
+ suggestions: [
1172
+ "Review type errors above",
1173
+ "Check for schema inconsistencies",
1174
+ "Update generated types or fix source schema"
1175
+ ],
1176
+ cause
1177
+ });
1178
+ },
1179
+ missingRequiredField(field, context) {
1180
+ return new ApicodegenError({
1181
+ code: ErrorCodes.VALIDATION_FAILED,
1182
+ message: `Missing required field: ${field}`,
1183
+ path: context,
1184
+ suggestions: [`Add the '${field}' field to your configuration`]
1185
+ });
1186
+ }
1187
+ };
1188
+ /**
1189
+ * Wrap unknown error in ApicodegenError if needed
1190
+ */
1191
+ function wrapError(error, context) {
1192
+ if (error instanceof ApicodegenError) return error;
1193
+ if (error instanceof Error) return new ApicodegenError({
1194
+ code: context?.code || ErrorCodes.GENERATION_FAILED,
1195
+ message: context?.message || error.message,
1196
+ location: context?.location,
1197
+ suggestions: context?.suggestions,
1198
+ cause: error
1199
+ });
1200
+ return new ApicodegenError({
1201
+ code: context?.code || ErrorCodes.GENERATION_FAILED,
1202
+ message: String(error),
1203
+ suggestions: context?.suggestions
1204
+ });
1205
+ }
1206
+ /**
1207
+ * Check if error is an ApicodegenError
1208
+ */
1209
+ function isApicodegenError(error) {
1210
+ return error instanceof ApicodegenError;
1211
+ }
1212
+ //#endregion
1213
+ //#region src/openapi/V2.ts
1286
1214
  var V2 = class {
1287
- doc;
1288
- constructor(doc) {
1289
- this.doc = doc;
1290
- }
1291
- /**
1292
- * Is array schema.
1293
- */
1294
- isOpenAPIArraySchema(schema) {
1295
- return typeof schema === "object" && schema.type === "array";
1296
- }
1297
- /**
1298
- * OpenAPI schema to base schema.
1299
- */
1300
- getSchemaByRef(schema, reserveRef = false, enums = [], upLevelSchemaKey = "") {
1301
- let refName = "";
1302
- if (Base.isRef(schema)) {
1303
- refName = Base.upperCamelCase(Base.ref2name(schema.$ref));
1304
- if (reserveRef) {
1305
- return {
1306
- type: upLevelSchemaKey + refName
1307
- };
1308
- }
1309
- if (!this.doc.definitions) {
1310
- this.doc.definitions = {};
1311
- }
1312
- schema = this.doc.definitions[Base.ref2name(schema.$ref, this.doc)];
1313
- }
1314
- return this.toBaseSchema(schema, enums, "", upLevelSchemaKey + refName);
1315
- }
1316
- /**
1317
- * Transform all OpenAPI schema to Base Schema
1318
- */
1319
- toBaseSchema(schema, enums = [], schemaKey = "", upLevelSchemaKey = "") {
1320
- if (!schema) {
1321
- return {
1322
- type: "unknown"
1323
- };
1324
- }
1325
- if (Base.isRef(schema)) {
1326
- return this.getSchemaByRef(schema, true);
1327
- }
1328
- if (this.isOpenAPIArraySchema(schema)) {
1329
- const { type, description, items, required } = schema;
1330
- return {
1331
- type,
1332
- required: !!required,
1333
- description,
1334
- items: this.toBaseSchema(items, enums, schemaKey, upLevelSchemaKey)
1335
- };
1336
- } else {
1337
- const {
1338
- required = [],
1339
- allOf,
1340
- anyOf,
1341
- description,
1342
- enum: enum_,
1343
- format: format2,
1344
- oneOf,
1345
- properties = {}
1346
- } = schema;
1347
- let { type } = schema;
1348
- if (enum_ && type !== "boolean") {
1349
- const name = Base.upperCamelCase(upLevelSchemaKey) + Base.upperCamelCase(schemaKey);
1350
- const enumObject = {
1351
- name,
1352
- enum: [...new Set(enum_)]
1353
- };
1354
- const sameObject = Base.findSameSchema(enumObject, enums);
1355
- if (!sameObject && Base.isValidEnumType(schema)) {
1356
- enums.push(enumObject);
1357
- }
1358
- return {
1359
- type: sameObject ? sameObject.name : Base.isBooleanEnum(schema) ? "boolean" : enumObject.name,
1360
- required,
1361
- description
1362
- };
1363
- }
1364
- if (type === void 0 && Object.keys(properties).length > 0) {
1365
- type = "object" /* object */;
1366
- }
1367
- return {
1368
- type,
1369
- required,
1370
- description,
1371
- enum: enum_,
1372
- format: format2,
1373
- allOf: allOf?.map(
1374
- (s) => Base.isRef(s) ? {
1375
- ...s,
1376
- ref: s.$ref,
1377
- type: Base.upperCamelCase(Base.ref2name(s.$ref, this.doc))
1378
- } : this.toBaseSchema(s, enums)
1379
- ),
1380
- anyOf: anyOf?.map(
1381
- (s) => Base.isRef(s) ? {
1382
- ...s,
1383
- ref: s.$ref,
1384
- type: Base.upperCamelCase(Base.ref2name(s.$ref, this.doc))
1385
- } : this.toBaseSchema(s, enums)
1386
- ),
1387
- oneOf: oneOf?.map(
1388
- (s) => Base.isRef(s) ? {
1389
- ...s,
1390
- ref: s.$ref,
1391
- type: Base.upperCamelCase(Base.ref2name(s.$ref, this.doc))
1392
- } : this.toBaseSchema(s, enums)
1393
- ),
1394
- properties: Object.keys(properties).reduce((acc, p) => {
1395
- const propSchema = properties[p];
1396
- return {
1397
- ...acc,
1398
- [p]: Base.isRef(propSchema) ? {
1399
- type: Base.upperCamelCase(
1400
- Base.ref2name(propSchema.$ref, this.doc)
1401
- )
1402
- } : this.toBaseSchema(propSchema, enums, p, upLevelSchemaKey)
1403
- };
1404
- }, {})
1405
- };
1406
- }
1407
- }
1408
- /**
1409
- * OpenAPI parameter to base parameter.
1410
- */
1411
- getParameterByRef(parameter, enums = [], upLevelSchemaKey = "") {
1412
- if (Base.isRef(parameter)) {
1413
- parameter = this.doc.parameters[Base.ref2name(parameter.$ref, this.doc)];
1414
- }
1415
- const {
1416
- name,
1417
- required,
1418
- description,
1419
- type,
1420
- items,
1421
- enum: enum_,
1422
- properties,
1423
- schema
1424
- } = parameter;
1425
- if (enum_) {
1426
- const type2 = Base.upperCamelCase(upLevelSchemaKey) + Base.upperCamelCase(name);
1427
- const enumSchema = {
1428
- name: type2,
1429
- enum: [...new Set(enum_)]
1430
- };
1431
- const sameEnum = Base.findSameSchema(enumSchema, enums);
1432
- if (!sameEnum && Base.isValidEnumType({ type: type2, enum: enums })) {
1433
- enums.push(enumSchema);
1434
- }
1435
- return {
1436
- name,
1437
- required,
1438
- description,
1439
- in: parameter.in,
1440
- schema: {
1441
- type: sameEnum?.name ?? type2
1442
- }
1443
- };
1444
- }
1445
- if (items) {
1446
- return {
1447
- name,
1448
- required,
1449
- description,
1450
- in: parameter.in,
1451
- schema: {
1452
- type,
1453
- items
1454
- }
1455
- };
1456
- }
1457
- if (schema && Base.isRef(schema)) {
1458
- return {
1459
- name,
1460
- required,
1461
- description,
1462
- in: parameter.in,
1463
- schema: {
1464
- type: Base.upperCamelCase(Base.ref2name(schema.$ref))
1465
- }
1466
- };
1467
- }
1468
- return {
1469
- name,
1470
- required,
1471
- description,
1472
- in: parameter.in,
1473
- schema: {
1474
- type,
1475
- properties
1476
- }
1477
- };
1478
- }
1479
- /**
1480
- * OpenAPI schema to base response
1481
- */
1482
- getResponseByRef(schema) {
1483
- if (Base.isRef(schema)) {
1484
- schema = this.doc.responses[Base.ref2name(schema.$ref, this.doc)];
1485
- }
1486
- const { schema: responseSchema } = schema;
1487
- return [
1488
- {
1489
- type: "application/json" /* JSON */,
1490
- schema: responseSchema && this.getSchemaByRef(responseSchema, true)
1491
- }
1492
- ];
1493
- }
1494
- init() {
1495
- const { definitions = {}, responses = {}, paths = {} } = this.doc;
1496
- const enums = [];
1497
- const definitions_ = Object.keys(definitions).reduce((acc, key) => {
1498
- const schema = definitions[key];
1499
- return {
1500
- ...acc,
1501
- [key]: this.getSchemaByRef(schema, false, enums, key)
1502
- };
1503
- }, {});
1504
- const responses_ = Object.keys(responses).reduce((acc, key) => {
1505
- const response = responses[key];
1506
- return {
1507
- ...acc,
1508
- [key]: this.getResponseByRef(response)
1509
- };
1510
- }, {});
1511
- const apis = Object.keys(paths).reduce((acc, path) => {
1512
- const pathObject = paths[path] ?? {};
1513
- const { $ref } = pathObject;
1514
- const methodApis = [];
1515
- if ($ref) {
1516
- } else {
1517
- const { parameters = [] } = pathObject;
1518
- Object.values(HttpMethods).forEach((method) => {
1519
- const methodObject = pathObject[method];
1520
- if (methodObject) {
1521
- const {
1522
- deprecated,
1523
- operationId,
1524
- summary: summary_,
1525
- description: description_,
1526
- responses: responses2 = {}
1527
- } = methodObject;
1528
- const { parameters: parameters_ = [] } = methodObject;
1529
- const baseParameters = [...parameters, ...parameters_].map(
1530
- (parameter) => this.getParameterByRef(parameter, enums)
1531
- );
1532
- const uniqueParameterName = [
1533
- ...new Set(baseParameters.map((p) => p.name))
1534
- ];
1535
- if (Object.keys(responses2).length === 0) {
1536
- Object.assign(responses2, {
1537
- 200: {
1538
- description: "Successful response"
1539
- }
1540
- });
1541
- }
1542
- const inBody = baseParameters.filter(
1543
- (p) => p.in === "body" || p.in === "formData"
1544
- );
1545
- const notInBody = baseParameters.filter(
1546
- (p) => p.in !== "body" && p.in !== "formData"
1547
- );
1548
- const httpCodes = Object.keys(responses2);
1549
- for (const code of httpCodes) {
1550
- if (code in responses2) {
1551
- const response = responses2[code];
1552
- const responseSchema = this.getResponseByRef(response);
1553
- const inBodyOnlyHasBody = inBody && inBody.length === 1 && inBody[0].in === "body" && inBody[0].name === "body";
1554
- methodApis.push({
1555
- method,
1556
- operationId,
1557
- summary: summary_,
1558
- deprecated,
1559
- description: description_,
1560
- parameters: uniqueParameterName.map((name) => notInBody.find((p) => p.name === name)).filter(Boolean),
1561
- responses: responseSchema,
1562
- requestBody: inBody.length > 0 ? inBodyOnlyHasBody ? [
1563
- {
1564
- type: "application/json" /* JSON */,
1565
- schema: inBody[0].schema
1566
- }
1567
- ] : [
1568
- {
1569
- type: "application/json" /* JSON */,
1570
- schema: {
1571
- type: "object" /* object */,
1572
- properties: inBody.reduce((a, p) => {
1573
- return {
1574
- ...a,
1575
- [p.name]: {
1576
- type: p.schema?.type ?? "unknown",
1577
- required: p.schema?.required,
1578
- // @ts-expect-error items can be undefined
1579
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
1580
- items: p.schema?.items,
1581
- description: p.schema?.description
1582
- }
1583
- };
1584
- }, {})
1585
- }
1586
- }
1587
- ] : void 0
1588
- });
1589
- break;
1590
- }
1591
- }
1592
- }
1593
- });
1594
- }
1595
- return {
1596
- ...acc,
1597
- [path]: methodApis
1598
- };
1599
- }, {});
1600
- return {
1601
- enums: Base.uniqueEnums(enums),
1602
- schemas: definitions_,
1603
- responses: responses_,
1604
- parameters: {},
1605
- requestBodies: {},
1606
- apis
1607
- };
1608
- }
1215
+ doc;
1216
+ constructor(doc) {
1217
+ this.doc = doc;
1218
+ }
1219
+ /**
1220
+ * Resolves a path $ref to the actual path object.
1221
+ */
1222
+ resolvePathRef($ref) {
1223
+ const refName = Base.ref2name($ref, this.doc);
1224
+ return this.doc.paths?.[refName];
1225
+ }
1226
+ /**
1227
+ * Is array schema.
1228
+ */
1229
+ isOpenAPIArraySchema(schema) {
1230
+ return typeof schema === "object" && schema.type === "array";
1231
+ }
1232
+ /**
1233
+ * OpenAPI schema to base schema.
1234
+ */
1235
+ getSchemaByRef(schema, reserveRef = false, enums = [], upLevelSchemaKey = "") {
1236
+ let refName = "";
1237
+ if (Base.isRef(schema)) {
1238
+ refName = Base.upperCamelCase(Base.ref2name(schema.$ref));
1239
+ if (reserveRef) return { type: upLevelSchemaKey + refName };
1240
+ if (!this.doc.definitions) this.doc.definitions = {};
1241
+ schema = this.doc.definitions[Base.ref2name(schema.$ref, this.doc)];
1242
+ }
1243
+ return this.toBaseSchema(schema, enums, "", upLevelSchemaKey + refName);
1244
+ }
1245
+ /**
1246
+ * Transform all OpenAPI schema to Base Schema
1247
+ */
1248
+ toBaseSchema(schema, enums = [], schemaKey = "", upLevelSchemaKey = "") {
1249
+ if (!schema) return { type: "unknown" };
1250
+ if (Base.isRef(schema)) return this.getSchemaByRef(schema, true);
1251
+ if (this.isOpenAPIArraySchema(schema)) {
1252
+ const { type, description, items, required } = schema;
1253
+ return {
1254
+ type,
1255
+ required: !!required,
1256
+ description,
1257
+ items: this.toBaseSchema(items, enums, schemaKey, upLevelSchemaKey)
1258
+ };
1259
+ } else {
1260
+ const { required = [], allOf, anyOf, description, enum: enum_, format, oneOf, properties = {} } = schema;
1261
+ let { type } = schema;
1262
+ if (enum_ && type !== "boolean") {
1263
+ const enumObject = {
1264
+ name: Base.upperCamelCase(Base.normalize(upLevelSchemaKey)) + Base.upperCamelCase(Base.normalize(schemaKey)),
1265
+ enum: [...new Set(enum_)]
1266
+ };
1267
+ const sameObject = Base.findSameSchema(enumObject, enums);
1268
+ if (!sameObject && Base.isValidEnumType(schema)) enums.push(enumObject);
1269
+ return {
1270
+ type: sameObject ? sameObject.name : Base.isBooleanEnum(schema) ? "boolean" : enumObject.name,
1271
+ required,
1272
+ description
1273
+ };
1274
+ }
1275
+ if (type === void 0 && Object.keys(properties).length > 0) type = "object";
1276
+ return {
1277
+ type,
1278
+ required,
1279
+ description,
1280
+ enum: enum_,
1281
+ format,
1282
+ allOf: allOf?.map((s) => Base.isRef(s) ? {
1283
+ ...s,
1284
+ ref: s.$ref,
1285
+ type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1286
+ } : this.toBaseSchema(s, enums)),
1287
+ anyOf: anyOf?.map((s) => Base.isRef(s) ? {
1288
+ ...s,
1289
+ ref: s.$ref,
1290
+ type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1291
+ } : this.toBaseSchema(s, enums)),
1292
+ oneOf: oneOf?.map((s) => Base.isRef(s) ? {
1293
+ ...s,
1294
+ ref: s.$ref,
1295
+ type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1296
+ } : this.toBaseSchema(s, enums)),
1297
+ properties: Object.keys(properties).reduce((acc, p) => {
1298
+ const propSchema = properties[p];
1299
+ return {
1300
+ ...acc,
1301
+ [p]: Base.isRef(propSchema) ? { type: Base.capitalize(Base.ref2name(propSchema.$ref, this.doc)) } : this.toBaseSchema(propSchema, enums, p, upLevelSchemaKey)
1302
+ };
1303
+ }, {})
1304
+ };
1305
+ }
1306
+ }
1307
+ /**
1308
+ * OpenAPI parameter to base parameter.
1309
+ */
1310
+ getParameterByRef(parameter, enums = [], upLevelSchemaKey = "") {
1311
+ if (Base.isRef(parameter)) {
1312
+ const refName = Base.ref2name(parameter.$ref, this.doc);
1313
+ const resolved = this.doc.parameters?.[refName];
1314
+ if (!resolved) throw new Error(`Parameter reference not found: ${parameter.$ref}`);
1315
+ parameter = resolved;
1316
+ }
1317
+ const p = parameter;
1318
+ const { name, required, description, type, items, enum: enum_, properties, schema } = p;
1319
+ if (enum_) {
1320
+ const type = Base.upperCamelCase(Base.normalize(upLevelSchemaKey)) + Base.upperCamelCase(Base.normalize(name));
1321
+ const enumSchema = {
1322
+ name: type,
1323
+ enum: [...new Set(enum_)]
1324
+ };
1325
+ const sameEnum = Base.findSameSchema(enumSchema, enums);
1326
+ if (!sameEnum && Base.isValidEnumType({
1327
+ type,
1328
+ enum: enum_
1329
+ })) enums.push(enumSchema);
1330
+ return {
1331
+ name,
1332
+ required,
1333
+ description,
1334
+ in: p.in,
1335
+ schema: { type: sameEnum?.name ?? type }
1336
+ };
1337
+ }
1338
+ if (items) return {
1339
+ name,
1340
+ required,
1341
+ description,
1342
+ in: p.in,
1343
+ schema: {
1344
+ type,
1345
+ items
1346
+ }
1347
+ };
1348
+ if (schema && Base.isRef(schema)) return {
1349
+ name,
1350
+ required,
1351
+ description,
1352
+ in: p.in,
1353
+ schema: { type: Base.capitalize(Base.ref2name(schema.$ref)) }
1354
+ };
1355
+ return {
1356
+ name,
1357
+ required,
1358
+ description,
1359
+ in: p.in,
1360
+ schema: {
1361
+ type,
1362
+ properties
1363
+ }
1364
+ };
1365
+ }
1366
+ /**
1367
+ * OpenAPI schema to base response
1368
+ */
1369
+ getResponseByRef(schema) {
1370
+ if (Base.isRef(schema)) schema = this.doc.responses[Base.ref2name(schema.$ref, this.doc)];
1371
+ const { schema: responseSchema } = schema;
1372
+ return [{
1373
+ type: "application/json",
1374
+ schema: responseSchema && this.getSchemaByRef(responseSchema, true)
1375
+ }];
1376
+ }
1377
+ init() {
1378
+ const { definitions = {}, responses = {}, paths = {} } = this.doc;
1379
+ const enums = [];
1380
+ const definitions_ = Object.keys(definitions).reduce((acc, key) => {
1381
+ const schema = definitions[key];
1382
+ return {
1383
+ ...acc,
1384
+ [key]: this.getSchemaByRef(schema, false, enums, key)
1385
+ };
1386
+ }, {});
1387
+ const responses_ = Object.keys(responses).reduce((acc, key) => {
1388
+ const response = responses[key];
1389
+ return {
1390
+ ...acc,
1391
+ [key]: this.getResponseByRef(response)
1392
+ };
1393
+ }, {});
1394
+ const apis = Object.keys(paths).reduce((acc, path) => {
1395
+ let pathObject = paths[path] ?? {};
1396
+ if (pathObject.$ref) {
1397
+ const resolved = this.resolvePathRef(pathObject.$ref);
1398
+ if (resolved) pathObject = resolved;
1399
+ }
1400
+ const { parameters = [] } = pathObject;
1401
+ const methodApis = [];
1402
+ Object.values(HttpMethods).forEach((method) => {
1403
+ const methodObject = pathObject[method];
1404
+ if (methodObject) {
1405
+ const { deprecated, operationId, summary: summary_, description: description_, responses = {} } = methodObject;
1406
+ const { parameters: parameters_ = [] } = methodObject;
1407
+ const baseParameters = [...parameters, ...parameters_].map((parameter) => this.getParameterByRef(parameter, enums));
1408
+ const uniqueParameterName = [...new Set(baseParameters.map((p) => p.name))];
1409
+ if (Object.keys(responses).length === 0) Object.assign(responses, { 200: { description: "Successful response" } });
1410
+ const inBody = baseParameters.filter((p) => p.in === "body" || p.in === "formData");
1411
+ const notInBody = baseParameters.filter((p) => p.in !== "body" && p.in !== "formData");
1412
+ const httpCodes = Object.keys(responses);
1413
+ for (const code of httpCodes) if (code in responses) {
1414
+ const response = responses[code];
1415
+ const responseSchema = this.getResponseByRef(response);
1416
+ const inBodyOnlyHasBody = inBody && inBody.length === 1 && inBody[0].in === "body" && inBody[0].name === "body";
1417
+ methodApis.push({
1418
+ method,
1419
+ operationId,
1420
+ summary: summary_,
1421
+ deprecated,
1422
+ description: description_,
1423
+ parameters: uniqueParameterName.map((name) => notInBody.find((p) => p.name === name)).filter(Boolean),
1424
+ responses: responseSchema,
1425
+ requestBody: inBody.length > 0 ? inBodyOnlyHasBody ? [{
1426
+ type: "application/json",
1427
+ schema: inBody[0].schema
1428
+ }] : [{
1429
+ type: "application/json",
1430
+ schema: {
1431
+ type: "object",
1432
+ properties: inBody.reduce((a, p) => {
1433
+ return {
1434
+ ...a,
1435
+ [p.name]: {
1436
+ type: p.schema?.type ?? "unknown",
1437
+ required: p.schema?.required,
1438
+ items: p.schema?.items,
1439
+ description: p.schema?.description
1440
+ }
1441
+ };
1442
+ }, {})
1443
+ }
1444
+ }] : void 0
1445
+ });
1446
+ break;
1447
+ }
1448
+ }
1449
+ });
1450
+ return {
1451
+ ...acc,
1452
+ [path]: methodApis
1453
+ };
1454
+ }, {});
1455
+ return {
1456
+ enums: Base.uniqueEnums(enums),
1457
+ schemas: definitions_,
1458
+ responses: responses_,
1459
+ parameters: {},
1460
+ requestBodies: {},
1461
+ apis
1462
+ };
1463
+ }
1609
1464
  };
1610
-
1611
- // src/openapi/V3.ts
1465
+ //#endregion
1466
+ //#region src/openapi/V3.ts
1612
1467
  var V3 = class {
1613
- doc;
1614
- constructor(doc) {
1615
- this.doc = doc;
1616
- }
1617
- /**
1618
- * Is array schema.
1619
- */
1620
- isOpenAPIArraySchema(schema) {
1621
- return typeof schema === "object" && schema.type === "array";
1622
- }
1623
- /**
1624
- * OpenAPI schema to base schema.
1625
- */
1626
- getSchemaByRef(schema, reserveRef = false, enums = [], upLevelSchemaKey = "") {
1627
- let refName = "";
1628
- if (Base.isRef(schema)) {
1629
- refName = Base.capitalize(Base.ref2name(schema.$ref));
1630
- if (reserveRef) {
1631
- return {
1632
- type: upLevelSchemaKey + refName
1633
- };
1634
- }
1635
- const resolvedSchema = this.doc.components?.schemas?.[Base.ref2name(schema.$ref, this.doc)];
1636
- if (!resolvedSchema) {
1637
- return { type: "unknown" };
1638
- }
1639
- schema = resolvedSchema;
1640
- }
1641
- return this.toBaseSchema(schema, enums, "", upLevelSchemaKey + refName);
1642
- }
1643
- /**
1644
- * OpenAPI parameter to base parameter.
1645
- */
1646
- getParameterByRef(schema, enums = [], upLevelSchemaKey = "") {
1647
- if (Base.isRef(schema)) {
1648
- const resolvedSchema = this.doc.components?.parameters?.[Base.ref2name(schema.$ref, this.doc)];
1649
- if (!resolvedSchema) {
1650
- return {
1651
- name: "unknown",
1652
- in: "query"
1653
- };
1654
- }
1655
- schema = resolvedSchema;
1656
- }
1657
- const {
1658
- name,
1659
- required,
1660
- deprecated,
1661
- description,
1662
- schema: parameterSchema
1663
- } = schema;
1664
- if (parameterSchema && !Base.isRef(parameterSchema) && parameterSchema.enum) {
1665
- const type = Base.upperCamelCase(Base.normalize(upLevelSchemaKey)) + Base.upperCamelCase(Base.normalize(name));
1666
- const enumSchema = {
1667
- name: type,
1668
- enum: [...new Set(parameterSchema.enum)]
1669
- };
1670
- const sameEnum = Base.findSameSchema(enumSchema, enums);
1671
- if (!sameEnum && Base.isValidEnumType(parameterSchema)) {
1672
- enums.push(enumSchema);
1673
- }
1674
- return {
1675
- name,
1676
- required,
1677
- description,
1678
- deprecated,
1679
- in: schema.in,
1680
- schema: {
1681
- type: sameEnum?.name ?? type
1682
- }
1683
- };
1684
- }
1685
- return {
1686
- name,
1687
- required,
1688
- description,
1689
- deprecated,
1690
- in: schema.in,
1691
- schema: schema.schema && this.getSchemaByRef(
1692
- schema.schema,
1693
- false,
1694
- enums,
1695
- upLevelSchemaKey + Base.capitalize(name)
1696
- )
1697
- };
1698
- }
1699
- /**
1700
- * OpenAPI schema to base response
1701
- */
1702
- getResponseByRef(schema) {
1703
- if (Base.isRef(schema)) {
1704
- const resolvedSchema = this.doc.components?.responses?.[Base.ref2name(schema.$ref, this.doc)];
1705
- if (!resolvedSchema) {
1706
- return [];
1707
- }
1708
- schema = resolvedSchema;
1709
- }
1710
- const { content = {} } = schema;
1711
- return Object.keys(content).map((c) => ({
1712
- type: c,
1713
- schema: content[c].schema && this.getSchemaByRef(content[c].schema, true)
1714
- }));
1715
- }
1716
- /**
1717
- * OpenAPI schema to requestBody.
1718
- */
1719
- getRequestBodyByRef(schema, enums = []) {
1720
- if (Base.isRef(schema)) {
1721
- const resolvedSchema = this.doc.components?.requestBodies?.[Base.ref2name(schema.$ref, this.doc)];
1722
- if (!resolvedSchema) {
1723
- return [];
1724
- }
1725
- schema = resolvedSchema;
1726
- }
1727
- const { content = {} } = schema;
1728
- return Object.keys(content).map((c) => ({
1729
- type: c,
1730
- schema: content[c].schema && this.getSchemaByRef(content[c].schema, false, enums)
1731
- }));
1732
- }
1733
- /**
1734
- * Transform all OpenAPI schema to Base Schema
1735
- */
1736
- toBaseSchema(schema, enums = [], schemaKey = "", upLevelSchemaKey = "") {
1737
- if (!schema) {
1738
- return {
1739
- type: "unknown"
1740
- };
1741
- }
1742
- if (Base.isRef(schema)) {
1743
- return this.getSchemaByRef(schema, true);
1744
- }
1745
- if (this.isOpenAPIArraySchema(schema)) {
1746
- const { type, description, items, required } = schema;
1747
- return {
1748
- type,
1749
- required: !!required,
1750
- description,
1751
- items: this.toBaseSchema(items, enums, schemaKey, upLevelSchemaKey)
1752
- };
1753
- } else {
1754
- const {
1755
- required = [],
1756
- allOf,
1757
- anyOf,
1758
- description,
1759
- deprecated,
1760
- enum: enum_,
1761
- format: format2,
1762
- oneOf,
1763
- properties = {}
1764
- } = schema;
1765
- let { type } = schema;
1766
- if (enum_ && type !== "boolean") {
1767
- const name = Base.upperCamelCase(Base.normalize(upLevelSchemaKey)) + Base.upperCamelCase(Base.normalize(schemaKey));
1768
- const enumObject = {
1769
- name,
1770
- enum: [...new Set(enum_)]
1771
- };
1772
- const sameObject = Base.findSameSchema(enumObject, enums);
1773
- if (!sameObject && Base.isValidEnumType(schema)) {
1774
- enums.push(enumObject);
1775
- }
1776
- return {
1777
- type: sameObject ? sameObject.name : Base.isBooleanEnum(schema) ? "boolean" : enumObject.name,
1778
- required,
1779
- description,
1780
- deprecated
1781
- };
1782
- }
1783
- if (type === void 0 && Object.keys(properties).length > 0) {
1784
- type = "object" /* object */;
1785
- }
1786
- return {
1787
- type,
1788
- required,
1789
- description,
1790
- deprecated,
1791
- enum: enum_,
1792
- format: format2,
1793
- allOf: allOf?.map(
1794
- (s) => Base.isRef(s) ? {
1795
- ...s,
1796
- ref: s.$ref,
1797
- type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1798
- } : this.toBaseSchema(s, enums)
1799
- ),
1800
- anyOf: anyOf?.map(
1801
- (s) => Base.isRef(s) ? {
1802
- ...s,
1803
- ref: s.$ref,
1804
- type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1805
- } : this.toBaseSchema(s, enums)
1806
- ),
1807
- oneOf: oneOf?.map(
1808
- (s) => Base.isRef(s) ? {
1809
- ...s,
1810
- ref: s.$ref,
1811
- type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1812
- } : this.toBaseSchema(s, enums)
1813
- ),
1814
- properties: Object.keys(properties).reduce((acc, p) => {
1815
- const propSchema = properties[p];
1816
- return {
1817
- ...acc,
1818
- [p]: Base.isRef(propSchema) ? {
1819
- type: Base.capitalize(
1820
- Base.ref2name(propSchema.$ref, this.doc)
1821
- )
1822
- } : this.toBaseSchema(propSchema, enums, p, upLevelSchemaKey)
1823
- };
1824
- }, {})
1825
- };
1826
- }
1827
- }
1828
- init() {
1829
- const { components = {}, paths = {} } = this.doc;
1830
- const enums = [];
1831
- const {
1832
- requestBodies = {},
1833
- responses = {},
1834
- parameters = {},
1835
- schemas = {}
1836
- } = components;
1837
- const schemas_ = Object.keys(schemas).reduce((acc, key) => {
1838
- const schema = schemas[key];
1839
- return {
1840
- ...acc,
1841
- [key]: this.getSchemaByRef(schema, false, enums, key)
1842
- };
1843
- }, {});
1844
- const parameters_ = Object.keys(parameters).reduce((acc, key) => {
1845
- const parameter = parameters[key];
1846
- return {
1847
- ...acc,
1848
- [key]: this.getParameterByRef(parameter, enums, key)
1849
- };
1850
- }, {});
1851
- const responses_ = Object.keys(responses).reduce((acc, key) => {
1852
- const response = responses[key];
1853
- return {
1854
- ...acc,
1855
- [key]: this.getResponseByRef(response)
1856
- };
1857
- }, {});
1858
- const requestBodies_ = Object.keys(requestBodies).reduce((acc, key) => {
1859
- const requestBody = requestBodies[key];
1860
- return {
1861
- ...acc,
1862
- [key]: this.getRequestBodyByRef(requestBody, enums)
1863
- };
1864
- }, {});
1865
- const apis = Object.keys(paths).reduce((acc, path) => {
1866
- const pathObject = paths[path] ?? {};
1867
- const { $ref } = pathObject;
1868
- const methodApis = [];
1869
- if ($ref) {
1870
- } else {
1871
- const { parameters: parameters2 = [], description, summary } = pathObject;
1872
- Object.values(HttpMethods).forEach((method) => {
1873
- const methodObject = pathObject[method];
1874
- if (methodObject) {
1875
- const {
1876
- deprecated,
1877
- operationId,
1878
- responses: responses2 = {},
1879
- summary: summary_,
1880
- description: description_,
1881
- requestBody = { content: {} }
1882
- } = methodObject;
1883
- const { parameters: parameters_2 = [] } = methodObject;
1884
- const baseParameters = [...parameters2, ...parameters_2].map(
1885
- (parameter) => this.getParameterByRef(parameter, enums)
1886
- );
1887
- const baseRequestBody = this.getRequestBodyByRef(
1888
- requestBody,
1889
- enums
1890
- );
1891
- const uniqueParameterName = [
1892
- ...new Set(baseParameters.map((p) => p.name))
1893
- ];
1894
- if (Object.keys(responses2).length === 0) {
1895
- Object.assign(responses2, {
1896
- 200: {
1897
- description: "Successful response"
1898
- }
1899
- });
1900
- }
1901
- const httpCodes = Object.keys(responses2);
1902
- for (const code of httpCodes) {
1903
- if (code in responses2) {
1904
- const response = responses2[code];
1905
- const responseSchema = this.getResponseByRef(response);
1906
- methodApis.push({
1907
- method,
1908
- operationId,
1909
- summary: summary_ ?? summary,
1910
- description: description_ ?? description,
1911
- deprecated,
1912
- parameters: uniqueParameterName.map(
1913
- (name) => baseParameters.find((p) => p.name === name)
1914
- ),
1915
- responses: responseSchema,
1916
- requestBody: baseRequestBody
1917
- });
1918
- break;
1919
- }
1920
- }
1921
- }
1922
- });
1923
- }
1924
- return {
1925
- ...acc,
1926
- [path]: methodApis
1927
- };
1928
- }, {});
1929
- return {
1930
- enums: Base.uniqueEnums(enums),
1931
- schemas: schemas_,
1932
- responses: responses_,
1933
- parameters: parameters_,
1934
- requestBodies: requestBodies_,
1935
- apis
1936
- };
1937
- }
1468
+ doc;
1469
+ constructor(doc) {
1470
+ this.doc = doc;
1471
+ }
1472
+ /**
1473
+ * Resolves a path $ref to the actual path object.
1474
+ */
1475
+ resolvePathRef($ref) {
1476
+ const refName = Base.ref2name($ref, this.doc);
1477
+ return this.doc.paths?.[refName];
1478
+ }
1479
+ /**
1480
+ * Is array schema.
1481
+ */
1482
+ isOpenAPIArraySchema(schema) {
1483
+ return typeof schema === "object" && schema.type === "array";
1484
+ }
1485
+ /**
1486
+ * OpenAPI schema to base schema.
1487
+ */
1488
+ getSchemaByRef(schema, reserveRef = false, enums = [], upLevelSchemaKey = "") {
1489
+ let refName = "";
1490
+ if (Base.isRef(schema)) {
1491
+ refName = Base.capitalize(Base.ref2name(schema.$ref));
1492
+ if (reserveRef) return { type: upLevelSchemaKey + refName };
1493
+ const resolvedSchema = this.doc.components?.schemas?.[Base.ref2name(schema.$ref, this.doc)];
1494
+ if (!resolvedSchema) return { type: "unknown" };
1495
+ schema = resolvedSchema;
1496
+ }
1497
+ return this.toBaseSchema(schema, enums, "", upLevelSchemaKey + refName);
1498
+ }
1499
+ /**
1500
+ * OpenAPI parameter to base parameter.
1501
+ */
1502
+ getParameterByRef(schema, enums = [], upLevelSchemaKey = "") {
1503
+ if (Base.isRef(schema)) {
1504
+ const resolvedSchema = this.doc.components?.parameters?.[Base.ref2name(schema.$ref, this.doc)];
1505
+ if (!resolvedSchema) return {
1506
+ name: "unknown",
1507
+ in: "query"
1508
+ };
1509
+ schema = resolvedSchema;
1510
+ }
1511
+ const { name, required, deprecated, description, schema: parameterSchema } = schema;
1512
+ if (parameterSchema && !Base.isRef(parameterSchema) && parameterSchema.enum) {
1513
+ const type = Base.upperCamelCase(Base.normalize(upLevelSchemaKey)) + Base.upperCamelCase(Base.normalize(name));
1514
+ const enumSchema = {
1515
+ name: type,
1516
+ enum: [...new Set(parameterSchema.enum)]
1517
+ };
1518
+ const sameEnum = Base.findSameSchema(enumSchema, enums);
1519
+ if (!sameEnum && Base.isValidEnumType(parameterSchema)) enums.push(enumSchema);
1520
+ return {
1521
+ name,
1522
+ required,
1523
+ description,
1524
+ deprecated,
1525
+ in: schema.in,
1526
+ schema: { type: sameEnum?.name ?? type }
1527
+ };
1528
+ }
1529
+ return {
1530
+ name,
1531
+ required,
1532
+ description,
1533
+ deprecated,
1534
+ in: schema.in,
1535
+ schema: schema.schema && this.getSchemaByRef(schema.schema, false, enums, upLevelSchemaKey + Base.capitalize(name))
1536
+ };
1537
+ }
1538
+ /**
1539
+ * OpenAPI schema to base response
1540
+ */
1541
+ getResponseByRef(schema) {
1542
+ if (Base.isRef(schema)) {
1543
+ const resolvedSchema = this.doc.components?.responses?.[Base.ref2name(schema.$ref, this.doc)];
1544
+ if (!resolvedSchema) return [];
1545
+ schema = resolvedSchema;
1546
+ }
1547
+ const { content = {} } = schema;
1548
+ return Object.keys(content).map((c) => ({
1549
+ type: c,
1550
+ schema: content[c].schema && this.getSchemaByRef(content[c].schema, true)
1551
+ }));
1552
+ }
1553
+ /**
1554
+ * OpenAPI schema to requestBody.
1555
+ */
1556
+ getRequestBodyByRef(schema, enums = []) {
1557
+ if (Base.isRef(schema)) {
1558
+ const resolvedSchema = this.doc.components?.requestBodies?.[Base.ref2name(schema.$ref, this.doc)];
1559
+ if (!resolvedSchema) return [];
1560
+ schema = resolvedSchema;
1561
+ }
1562
+ const { content = {} } = schema;
1563
+ return Object.keys(content).map((c) => ({
1564
+ type: c,
1565
+ schema: content[c].schema && this.getSchemaByRef(content[c].schema, false, enums)
1566
+ }));
1567
+ }
1568
+ /**
1569
+ * Transform all OpenAPI schema to Base Schema
1570
+ */
1571
+ toBaseSchema(schema, enums = [], schemaKey = "", upLevelSchemaKey = "") {
1572
+ if (!schema) return { type: "unknown" };
1573
+ if (Base.isRef(schema)) return this.getSchemaByRef(schema, true);
1574
+ if (this.isOpenAPIArraySchema(schema)) {
1575
+ const { type, description, items, required } = schema;
1576
+ return {
1577
+ type,
1578
+ required: !!required,
1579
+ description,
1580
+ items: this.toBaseSchema(items, enums, schemaKey, upLevelSchemaKey)
1581
+ };
1582
+ } else {
1583
+ const { required = [], allOf, anyOf, description, deprecated, enum: enum_, format, oneOf, properties = {} } = schema;
1584
+ let { type } = schema;
1585
+ if (enum_ && type !== "boolean") {
1586
+ const enumObject = {
1587
+ name: Base.upperCamelCase(Base.normalize(upLevelSchemaKey)) + Base.upperCamelCase(Base.normalize(schemaKey)),
1588
+ enum: [...new Set(enum_)]
1589
+ };
1590
+ const sameObject = Base.findSameSchema(enumObject, enums);
1591
+ if (!sameObject && Base.isValidEnumType(schema)) enums.push(enumObject);
1592
+ return {
1593
+ type: sameObject ? sameObject.name : Base.isBooleanEnum(schema) ? "boolean" : enumObject.name,
1594
+ required,
1595
+ description,
1596
+ deprecated
1597
+ };
1598
+ }
1599
+ if (type === void 0 && Object.keys(properties).length > 0) type = "object";
1600
+ return {
1601
+ type,
1602
+ required,
1603
+ description,
1604
+ deprecated,
1605
+ enum: enum_,
1606
+ format,
1607
+ allOf: allOf?.map((s) => Base.isRef(s) ? {
1608
+ ...s,
1609
+ ref: s.$ref,
1610
+ type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1611
+ } : this.toBaseSchema(s, enums)),
1612
+ anyOf: anyOf?.map((s) => Base.isRef(s) ? {
1613
+ ...s,
1614
+ ref: s.$ref,
1615
+ type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1616
+ } : this.toBaseSchema(s, enums)),
1617
+ oneOf: oneOf?.map((s) => Base.isRef(s) ? {
1618
+ ...s,
1619
+ ref: s.$ref,
1620
+ type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1621
+ } : this.toBaseSchema(s, enums)),
1622
+ properties: Object.keys(properties).reduce((acc, p) => {
1623
+ const propSchema = properties[p];
1624
+ return {
1625
+ ...acc,
1626
+ [p]: Base.isRef(propSchema) ? {
1627
+ type: Base.capitalize(Base.ref2name(propSchema.$ref, this.doc)),
1628
+ isRef: true
1629
+ } : this.toBaseSchema(propSchema, enums, p, upLevelSchemaKey)
1630
+ };
1631
+ }, {})
1632
+ };
1633
+ }
1634
+ }
1635
+ init() {
1636
+ const { components = {}, paths = {} } = this.doc;
1637
+ const enums = [];
1638
+ const { requestBodies = {}, responses = {}, parameters = {}, schemas = {} } = components;
1639
+ const schemas_ = Object.keys(schemas).reduce((acc, key) => {
1640
+ const schema = schemas[key];
1641
+ return {
1642
+ ...acc,
1643
+ [key]: this.getSchemaByRef(schema, false, enums, key)
1644
+ };
1645
+ }, {});
1646
+ const parameters_ = Object.keys(parameters).reduce((acc, key) => {
1647
+ const parameter = parameters[key];
1648
+ return {
1649
+ ...acc,
1650
+ [key]: this.getParameterByRef(parameter, enums, key)
1651
+ };
1652
+ }, {});
1653
+ const responses_ = Object.keys(responses).reduce((acc, key) => {
1654
+ const response = responses[key];
1655
+ return {
1656
+ ...acc,
1657
+ [key]: this.getResponseByRef(response)
1658
+ };
1659
+ }, {});
1660
+ const requestBodies_ = Object.keys(requestBodies).reduce((acc, key) => {
1661
+ const requestBody = requestBodies[key];
1662
+ return {
1663
+ ...acc,
1664
+ [key]: this.getRequestBodyByRef(requestBody, enums)
1665
+ };
1666
+ }, {});
1667
+ const apis = Object.keys(paths).reduce((acc, path) => {
1668
+ let pathObject = paths[path] ?? {};
1669
+ if (pathObject.$ref) {
1670
+ const resolved = this.resolvePathRef(pathObject.$ref);
1671
+ if (resolved) pathObject = resolved;
1672
+ }
1673
+ const { parameters = [], description, summary } = pathObject;
1674
+ const methodApis = [];
1675
+ Object.values(HttpMethods).forEach((method) => {
1676
+ const methodObject = pathObject[method];
1677
+ if (methodObject) {
1678
+ const { deprecated, operationId, responses = {}, summary: summary_, description: description_, requestBody = { content: {} } } = methodObject;
1679
+ const { parameters: parameters_ = [] } = methodObject;
1680
+ const baseParameters = [...parameters, ...parameters_].map((parameter) => this.getParameterByRef(parameter, enums));
1681
+ const baseRequestBody = this.getRequestBodyByRef(requestBody, enums);
1682
+ const uniqueParameterName = [...new Set(baseParameters.map((p) => p.name))];
1683
+ if (Object.keys(responses).length === 0) Object.assign(responses, { 200: { description: "Successful response" } });
1684
+ const httpCodes = Object.keys(responses);
1685
+ for (const code of httpCodes) if (code in responses) {
1686
+ const response = responses[code];
1687
+ const responseSchema = this.getResponseByRef(response);
1688
+ methodApis.push({
1689
+ method,
1690
+ operationId,
1691
+ summary: summary_ ?? summary,
1692
+ description: description_ ?? description,
1693
+ deprecated,
1694
+ parameters: uniqueParameterName.map((name) => baseParameters.find((p) => p.name === name)).filter((p) => p !== void 0),
1695
+ responses: responseSchema,
1696
+ requestBody: baseRequestBody
1697
+ });
1698
+ break;
1699
+ }
1700
+ }
1701
+ });
1702
+ return {
1703
+ ...acc,
1704
+ [path]: methodApis
1705
+ };
1706
+ }, {});
1707
+ return {
1708
+ enums: Base.uniqueEnums(enums),
1709
+ schemas: schemas_,
1710
+ responses: responses_,
1711
+ parameters: parameters_,
1712
+ requestBodies: requestBodies_,
1713
+ apis
1714
+ };
1715
+ }
1938
1716
  };
1939
-
1940
- // src/openapi/V3_1.ts
1717
+ //#endregion
1718
+ //#region src/openapi/V3_1.ts
1941
1719
  var V3_1 = class {
1942
- doc;
1943
- constructor(doc) {
1944
- this.doc = doc;
1945
- }
1946
- /**
1947
- * Is array schema.
1948
- */
1949
- isOpenAPIArraySchema(schema) {
1950
- return typeof schema === "object" && schema.type === "array";
1951
- }
1952
- /**
1953
- * OpenAPI schema to base schema.
1954
- */
1955
- getSchemaByRef(schema, reserveRef = false, enums = [], upLevelSchemaKey = "") {
1956
- let refName = "";
1957
- if (Base.isRef(schema)) {
1958
- refName = Base.upperCamelCase(Base.ref2name(schema.$ref));
1959
- if (reserveRef) {
1960
- return {
1961
- type: upLevelSchemaKey + refName
1962
- };
1963
- }
1964
- if (!this.doc.components) {
1965
- this.doc.components = {
1966
- schemas: {}
1967
- };
1968
- }
1969
- schema = this.doc.components.schemas[Base.ref2name(schema.$ref, this.doc)];
1970
- }
1971
- return this.toBaseSchema(schema, enums, "", upLevelSchemaKey + refName);
1972
- }
1973
- /**
1974
- * OpenAPI parameter to base parameter.
1975
- */
1976
- getParameterByRef(schema, enums = [], upLevelSchemaKey = "") {
1977
- if (Base.isRef(schema)) {
1978
- schema = this.doc.components?.parameters?.[Base.ref2name(schema.$ref, this.doc)];
1979
- }
1980
- const {
1981
- name,
1982
- required,
1983
- deprecated,
1984
- description,
1985
- schema: parameterSchema
1986
- } = schema;
1987
- if (parameterSchema && !Base.isRef(parameterSchema) && parameterSchema.enum) {
1988
- const type = Base.upperCamelCase(upLevelSchemaKey) + Base.upperCamelCase(name);
1989
- const enumSchema = {
1990
- name: type,
1991
- enum: [...new Set(parameterSchema.enum)]
1992
- };
1993
- const sameEnum = Base.findSameSchema(enumSchema, enums);
1994
- if (!sameEnum && Base.isValidEnumType(parameterSchema)) {
1995
- enums.push(enumSchema);
1996
- }
1997
- return {
1998
- name,
1999
- required,
2000
- description,
2001
- deprecated,
2002
- in: schema.in,
2003
- schema: {
2004
- type: sameEnum?.name ?? type
2005
- }
2006
- };
2007
- }
2008
- return {
2009
- name,
2010
- required,
2011
- description,
2012
- deprecated,
2013
- in: schema.in,
2014
- schema: schema.schema && this.getSchemaByRef(
2015
- schema.schema,
2016
- false,
2017
- enums,
2018
- upLevelSchemaKey + Base.capitalize(name)
2019
- )
2020
- };
2021
- }
2022
- /**
2023
- * OpenAPI schema to base response
2024
- */
2025
- getResponseByRef(schema) {
2026
- if (Base.isRef(schema)) {
2027
- schema = this.doc.components?.responses?.[Base.ref2name(schema.$ref, this.doc)];
2028
- }
2029
- const { content = {} } = schema;
2030
- return Object.keys(content).map((c) => ({
2031
- type: c,
2032
- schema: content[c].schema && this.getSchemaByRef(content[c].schema, true)
2033
- }));
2034
- }
2035
- /**
2036
- * OpenAPI schema to requestBody.
2037
- */
2038
- getRequestBodyByRef(schema, enums = [], reserveRef = false) {
2039
- if (Base.isRef(schema)) {
2040
- schema = this.doc.components?.requestBodies?.[Base.ref2name(schema.$ref, this.doc)];
2041
- }
2042
- const { content = {} } = schema;
2043
- return Object.keys(content).map((c) => ({
2044
- type: c,
2045
- schema: content[c].schema && this.getSchemaByRef(content[c].schema, reserveRef, enums)
2046
- }));
2047
- }
2048
- /**
2049
- * Transform all OpenAPI schema to Base Schema
2050
- */
2051
- toBaseSchema(schema, enums = [], schemaKey = "", upLevelSchemaKey = "") {
2052
- if (!schema) {
2053
- return {
2054
- type: "unknown"
2055
- };
2056
- }
2057
- if (Base.isRef(schema)) {
2058
- return this.getSchemaByRef(schema, true);
2059
- }
2060
- if (this.isOpenAPIArraySchema(schema)) {
2061
- const { type, description, items, required } = schema;
2062
- return {
2063
- type,
2064
- required: !!required,
2065
- description,
2066
- items: this.toBaseSchema(items, enums, schemaKey, upLevelSchemaKey)
2067
- };
2068
- } else {
2069
- const {
2070
- required = [],
2071
- allOf,
2072
- anyOf,
2073
- description,
2074
- deprecated,
2075
- enum: enum_,
2076
- format: format2,
2077
- oneOf,
2078
- properties = {}
2079
- } = schema;
2080
- let { type } = schema;
2081
- if (enum_ && type !== "boolean") {
2082
- const name = Base.upperCamelCase(upLevelSchemaKey) + Base.upperCamelCase(schemaKey);
2083
- const enumObject = {
2084
- name,
2085
- enum: [...new Set(enum_)]
2086
- };
2087
- const sameObject = Base.findSameSchema(enumObject, enums);
2088
- if (!sameObject && Base.isValidEnumType(schema)) {
2089
- enums.push(enumObject);
2090
- }
2091
- return {
2092
- type: sameObject ? sameObject.name : Base.isBooleanEnum(schema) ? "boolean" : enumObject.name,
2093
- required,
2094
- description,
2095
- deprecated
2096
- };
2097
- }
2098
- if (type === void 0 && Object.keys(properties).length > 0) {
2099
- type = "object" /* object */;
2100
- }
2101
- return {
2102
- type,
2103
- required,
2104
- description,
2105
- deprecated,
2106
- enum: enum_,
2107
- format: format2,
2108
- allOf: allOf?.map(
2109
- (s) => Base.isRef(s) ? {
2110
- ...s,
2111
- ref: s.$ref,
2112
- type: Base.upperCamelCase(Base.ref2name(s.$ref, this.doc))
2113
- } : this.toBaseSchema(s, enums)
2114
- ),
2115
- anyOf: anyOf?.map(
2116
- (s) => Base.isRef(s) ? {
2117
- ...s,
2118
- ref: s.$ref,
2119
- type: Base.upperCamelCase(Base.ref2name(s.$ref, this.doc))
2120
- } : this.toBaseSchema(s, enums)
2121
- ),
2122
- oneOf: oneOf?.map(
2123
- (s) => Base.isRef(s) ? {
2124
- ...s,
2125
- ref: s.$ref,
2126
- type: Base.upperCamelCase(Base.ref2name(s.$ref, this.doc))
2127
- } : this.toBaseSchema(s, enums)
2128
- ),
2129
- properties: Object.keys(properties).reduce((acc, p) => {
2130
- const propSchema = properties[p];
2131
- return {
2132
- ...acc,
2133
- [p]: Base.isRef(propSchema) ? {
2134
- type: Base.upperCamelCase(
2135
- Base.ref2name(propSchema.$ref, this.doc)
2136
- )
2137
- } : this.toBaseSchema(propSchema, enums, p, upLevelSchemaKey)
2138
- };
2139
- }, {})
2140
- };
2141
- }
2142
- }
2143
- init() {
2144
- const { components = {}, paths = {} } = this.doc;
2145
- const enums = [];
2146
- const {
2147
- requestBodies = {},
2148
- responses = {},
2149
- parameters = {},
2150
- schemas = {}
2151
- } = components;
2152
- const schemas_ = Object.keys(schemas).reduce((acc, key) => {
2153
- const schema = schemas[key];
2154
- return {
2155
- ...acc,
2156
- [key]: this.getSchemaByRef(schema, false, enums, key)
2157
- };
2158
- }, {});
2159
- const parameters_ = Object.keys(parameters).reduce((acc, key) => {
2160
- const parameter = parameters[key];
2161
- return {
2162
- ...acc,
2163
- [key]: this.getParameterByRef(parameter, enums, key)
2164
- };
2165
- }, {});
2166
- const responses_ = Object.keys(responses).reduce((acc, key) => {
2167
- const response = responses[key];
2168
- return {
2169
- ...acc,
2170
- [key]: this.getResponseByRef(response)
2171
- };
2172
- }, {});
2173
- const requestBodies_ = Object.keys(requestBodies).reduce((acc, key) => {
2174
- const requestBody = requestBodies[key];
2175
- return {
2176
- ...acc,
2177
- [key]: this.getRequestBodyByRef(requestBody, enums)
2178
- };
2179
- }, {});
2180
- const apis = Object.keys(paths).reduce((acc, path) => {
2181
- const pathObject = paths[path] ?? {};
2182
- const { $ref } = pathObject;
2183
- const methodApis = [];
2184
- if ($ref) {
2185
- } else {
2186
- const { parameters: parameters2 = [], description, summary } = pathObject;
2187
- Object.values(HttpMethods).forEach((method) => {
2188
- const methodObject = pathObject[method];
2189
- if (methodObject) {
2190
- const {
2191
- deprecated,
2192
- operationId,
2193
- summary: summary_,
2194
- description: description_,
2195
- responses: responses2 = {},
2196
- requestBody = { content: {} }
2197
- } = methodObject;
2198
- const { parameters: parameters_2 = [] } = methodObject;
2199
- const baseParameters = [...parameters2, ...parameters_2].map(
2200
- (parameter) => this.getParameterByRef(parameter, enums)
2201
- );
2202
- const baseRequestBody = this.getRequestBodyByRef(
2203
- requestBody,
2204
- enums,
2205
- true
2206
- );
2207
- const uniqueParameterName = [
2208
- ...new Set(baseParameters.map((p) => p.name))
2209
- ];
2210
- if (Object.keys(responses2).length === 0) {
2211
- Object.assign(responses2, {
2212
- 200: {
2213
- description: "Successful response"
2214
- }
2215
- });
2216
- }
2217
- const httpCodes = Object.keys(responses2);
2218
- for (const code of httpCodes) {
2219
- if (code in responses2) {
2220
- const response = responses2[code];
2221
- const responseSchema = this.getResponseByRef(response);
2222
- methodApis.push({
2223
- method,
2224
- operationId,
2225
- summary: summary_ ?? summary,
2226
- description: description_ ?? description,
2227
- deprecated,
2228
- parameters: uniqueParameterName.map(
2229
- (name) => baseParameters.find((p) => p.name === name)
2230
- ),
2231
- responses: responseSchema,
2232
- requestBody: baseRequestBody
2233
- });
2234
- break;
2235
- }
2236
- }
2237
- }
2238
- });
2239
- }
2240
- return {
2241
- ...acc,
2242
- [path]: methodApis
2243
- };
2244
- }, {});
2245
- return {
2246
- enums: Base.uniqueEnums(enums),
2247
- schemas: schemas_,
2248
- responses: responses_,
2249
- parameters: parameters_,
2250
- requestBodies: requestBodies_,
2251
- apis
2252
- };
2253
- }
1720
+ doc;
1721
+ constructor(doc) {
1722
+ this.doc = doc;
1723
+ }
1724
+ /**
1725
+ * Resolves a path $ref to the actual path object.
1726
+ */
1727
+ resolvePathRef($ref) {
1728
+ const refName = Base.ref2name($ref, this.doc);
1729
+ return this.doc.paths?.[refName];
1730
+ }
1731
+ /**
1732
+ * Is array schema.
1733
+ */
1734
+ isOpenAPIArraySchema(schema) {
1735
+ return typeof schema === "object" && schema.type === "array";
1736
+ }
1737
+ /**
1738
+ * OpenAPI schema to base schema.
1739
+ */
1740
+ getSchemaByRef(schema, reserveRef = false, enums = [], upLevelSchemaKey = "") {
1741
+ let refName = "";
1742
+ if (Base.isRef(schema)) {
1743
+ refName = Base.upperCamelCase(Base.ref2name(schema.$ref));
1744
+ if (reserveRef) return { type: upLevelSchemaKey + refName };
1745
+ if (!this.doc.components) this.doc.components = { schemas: {} };
1746
+ const resolvedSchema = this.doc.components.schemas?.[Base.ref2name(schema.$ref, this.doc)];
1747
+ if (!resolvedSchema) throw new Error(`Schema reference not found: ${refName}`);
1748
+ schema = resolvedSchema;
1749
+ }
1750
+ return this.toBaseSchema(schema, enums, "", upLevelSchemaKey + refName);
1751
+ }
1752
+ /**
1753
+ * OpenAPI parameter to base parameter.
1754
+ */
1755
+ getParameterByRef(schema, enums = [], upLevelSchemaKey = "") {
1756
+ if (Base.isRef(schema)) schema = this.doc.components?.parameters?.[Base.ref2name(schema.$ref, this.doc)];
1757
+ const { name, required, deprecated, description, schema: parameterSchema } = schema;
1758
+ if (parameterSchema && !Base.isRef(parameterSchema) && parameterSchema.enum) {
1759
+ const type = Base.upperCamelCase(Base.normalize(upLevelSchemaKey)) + Base.upperCamelCase(Base.normalize(name));
1760
+ const enumSchema = {
1761
+ name: type,
1762
+ enum: [...new Set(parameterSchema.enum)]
1763
+ };
1764
+ const sameEnum = Base.findSameSchema(enumSchema, enums);
1765
+ if (!sameEnum && Base.isValidEnumType(parameterSchema)) enums.push(enumSchema);
1766
+ return {
1767
+ name,
1768
+ required,
1769
+ description,
1770
+ deprecated,
1771
+ in: schema.in,
1772
+ schema: { type: sameEnum?.name ?? type }
1773
+ };
1774
+ }
1775
+ return {
1776
+ name,
1777
+ required,
1778
+ description,
1779
+ deprecated,
1780
+ in: schema.in,
1781
+ schema: schema.schema && this.getSchemaByRef(schema.schema, false, enums, upLevelSchemaKey + Base.capitalize(name))
1782
+ };
1783
+ }
1784
+ /**
1785
+ * OpenAPI schema to base response
1786
+ */
1787
+ getResponseByRef(schema) {
1788
+ if (Base.isRef(schema)) schema = this.doc.components?.responses?.[Base.ref2name(schema.$ref, this.doc)];
1789
+ const { content = {} } = schema;
1790
+ return Object.keys(content).map((c) => ({
1791
+ type: c,
1792
+ schema: content[c].schema && this.getSchemaByRef(content[c].schema, true)
1793
+ }));
1794
+ }
1795
+ /**
1796
+ * OpenAPI schema to requestBody.
1797
+ */
1798
+ getRequestBodyByRef(schema, enums = []) {
1799
+ if (Base.isRef(schema)) schema = this.doc.components?.requestBodies?.[Base.ref2name(schema.$ref, this.doc)];
1800
+ const { content = {} } = schema;
1801
+ return Object.keys(content).map((c) => ({
1802
+ type: c,
1803
+ schema: content[c].schema && this.getSchemaByRef(content[c].schema, true, enums)
1804
+ }));
1805
+ }
1806
+ /**
1807
+ * Transform all OpenAPI schema to Base Schema
1808
+ */
1809
+ toBaseSchema(schema, enums = [], schemaKey = "", upLevelSchemaKey = "") {
1810
+ if (!schema) return { type: "unknown" };
1811
+ if (Base.isRef(schema)) return this.getSchemaByRef(schema, true);
1812
+ if (this.isOpenAPIArraySchema(schema)) {
1813
+ const { type, description, items, required } = schema;
1814
+ return {
1815
+ type,
1816
+ required: !!required,
1817
+ description,
1818
+ items: this.toBaseSchema(items, enums, schemaKey, upLevelSchemaKey)
1819
+ };
1820
+ } else {
1821
+ const { required = [], allOf, anyOf, description, deprecated, enum: enum_, format, oneOf, properties = {} } = schema;
1822
+ let { type } = schema;
1823
+ if (enum_ && type !== "boolean") {
1824
+ const enumObject = {
1825
+ name: Base.upperCamelCase(Base.normalize(upLevelSchemaKey)) + Base.upperCamelCase(Base.normalize(schemaKey)),
1826
+ enum: [...new Set(enum_)]
1827
+ };
1828
+ const sameObject = Base.findSameSchema(enumObject, enums);
1829
+ if (!sameObject && Base.isValidEnumType(schema)) enums.push(enumObject);
1830
+ return {
1831
+ type: sameObject ? sameObject.name : Base.isBooleanEnum(schema) ? "boolean" : enumObject.name,
1832
+ required,
1833
+ description,
1834
+ deprecated
1835
+ };
1836
+ }
1837
+ if (type === void 0 && Object.keys(properties).length > 0) type = "object";
1838
+ return {
1839
+ type,
1840
+ required,
1841
+ description,
1842
+ deprecated,
1843
+ enum: enum_,
1844
+ format,
1845
+ allOf: allOf?.map((s) => Base.isRef(s) ? {
1846
+ ...s,
1847
+ ref: s.$ref,
1848
+ type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1849
+ } : this.toBaseSchema(s, enums)),
1850
+ anyOf: anyOf?.map((s) => Base.isRef(s) ? {
1851
+ ...s,
1852
+ ref: s.$ref,
1853
+ type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1854
+ } : this.toBaseSchema(s, enums)),
1855
+ oneOf: oneOf?.map((s) => Base.isRef(s) ? {
1856
+ ...s,
1857
+ ref: s.$ref,
1858
+ type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1859
+ } : this.toBaseSchema(s, enums)),
1860
+ properties: Object.keys(properties).reduce((acc, p) => {
1861
+ const propSchema = properties[p];
1862
+ return {
1863
+ ...acc,
1864
+ [p]: Base.isRef(propSchema) ? {
1865
+ type: Base.capitalize(Base.ref2name(propSchema.$ref, this.doc)),
1866
+ isRef: true
1867
+ } : this.toBaseSchema(propSchema, enums, p, upLevelSchemaKey)
1868
+ };
1869
+ }, {})
1870
+ };
1871
+ }
1872
+ }
1873
+ init() {
1874
+ const { components = {}, paths = {} } = this.doc;
1875
+ const enums = [];
1876
+ const { requestBodies = {}, responses = {}, parameters = {}, schemas = {} } = components;
1877
+ const schemas_ = Object.keys(schemas).reduce((acc, key) => {
1878
+ const schema = schemas[key];
1879
+ return {
1880
+ ...acc,
1881
+ [key]: this.getSchemaByRef(schema, false, enums, key)
1882
+ };
1883
+ }, {});
1884
+ const parameters_ = Object.keys(parameters).reduce((acc, key) => {
1885
+ const parameter = parameters[key];
1886
+ return {
1887
+ ...acc,
1888
+ [key]: this.getParameterByRef(parameter, enums, key)
1889
+ };
1890
+ }, {});
1891
+ const responses_ = Object.keys(responses).reduce((acc, key) => {
1892
+ const response = responses[key];
1893
+ return {
1894
+ ...acc,
1895
+ [key]: this.getResponseByRef(response)
1896
+ };
1897
+ }, {});
1898
+ const requestBodies_ = Object.keys(requestBodies).reduce((acc, key) => {
1899
+ const requestBody = requestBodies[key];
1900
+ return {
1901
+ ...acc,
1902
+ [key]: this.getRequestBodyByRef(requestBody, enums)
1903
+ };
1904
+ }, {});
1905
+ const apis = Object.keys(paths).reduce((acc, path) => {
1906
+ let pathObject = paths[path] ?? {};
1907
+ if (pathObject.$ref) {
1908
+ const resolved = this.resolvePathRef(pathObject.$ref);
1909
+ if (resolved) pathObject = resolved;
1910
+ }
1911
+ const { parameters = [], description, summary } = pathObject;
1912
+ const methodApis = [];
1913
+ Object.values(HttpMethods).forEach((method) => {
1914
+ const methodObject = pathObject[method];
1915
+ if (methodObject) {
1916
+ const { deprecated, operationId, summary: summary_, description: description_, responses = {}, requestBody = { content: {} } } = methodObject;
1917
+ const { parameters: parameters_ = [] } = methodObject;
1918
+ const baseParameters = [...parameters, ...parameters_].map((parameter) => this.getParameterByRef(parameter, enums));
1919
+ const baseRequestBody = this.getRequestBodyByRef(requestBody, enums);
1920
+ const uniqueParameterName = [...new Set(baseParameters.map((p) => p.name))];
1921
+ if (Object.keys(responses).length === 0) Object.assign(responses, { 200: { description: "Successful response" } });
1922
+ const httpCodes = Object.keys(responses);
1923
+ for (const code of httpCodes) if (code in responses) {
1924
+ const response = responses[code];
1925
+ const responseSchema = this.getResponseByRef(response);
1926
+ methodApis.push({
1927
+ method,
1928
+ operationId,
1929
+ summary: summary_ ?? summary,
1930
+ description: description_ ?? description,
1931
+ deprecated,
1932
+ parameters: uniqueParameterName.map((name) => baseParameters.find((p) => p.name === name)).filter((p) => p !== void 0),
1933
+ responses: responseSchema,
1934
+ requestBody: baseRequestBody
1935
+ });
1936
+ break;
1937
+ }
1938
+ }
1939
+ });
1940
+ return {
1941
+ ...acc,
1942
+ [path]: methodApis
1943
+ };
1944
+ }, {});
1945
+ return {
1946
+ enums: Base.uniqueEnums(enums),
1947
+ schemas: schemas_,
1948
+ responses: responses_,
1949
+ parameters: parameters_,
1950
+ requestBodies: requestBodies_,
1951
+ apis
1952
+ };
1953
+ }
2254
1954
  };
2255
-
2256
- // src/openapi/index.ts
2257
- var logger = (0, import_logger.createScopedLogger)("OpenAPI");
2258
- var OpenAPIVersion = /* @__PURE__ */ ((OpenAPIVersion2) => {
2259
- OpenAPIVersion2["v2"] = "v2";
2260
- OpenAPIVersion2["v3"] = "v3";
2261
- OpenAPIVersion2["v3_1"] = "v3_1";
2262
- OpenAPIVersion2["unknown"] = "unknown";
2263
- return OpenAPIVersion2;
2264
- })(OpenAPIVersion || {});
1955
+ //#endregion
1956
+ //#region src/openapi/index.ts
1957
+ const logger$1 = (0, _moccona_logger.createScopedLogger)("OpenAPI");
1958
+ let OpenAPIVersion = /* @__PURE__ */ function(OpenAPIVersion) {
1959
+ OpenAPIVersion["v2"] = "v2";
1960
+ OpenAPIVersion["v3"] = "v3";
1961
+ OpenAPIVersion["v3_1"] = "v3_1";
1962
+ OpenAPIVersion["unknown"] = "unknown";
1963
+ return OpenAPIVersion;
1964
+ }({});
2265
1965
  function getDocVersion(doc) {
2266
- const version = (doc.openapi || doc.swagger).slice(0, 3);
2267
- switch (version) {
2268
- case "2.0":
2269
- return "v2" /* v2 */;
2270
- case "3.0":
2271
- return "v3" /* v3 */;
2272
- case "3.1":
2273
- return "v3_1" /* v3_1 */;
2274
- default:
2275
- return "unknown" /* unknown */;
2276
- }
1966
+ switch ((doc.openapi || doc.swagger).slice(0, 3)) {
1967
+ case "3.1": return "v3_1";
1968
+ case "3.0": return "v3";
1969
+ case "2.0": return "v2";
1970
+ default: return "unknown";
1971
+ }
2277
1972
  }
2278
1973
  var OpenAPIProvider = class extends Provider {
2279
- parse(doc) {
2280
- const version = getDocVersion(doc);
2281
- logger.debug(`openapi version ${version}`);
2282
- let returnValue;
2283
- switch (version) {
2284
- case "v2" /* v2 */:
2285
- returnValue = new V2(doc).init();
2286
- break;
2287
- case "v3" /* v3 */:
2288
- returnValue = new V3(doc).init();
2289
- break;
2290
- case "v3_1" /* v3_1 */:
2291
- returnValue = new V3_1(doc).init();
2292
- break;
2293
- default:
2294
- logger.error(`Not a valid OpenAPI version ${version}`);
2295
- process.exit(1);
2296
- }
2297
- return returnValue;
2298
- }
1974
+ parse(doc) {
1975
+ const version = getDocVersion(doc);
1976
+ logger$1.debug(`openapi version ${version}`);
1977
+ switch (version) {
1978
+ case "v2": return new V2(doc).init();
1979
+ case "v3": return new V3(doc).init();
1980
+ case "v3_1": return new V3_1(doc).init();
1981
+ default: throw new Error(`Not a valid OpenAPI version: ${version}`);
1982
+ }
1983
+ }
2299
1984
  };
2300
1985
  function getAdaptor(type) {
2301
- switch (type) {
2302
- case "axios" /* axios */:
2303
- return new AxiosAdapter();
2304
- case "fetch" /* fetch */:
2305
- return new FetchAdapter();
2306
- default:
2307
- throw TypeError(`Not Supported Adaptor ${type}`);
2308
- }
1986
+ switch (type) {
1987
+ case "axios": return new AxiosAdapter();
1988
+ default: return new FetchAdapter();
1989
+ }
2309
1990
  }
2310
1991
  async function codeGen(initOptions) {
2311
- const { verbose } = initOptions;
2312
- if (verbose) {
2313
- logger.setLevel("debug");
2314
- } else {
2315
- logger.setLevel("info");
2316
- }
2317
- logger.info(`Fech document from ${initOptions.docURL}`);
2318
- const doc = await Base.fetchDoc(
2319
- initOptions.docURL,
2320
- initOptions.requestOptions
2321
- );
2322
- const provider = new OpenAPIProvider(initOptions, doc);
2323
- const { enums, schemas, parameters, responses, requestBodies, apis } = provider;
2324
- const adaptor = getAdaptor(initOptions.adaptor ?? "fetch" /* fetch */);
2325
- const code = await Generator.genCode(
2326
- {
2327
- enums,
2328
- schemas,
2329
- parameters,
2330
- responses,
2331
- requestBodies,
2332
- apis
2333
- },
2334
- initOptions,
2335
- adaptor
2336
- );
2337
- if (process.env.NODE_ENV === "test") {
2338
- await Generator.write(code, initOptions.output);
2339
- }
2340
- return code;
1992
+ const startTime = Date.now();
1993
+ const { verbose } = initOptions;
1994
+ if (verbose) logger$1.setLevel("debug");
1995
+ else logger$1.setLevel("info");
1996
+ logger$1.info(`Fetch document from ${initOptions.docURL}`);
1997
+ const { enums, schemas, parameters, responses, requestBodies, apis } = new OpenAPIProvider(initOptions, await Base.fetchDoc(initOptions.docURL, initOptions.requestOptions));
1998
+ const adaptor = getAdaptor(initOptions.adaptor ?? "fetch");
1999
+ const code = await Generator.genCode({
2000
+ enums,
2001
+ schemas,
2002
+ parameters,
2003
+ responses,
2004
+ requestBodies,
2005
+ apis
2006
+ }, initOptions, adaptor);
2007
+ if (initOptions.output) await Generator.write(code, initOptions.output);
2008
+ const duration = Date.now() - startTime;
2009
+ return {
2010
+ code,
2011
+ stats: {
2012
+ endpoints: Object.keys(apis).length,
2013
+ schemas: Object.keys(schemas).length,
2014
+ duration
2015
+ }
2016
+ };
2341
2017
  }
2342
-
2343
- // src/vite-plugin/index.ts
2344
- var import_logger2 = require("@moccona/logger");
2345
- var import_execa = require("execa");
2346
- var import_fs_extra = __toESM(require("fs-extra"), 1);
2347
- var PLUGIN_NAME = "apiCodeGen";
2348
- var logger2 = (0, import_logger2.createScopedLogger)("api-codegen-vite-plugin");
2349
- var tsc = async (path) => {
2350
- await (0, import_execa.execaCommand)(`npx tsc ${path} --noEmit`);
2351
- };
2018
+ //#endregion
2019
+ //#region src/vite-plugin/index.ts
2020
+ const PLUGIN_NAME = "api-code-gen";
2021
+ const logger = (0, _moccona_logger.createScopedLogger)("api-code-gen");
2022
+ /**
2023
+ * Run TypeScript type checking on generated file
2024
+ */
2025
+ async function runTypeCheck(filePath) {
2026
+ const { execaCommand } = await import("execa");
2027
+ const errors = [];
2028
+ try {
2029
+ await execaCommand(`npx tsc ${filePath} --noEmit`, { shell: true });
2030
+ } catch (error) {
2031
+ if (error instanceof Error) errors.push(error.message);
2032
+ }
2033
+ return errors;
2034
+ }
2035
+ /**
2036
+ * Validate spec path exists
2037
+ */
2038
+ async function validateSpecPath(specPath) {
2039
+ if (specPath.startsWith("http://") || specPath.startsWith("https://")) return;
2040
+ const filePath = specPath.replace(/^file:\/\//, "");
2041
+ const absolutePath = node_path.default.isAbsolute(filePath) ? filePath : node_path.default.resolve(process.cwd(), filePath);
2042
+ if (!await fs_extra.default.pathExists(absolutePath)) throw createErrors.specNotFound(absolutePath);
2043
+ }
2044
+ /**
2045
+ * Generate code for a single API configuration
2046
+ */
2047
+ async function generateForOption(option) {
2048
+ const { name, typeCheck = true, verbose, ...restOptions } = option;
2049
+ try {
2050
+ console.log(`\x1b[36m├─\x1b[0m ${name}`);
2051
+ const config = await loadConfig({
2052
+ name,
2053
+ cliOptions: {
2054
+ ...restOptions,
2055
+ verbose
2056
+ }
2057
+ });
2058
+ await validateSpecPath(config.spec);
2059
+ if (config.output) {
2060
+ const outputDir = node_path.default.dirname(config.output);
2061
+ await fs_extra.default.ensureDir(outputDir);
2062
+ }
2063
+ let docURL = config.spec;
2064
+ if (!docURL.startsWith("http://") && !docURL.startsWith("https://")) if (docURL.startsWith("/") || docURL.match(/^[A-Za-z]:/)) docURL = `file://${docURL}`;
2065
+ else docURL = node_path.default.resolve(process.cwd(), docURL);
2066
+ const result = await codeGen({
2067
+ ...toProviderOptions(config),
2068
+ docURL
2069
+ });
2070
+ if (config.output) await fs_extra.default.writeFile(config.output, result.code);
2071
+ if (typeCheck && config.output) {
2072
+ const typeErrors = await runTypeCheck(config.output);
2073
+ if (typeErrors.length > 0) {
2074
+ logger.warn(`Type check failed for ${config.output}`);
2075
+ if (verbose) for (const error of typeErrors) logger.warn(` ${error}`);
2076
+ }
2077
+ }
2078
+ return {
2079
+ success: true,
2080
+ name,
2081
+ output: config.output,
2082
+ stats: result.stats
2083
+ };
2084
+ } catch (error) {
2085
+ return {
2086
+ success: false,
2087
+ name,
2088
+ error
2089
+ };
2090
+ }
2091
+ }
2092
+ /**
2093
+ * Main Vite plugin function
2094
+ *
2095
+ * @example
2096
+ * ```ts
2097
+ * // vite.config.ts
2098
+ * import { apiCodeGenPlugin } from '@moccona/apicodegen/vite';
2099
+ *
2100
+ * export default defineConfig({
2101
+ * plugins: [
2102
+ * apiCodeGenPlugin([
2103
+ * {
2104
+ * name: 'my-api',
2105
+ * spec: './openapi.json',
2106
+ * output: './src/api/generated.ts',
2107
+ * baseURL: 'https://api.example.com',
2108
+ * },
2109
+ * ]),
2110
+ * ],
2111
+ * });
2112
+ * ```
2113
+ */
2352
2114
  function apiCodeGenPlugin(options) {
2353
- let firstRun = true;
2354
- return {
2355
- name: PLUGIN_NAME,
2356
- async config(config) {
2357
- if (!firstRun) return;
2358
- firstRun = false;
2359
- logger2.info("-------> api codegen start <--------");
2360
- const proxies = await options.reduce(
2361
- async (proxiesPromise_, option) => {
2362
- const proxies_ = await proxiesPromise_;
2363
- const { proxy = {}, name, ...codeGenInitOptions } = option;
2364
- try {
2365
- const code = await codeGen(codeGenInitOptions);
2366
- await import_fs_extra.default.createFile(codeGenInitOptions.output);
2367
- await import_fs_extra.default.writeFile(codeGenInitOptions.output, code);
2368
- try {
2369
- await tsc(codeGenInitOptions.output);
2370
- } catch (error) {
2371
- logger2.error(error);
2372
- }
2373
- } catch (error) {
2374
- logger2.error(`Failed to generate api ${name}: ${error}`);
2375
- }
2376
- return {
2377
- ...proxies_,
2378
- ...proxy
2379
- };
2380
- },
2381
- Promise.resolve({})
2382
- );
2383
- logger2.info("-------> api codegen finished <--------");
2384
- return {
2385
- ...config,
2386
- server: {
2387
- ...config.server ?? {},
2388
- proxy: Object.assign({}, config.server?.proxy ?? {}, proxies)
2389
- }
2390
- };
2391
- }
2392
- };
2115
+ if (!Array.isArray(options) || options.length === 0) {
2116
+ logger.warn("No API configurations provided to apiCodeGenPlugin");
2117
+ return { name: PLUGIN_NAME };
2118
+ }
2119
+ return {
2120
+ name: PLUGIN_NAME,
2121
+ async config(_config, env) {
2122
+ console.log(`\x1b[1m\x1b[36m${"─".repeat(50)}\x1b[0m`);
2123
+ console.log(`\x1b[1m\x1b[36mAPI Code Gen\x1b[0m`);
2124
+ console.log(`\x1b[90mMode:\x1b[0m ${env?.command || "unknown"}`);
2125
+ console.log(`\x1b[1m\x1b[36m${"─".repeat(50)}\x1b[0m`);
2126
+ const results = await Promise.all(options.map(generateForOption));
2127
+ const successCount = results.filter((r) => r.success).length;
2128
+ const failCount = options.length - successCount;
2129
+ console.log(`\x1b[1m\x1b[36m${"─".repeat(50)}\x1b[0m`);
2130
+ for (const result of results) if (result.success) {
2131
+ const { name, output, stats } = result;
2132
+ if (stats) console.log(`\x1b[32m✓\x1b[0m ${name} ${output} (${stats.endpoints} endpoints, ${stats.schemas} schemas) ${stats.duration}ms`);
2133
+ else console.log(`\x1b[32m✓\x1b[0m ${name} → ${output || "N/A"}`);
2134
+ } else {
2135
+ const { name, error } = result;
2136
+ if (isApicodegenError(error)) {
2137
+ console.log(`\x1b[31m✗\x1b[0m ${name}`);
2138
+ console.log(`\x1b[90m${formatError(error, true)}\x1b[0m`);
2139
+ } else {
2140
+ const wrapped = wrapError(error, {
2141
+ code: "E_GENERATION_FAILED",
2142
+ message: `Failed to generate API "${name}"`
2143
+ });
2144
+ console.log(`\x1b[31m✗\x1b[0m ${name}`);
2145
+ console.log(`\x1b[90m${formatError(wrapped, true)}\x1b[0m`);
2146
+ }
2147
+ }
2148
+ console.log(`\x1b[1m\x1b[36m${"─".repeat(50)}\x1b[0m`);
2149
+ const totalDuration = results.reduce((sum, r) => sum + (r.stats?.duration || 0), 0);
2150
+ const totalEndpoints = results.reduce((sum, r) => sum + (r.stats?.endpoints || 0), 0);
2151
+ const totalSchemas = results.reduce((sum, r) => sum + (r.stats?.schemas || 0), 0);
2152
+ if (failCount === 0) console.log(`\x1b[32m✓\x1b[0m API Code Gen - Complete (\x1b[90m${successCount}/${options.length} succeeded\x1b[0m, ${totalEndpoints} endpoints, ${totalSchemas} schemas, ${totalDuration}ms\x1b[0m)`);
2153
+ else console.log(`\x1b[33m⚠\x1b[0m API Code Gen - Complete (\x1b[90m${successCount} succeeded, ${failCount} failed\x1b[0m, ${totalEndpoints} endpoints, ${totalSchemas} schemas, ${totalDuration}ms\x1b[0m)`);
2154
+ console.log(`\x1b[1m\x1b[36m${"─".repeat(50)}\x1b[0m`);
2155
+ return {};
2156
+ }
2157
+ };
2393
2158
  }
2394
- // Annotate the CommonJS export names for ESM import in node:
2395
- 0 && (module.exports = {
2396
- Adapter,
2397
- Adaptors,
2398
- ArraySchemaType,
2399
- AxiosAdapter,
2400
- Base,
2401
- FetchAdapter,
2402
- Generator,
2403
- HttpMethods,
2404
- MediaTypes,
2405
- NonArraySchemaType,
2406
- OpenAPIProvider,
2407
- OpenAPIVersion,
2408
- ParameterIn,
2409
- Provider,
2410
- SchemaFormatType,
2411
- SchemaType,
2412
- SuccessHttpStatusCode,
2413
- apiCodeGenPlugin,
2414
- codeGen,
2415
- tsc
2416
- });
2159
+ //#endregion
2160
+ exports.Adapter = Adapter;
2161
+ exports.Adaptors = Adaptors;
2162
+ exports.ApicodegenError = ApicodegenError;
2163
+ exports.ArraySchemaType = ArraySchemaType;
2164
+ exports.AxiosAdapter = AxiosAdapter;
2165
+ exports.Base = Base;
2166
+ exports.Colors = Colors;
2167
+ exports.ErrorCodes = ErrorCodes;
2168
+ exports.FetchAdapter = FetchAdapter;
2169
+ exports.Generator = Generator;
2170
+ exports.HttpMethods = HttpMethods;
2171
+ exports.MediaTypes = MediaTypes;
2172
+ exports.NonArraySchemaType = NonArraySchemaType;
2173
+ exports.OpenAPIProvider = OpenAPIProvider;
2174
+ exports.OpenAPIVersion = OpenAPIVersion;
2175
+ exports.ParameterIn = ParameterIn;
2176
+ exports.Provider = Provider;
2177
+ exports.SchemaFormatType = SchemaFormatType;
2178
+ exports.SchemaType = SchemaType;
2179
+ exports.SuccessHttpStatusCode = SuccessHttpStatusCode;
2180
+ exports.apiCodeGenPlugin = apiCodeGenPlugin;
2181
+ exports.codeGen = codeGen;
2182
+ exports.configToCLIOptions = configToCLIOptions;
2183
+ exports.createErrors = createErrors;
2184
+ exports.formatError = formatError;
2185
+ exports.isApicodegenError = isApicodegenError;
2186
+ exports.loadConfig = loadConfig;
2187
+ exports.printError = printError;
2188
+ exports.toProviderOptions = toProviderOptions;
2189
+ exports.wrapError = wrapError;
2190
+
2417
2191
  //# sourceMappingURL=index.cjs.map