@moccona/apicodegen 0.0.3 → 0.0.4

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