@moccona/apicodegen 0.0.9 → 0.0.10

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
@@ -440,6 +440,250 @@ var Provider = class {
440
440
  }
441
441
  };
442
442
  //#endregion
443
+ //#region src/core/errors.ts
444
+ /**
445
+ * Error handling utilities for api-codegen
446
+ */
447
+ const ErrorCodes = {
448
+ SPEC_NOT_FOUND: "E_SPEC_NOT_FOUND",
449
+ SPEC_FETCH_FAILED: "E_SPEC_FETCH_FAILED",
450
+ SPEC_PARSE_FAILED: "E_SPEC_PARSE_FAILED",
451
+ OUTPUT_DIR_MISSING: "E_OUTPUT_DIR_MISSING",
452
+ CONFIG_INVALID: "E_CONFIG_INVALID",
453
+ VALIDATION_FAILED: "E_VALIDATION_FAILED",
454
+ GENERATION_FAILED: "E_GENERATION_FAILED",
455
+ TYPE_CHECK_FAILED: "E_TYPE_CHECK_FAILED"
456
+ };
457
+ /**
458
+ * Custom error class for api-codegen with rich context
459
+ */
460
+ var ApicodegenError = class ApicodegenError extends Error {
461
+ code;
462
+ location;
463
+ line;
464
+ column;
465
+ path;
466
+ suggestions;
467
+ cause;
468
+ constructor(context) {
469
+ super(context.message);
470
+ this.name = "ApicodegenError";
471
+ this.code = context.code;
472
+ this.location = context.location;
473
+ this.line = context.line;
474
+ this.column = context.column;
475
+ this.path = context.path;
476
+ this.suggestions = context.suggestions || [];
477
+ this.cause = context.cause;
478
+ if (Error.captureStackTrace) Error.captureStackTrace(this, ApicodegenError);
479
+ }
480
+ /**
481
+ * Convert error to formatted string for CLI output
482
+ */
483
+ toString(verbose = false) {
484
+ const lines = [];
485
+ lines.push(`\x1b[1;31mError [${this.code}]\x1b[0m ${this.message}`);
486
+ if (this.location) lines.push(` \x1b[36m→ Location:\x1b[0m ${this.location}`);
487
+ if (this.path) lines.push(` \x1b[36m→ Path:\x1b[0m ${this.path}`);
488
+ if (this.line !== void 0) {
489
+ let lineInfo = ` \x1b[36m→ Line:\x1b[0m ${this.line}`;
490
+ if (this.column !== void 0) lineInfo += `, Column: ${this.column}`;
491
+ lines.push(lineInfo);
492
+ }
493
+ if (this.suggestions.length > 0) for (const suggestion of this.suggestions) lines.push(` \x1b[32m→ Suggestion:\x1b[0m ${suggestion}`);
494
+ if (verbose && this.cause) {
495
+ lines.push(`\n \x1b[90mOriginal Error:\x1b[0m ${this.cause.message}`);
496
+ if (this.stack) {
497
+ const stackLines = this.stack.split("\n").slice(1).join("\n");
498
+ lines.push(`\x1b[90m${stackLines}\x1b[0m`);
499
+ }
500
+ }
501
+ return lines.join("\n");
502
+ }
503
+ /**
504
+ * Convert to JSON-serializable object
505
+ */
506
+ toJSON() {
507
+ return {
508
+ name: this.name,
509
+ code: this.code,
510
+ message: this.message,
511
+ location: this.location,
512
+ line: this.line,
513
+ column: this.column,
514
+ path: this.path,
515
+ suggestions: this.suggestions,
516
+ cause: this.cause?.message
517
+ };
518
+ }
519
+ };
520
+ /**
521
+ * ANSI color codes for terminal output
522
+ */
523
+ const Colors = {
524
+ reset: "\x1B[0m",
525
+ bold: "\x1B[1m",
526
+ red: "\x1B[31m",
527
+ green: "\x1B[32m",
528
+ yellow: "\x1B[33m",
529
+ blue: "\x1B[34m",
530
+ cyan: "\x1B[36m",
531
+ gray: "\x1B[90m",
532
+ brightRed: "\x1B[91m",
533
+ brightGreen: "\x1B[92m"
534
+ };
535
+ /**
536
+ * Format error for CLI output
537
+ */
538
+ function formatError(error, verbose = false) {
539
+ if (error instanceof ApicodegenError) return error.toString(verbose);
540
+ 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}` : ""}`;
541
+ return `${Colors.red}${Colors.bold}Error${Colors.reset}: ${String(error)}`;
542
+ }
543
+ /**
544
+ * Print error to console with formatting
545
+ */
546
+ function printError(error, verbose = false, stream = process.stderr) {
547
+ stream.write(formatError(error, verbose));
548
+ stream.write("\n");
549
+ }
550
+ /**
551
+ * Create error with common patterns
552
+ */
553
+ const createErrors = {
554
+ specNotFound(path, cause) {
555
+ return new ApicodegenError({
556
+ code: ErrorCodes.SPEC_NOT_FOUND,
557
+ message: "OpenAPI spec file not found",
558
+ location: path,
559
+ suggestions: [
560
+ "Check if the file exists using 'ls -la'",
561
+ "Use --spec to provide the correct path",
562
+ "For remote specs, ensure the URL is accessible"
563
+ ],
564
+ cause
565
+ });
566
+ },
567
+ specFetchFailed(url, statusCode, cause) {
568
+ const message = statusCode ? `Failed to fetch OpenAPI spec (HTTP ${statusCode})` : "Failed to fetch OpenAPI spec from URL";
569
+ return new ApicodegenError({
570
+ code: ErrorCodes.SPEC_FETCH_FAILED,
571
+ message,
572
+ location: url,
573
+ suggestions: [
574
+ "Check if the URL is accessible in a browser",
575
+ "Download the spec file locally and use the local path",
576
+ "Verify CORS settings if fetching from a different origin"
577
+ ],
578
+ cause
579
+ });
580
+ },
581
+ specParseFailed(path, line, column, cause) {
582
+ return new ApicodegenError({
583
+ code: ErrorCodes.SPEC_PARSE_FAILED,
584
+ message: "Failed to parse OpenAPI spec (invalid JSON or YAML)",
585
+ location: path,
586
+ line,
587
+ column,
588
+ suggestions: [
589
+ "Validate JSON syntax using jsonlint.com",
590
+ "For YAML specs, ensure proper indentation",
591
+ "Check for trailing commas or unquoted special characters"
592
+ ],
593
+ cause
594
+ });
595
+ },
596
+ outputDirMissing(path, cause) {
597
+ return new ApicodegenError({
598
+ code: ErrorCodes.OUTPUT_DIR_MISSING,
599
+ message: "Output directory does not exist",
600
+ location: path,
601
+ suggestions: ["Create the directory: mkdir -p $(dirname <output>)", "Check if the path is correct"],
602
+ cause
603
+ });
604
+ },
605
+ configInvalid(path, cause) {
606
+ return new ApicodegenError({
607
+ code: ErrorCodes.CONFIG_INVALID,
608
+ message: "Invalid configuration file",
609
+ location: path,
610
+ suggestions: ["Validate JSON syntax in the config file", "Check for required fields (spec, output)"],
611
+ cause
612
+ });
613
+ },
614
+ validationFailed(path, details, cause) {
615
+ return new ApicodegenError({
616
+ code: ErrorCodes.VALIDATION_FAILED,
617
+ message: "OpenAPI spec validation failed",
618
+ location: path,
619
+ path: details,
620
+ suggestions: [
621
+ "Check OpenAPI spec structure at the specified path",
622
+ "Ensure all required fields are present",
623
+ "Validate using swagger.io editor"
624
+ ],
625
+ cause
626
+ });
627
+ },
628
+ generationFailed(cause) {
629
+ return new ApicodegenError({
630
+ code: ErrorCodes.GENERATION_FAILED,
631
+ message: "Code generation failed",
632
+ suggestions: [
633
+ "Check for unsupported OpenAPI features",
634
+ "Ensure spec follows OpenAPI 2.0, 3.0, or 3.1 specification",
635
+ "Use --verbose for more details"
636
+ ],
637
+ cause
638
+ });
639
+ },
640
+ typeCheckFailed(path, _errors, cause) {
641
+ return new ApicodegenError({
642
+ code: ErrorCodes.TYPE_CHECK_FAILED,
643
+ message: "TypeScript type check failed",
644
+ location: path,
645
+ suggestions: [
646
+ "Review type errors above",
647
+ "Check for schema inconsistencies",
648
+ "Update generated types or fix source schema"
649
+ ],
650
+ cause
651
+ });
652
+ },
653
+ missingRequiredField(field, context) {
654
+ return new ApicodegenError({
655
+ code: ErrorCodes.VALIDATION_FAILED,
656
+ message: `Missing required field: ${field}`,
657
+ path: context,
658
+ suggestions: [`Add the '${field}' field to your configuration`]
659
+ });
660
+ }
661
+ };
662
+ /**
663
+ * Wrap unknown error in ApicodegenError if needed
664
+ */
665
+ function wrapError(error, context) {
666
+ if (error instanceof ApicodegenError) return error;
667
+ if (error instanceof Error) return new ApicodegenError({
668
+ code: context?.code || ErrorCodes.GENERATION_FAILED,
669
+ message: context?.message || error.message,
670
+ location: context?.location,
671
+ suggestions: context?.suggestions,
672
+ cause: error
673
+ });
674
+ return new ApicodegenError({
675
+ code: context?.code || ErrorCodes.GENERATION_FAILED,
676
+ message: String(error),
677
+ suggestions: context?.suggestions
678
+ });
679
+ }
680
+ /**
681
+ * Check if error is an ApicodegenError
682
+ */
683
+ function isApicodegenError(error) {
684
+ return error instanceof ApicodegenError;
685
+ }
686
+ //#endregion
443
687
  //#region src/core/generator/index.ts
444
688
  var Generator = class Generator {
445
689
  /**
@@ -455,10 +699,19 @@ var Generator = class Generator {
455
699
  return (0, typescript.createPrinter)().printFile(sourceFile);
456
700
  }
457
701
  static async write(code, filepath) {
702
+ const { mkdir } = await import("node:fs/promises");
703
+ const { dirname } = await import("node:path");
458
704
  try {
705
+ await mkdir(dirname(filepath), { recursive: true });
459
706
  await (0, node_fs_promises.writeFile)(filepath, code);
460
707
  } catch (error) {
461
- console.error(error);
708
+ throw new ApicodegenError({
709
+ code: ErrorCodes.OUTPUT_DIR_MISSING,
710
+ message: "Failed to write generated code to output file",
711
+ location: filepath,
712
+ cause: error instanceof Error ? error : new Error(String(error)),
713
+ suggestions: ["Verify the output directory path is writable", "Check that the parent directory exists or can be created"]
714
+ });
462
715
  }
463
716
  }
464
717
  /**
@@ -938,20 +1191,6 @@ async function loadConfig(options = {}) {
938
1191
  };
939
1192
  }
940
1193
  /**
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
1194
  * Convert resolved config to provider options format
956
1195
  */
957
1196
  function toProviderOptions(config) {
@@ -966,509 +1205,74 @@ function toProviderOptions(config) {
966
1205
  };
967
1206
  }
968
1207
  //#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
1214
- var V2 = class {
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
- };
1208
+ //#region src/core/logger.ts
1209
+ const cyan = (s) => `\x1b[36m${s}\x1b[0m`;
1210
+ const green = (s) => `\x1b[32m${s}\x1b[0m`;
1211
+ const red = (s) => `\x1b[31m${s}\x1b[0m`;
1212
+ const blue = (s) => `\x1b[34m${s}\x1b[0m`;
1213
+ const yellow = (s) => `\x1b[33m${s}\x1b[0m`;
1214
+ const magenta = (s) => `\x1b[35m${s}\x1b[0m`;
1215
+ const gray = (s) => `\x1b[90m${s}\x1b[0m`;
1216
+ const bold = (s) => `\x1b[1m${s}\x1b[0m`;
1217
+ const logger = {
1218
+ success(msg) {
1219
+ console.log(`${green("")} ${msg}`);
1220
+ },
1221
+ error(err, verbose = false) {
1222
+ if (isApicodegenError(err)) console.error(`${red("✗")} ${err.toString(verbose)}`);
1223
+ else if (err instanceof Error) {
1224
+ const msg = `Error: ${err.message}`;
1225
+ console.error(`${red("✗")} ${msg}${verbose && err.stack ? `\n${gray(err.stack)}` : ""}`);
1226
+ } else console.error(`${red("✗")} ${String(err)}`);
1227
+ },
1228
+ info(msg) {
1229
+ console.log(`${blue("ℹ")} ${msg}`);
1230
+ },
1231
+ warn(msg) {
1232
+ console.log(`${yellow("⚠")} ${msg}`);
1233
+ },
1234
+ loading(msg) {
1235
+ console.log(`${yellow("🔄")} ${msg}`);
1236
+ },
1237
+ watching(msg) {
1238
+ console.log(`${magenta("⟳")} ${msg}`);
1239
+ },
1240
+ fileChange(filePath) {
1241
+ console.log(`${yellow("↓")} ${filePath}`);
1242
+ },
1243
+ fileAdd(filePath) {
1244
+ console.log(`${green("+")} ${filePath}`);
1245
+ },
1246
+ shutdown() {
1247
+ console.log(`\n${gray("👋 Shutting down...")}`);
1248
+ },
1249
+ divider(width = 50) {
1250
+ console.log(`${bold(cyan("─".repeat(width)))}`);
1251
+ },
1252
+ heading(text, mode, width = 50) {
1253
+ console.log(`${bold(cyan("─".repeat(width)))}`);
1254
+ console.log(`${bold(cyan(text))}`);
1255
+ console.log(`${gray("Mode:")} ${mode || "unknown"}`);
1256
+ console.log(`${bold(cyan("─".repeat(width)))}`);
1257
+ },
1258
+ item(label, color = "green") {
1259
+ const icon = color === "green" ? "✓" : color === "red" ? "✗" : "⚠";
1260
+ console.log(`${color === "green" ? green(icon) : color === "red" ? red(icon) : yellow(icon)} ${label}`);
1261
+ },
1262
+ summary(stats) {
1263
+ const { succeeded, failed, endpoints, schemas, duration } = stats;
1264
+ const label = `API Code Gen - Complete (${succeeded} succeeded${failed > 0 ? `, ${failed} failed` : ""}, ${endpoints} endpoints, ${schemas} schemas, ${duration}ms)`;
1265
+ if (failed === 0) console.log(`${green("✓")} ${label}`);
1266
+ else console.log(`${yellow("")} ${label}`);
1463
1267
  }
1464
1268
  };
1465
1269
  //#endregion
1466
- //#region src/openapi/V3.ts
1467
- var V3 = class {
1468
- doc;
1469
- constructor(doc) {
1470
- this.doc = doc;
1471
- }
1270
+ //#region src/openapi/VersionedProvider.ts
1271
+ /**
1272
+ * Abstract base class. Subclasses implement the four container accessors
1273
+ * and a version tag. The shared logic lives here.
1274
+ */
1275
+ var VersionedProvider = class {
1472
1276
  /**
1473
1277
  * Resolves a path $ref to the actual path object.
1474
1278
  */
@@ -1480,28 +1284,37 @@ var V3 = class {
1480
1284
  * Is array schema.
1481
1285
  */
1482
1286
  isOpenAPIArraySchema(schema) {
1483
- return typeof schema === "object" && schema.type === "array";
1287
+ return typeof schema === "object" && schema !== null && schema.type === "array";
1484
1288
  }
1485
1289
  /**
1486
- * OpenAPI schema to base schema.
1290
+ * OpenAPI schema to base schema. Override for version-specific quirks
1291
+ * (V3_1 throws on missing ref; V3 returns `{ type: 'unknown' }`).
1487
1292
  */
1488
1293
  getSchemaByRef(schema, reserveRef = false, enums = [], upLevelSchemaKey = "") {
1489
1294
  let refName = "";
1490
1295
  if (Base.isRef(schema)) {
1491
- refName = Base.capitalize(Base.ref2name(schema.$ref));
1296
+ refName = this.formatRefName(Base.ref2name(schema.$ref));
1492
1297
  if (reserveRef) return { type: upLevelSchemaKey + refName };
1493
- const resolvedSchema = this.doc.components?.schemas?.[Base.ref2name(schema.$ref, this.doc)];
1298
+ const resolvedSchema = this.getSchemaContainer()?.[Base.ref2name(schema.$ref, this.doc)];
1494
1299
  if (!resolvedSchema) return { type: "unknown" };
1495
1300
  schema = resolvedSchema;
1496
1301
  }
1497
1302
  return this.toBaseSchema(schema, enums, "", upLevelSchemaKey + refName);
1498
1303
  }
1499
1304
  /**
1500
- * OpenAPI parameter to base parameter.
1305
+ * Format a ref name for the schema's `type` field.
1306
+ * V3 uses `capitalize`; V3_1 uses `upperCamelCase` (preserved for compat).
1307
+ */
1308
+ formatRefName(name) {
1309
+ return Base.capitalize(name);
1310
+ }
1311
+ /**
1312
+ * OpenAPI parameter to base parameter. Override in V2 — its parameter
1313
+ * shape is structurally different (top-level `items`/`properties`/`enum`).
1501
1314
  */
1502
1315
  getParameterByRef(schema, enums = [], upLevelSchemaKey = "") {
1503
1316
  if (Base.isRef(schema)) {
1504
- const resolvedSchema = this.doc.components?.parameters?.[Base.ref2name(schema.$ref, this.doc)];
1317
+ const resolvedSchema = this.getParameterContainer()?.[Base.ref2name(schema.$ref, this.doc)];
1505
1318
  if (!resolvedSchema) return {
1506
1319
  name: "unknown",
1507
1320
  in: "query"
@@ -1532,37 +1345,38 @@ var V3 = class {
1532
1345
  description,
1533
1346
  deprecated,
1534
1347
  in: schema.in,
1535
- schema: schema.schema && this.getSchemaByRef(schema.schema, false, enums, upLevelSchemaKey + Base.capitalize(name))
1348
+ schema: schema.schema ? this.getSchemaByRef(schema.schema, false, enums, upLevelSchemaKey + Base.capitalize(name)) : void 0
1536
1349
  };
1537
1350
  }
1538
1351
  /**
1539
- * OpenAPI schema to base response
1352
+ * OpenAPI schema to base response. Override in V2 (its response shape
1353
+ * lacks the `content` wrapper).
1540
1354
  */
1541
1355
  getResponseByRef(schema) {
1542
1356
  if (Base.isRef(schema)) {
1543
- const resolvedSchema = this.doc.components?.responses?.[Base.ref2name(schema.$ref, this.doc)];
1357
+ const resolvedSchema = this.getResponseContainer()?.[Base.ref2name(schema.$ref, this.doc)];
1544
1358
  if (!resolvedSchema) return [];
1545
1359
  schema = resolvedSchema;
1546
1360
  }
1547
1361
  const { content = {} } = schema;
1548
1362
  return Object.keys(content).map((c) => ({
1549
1363
  type: c,
1550
- schema: content[c].schema && this.getSchemaByRef(content[c].schema, true)
1364
+ schema: content[c].schema ? this.getSchemaByRef(content[c].schema, true) : void 0
1551
1365
  }));
1552
1366
  }
1553
1367
  /**
1554
- * OpenAPI schema to requestBody.
1368
+ * OpenAPI schema to requestBody. V2 has no requestBody concept.
1555
1369
  */
1556
1370
  getRequestBodyByRef(schema, enums = []) {
1557
1371
  if (Base.isRef(schema)) {
1558
- const resolvedSchema = this.doc.components?.requestBodies?.[Base.ref2name(schema.$ref, this.doc)];
1372
+ const resolvedSchema = this.getRequestBodyContainer()?.[Base.ref2name(schema.$ref, this.doc)];
1559
1373
  if (!resolvedSchema) return [];
1560
1374
  schema = resolvedSchema;
1561
1375
  }
1562
1376
  const { content = {} } = schema;
1563
1377
  return Object.keys(content).map((c) => ({
1564
1378
  type: c,
1565
- schema: content[c].schema && this.getSchemaByRef(content[c].schema, false, enums)
1379
+ schema: content[c].schema ? this.getSchemaByRef(content[c].schema, false, enums) : void 0
1566
1380
  }));
1567
1381
  }
1568
1382
  /**
@@ -1573,92 +1387,98 @@ var V3 = class {
1573
1387
  if (Base.isRef(schema)) return this.getSchemaByRef(schema, true);
1574
1388
  if (this.isOpenAPIArraySchema(schema)) {
1575
1389
  const { type, description, items, required } = schema;
1390
+ const itemsSchema = items ? this.toBaseSchema(items, enums, schemaKey, upLevelSchemaKey) : { type: "unknown" };
1576
1391
  return {
1577
1392
  type,
1578
1393
  required: !!required,
1579
1394
  description,
1580
- items: this.toBaseSchema(items, enums, schemaKey, upLevelSchemaKey)
1395
+ items: itemsSchema
1581
1396
  };
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";
1397
+ }
1398
+ const { required = [], allOf, anyOf, description, deprecated, enum: enum_, format, oneOf, properties = {} } = schema;
1399
+ let { type } = schema;
1400
+ if (enum_ && type !== "boolean") {
1401
+ const enumObject = {
1402
+ name: Base.upperCamelCase(Base.normalize(upLevelSchemaKey)) + Base.upperCamelCase(Base.normalize(schemaKey)),
1403
+ enum: [...new Set(enum_)]
1404
+ };
1405
+ const sameObject = Base.findSameSchema(enumObject, enums);
1406
+ if (!sameObject && Base.isValidEnumType(schema)) enums.push(enumObject);
1600
1407
  return {
1601
- type,
1408
+ type: sameObject ? sameObject.name : Base.isBooleanEnum(schema) ? "boolean" : enumObject.name,
1602
1409
  required,
1603
1410
  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
- }, {})
1411
+ deprecated
1632
1412
  };
1633
1413
  }
1414
+ if (type === void 0 && Object.keys(properties).length > 0) type = "object";
1415
+ return {
1416
+ type,
1417
+ required,
1418
+ description,
1419
+ deprecated,
1420
+ enum: enum_,
1421
+ format,
1422
+ allOf: allOf?.map((s) => Base.isRef(s) ? {
1423
+ ...s,
1424
+ ref: s.$ref,
1425
+ type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1426
+ } : this.toBaseSchema(s, enums)),
1427
+ anyOf: anyOf?.map((s) => Base.isRef(s) ? {
1428
+ ...s,
1429
+ ref: s.$ref,
1430
+ type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1431
+ } : this.toBaseSchema(s, enums)),
1432
+ oneOf: oneOf?.map((s) => Base.isRef(s) ? {
1433
+ ...s,
1434
+ ref: s.$ref,
1435
+ type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1436
+ } : this.toBaseSchema(s, enums)),
1437
+ properties: Object.keys(properties).reduce((acc, p) => {
1438
+ const propSchema = properties[p];
1439
+ return {
1440
+ ...acc,
1441
+ [p]: Base.isRef(propSchema) ? {
1442
+ type: Base.capitalize(Base.ref2name(propSchema.$ref, this.doc)),
1443
+ isRef: true
1444
+ } : this.toBaseSchema(propSchema, enums, p, upLevelSchemaKey)
1445
+ };
1446
+ }, {})
1447
+ };
1634
1448
  }
1449
+ /**
1450
+ * Run the parsing pipeline and return a ProviderInitResult.
1451
+ */
1635
1452
  init() {
1636
- const { components = {}, paths = {} } = this.doc;
1453
+ const { paths = {} } = this.doc;
1637
1454
  const enums = [];
1638
- const { requestBodies = {}, responses = {}, parameters = {}, schemas = {} } = components;
1639
- const schemas_ = Object.keys(schemas).reduce((acc, key) => {
1640
- const schema = schemas[key];
1455
+ const schemaContainer = this.getSchemaContainer() ?? {};
1456
+ const parameterContainer = this.getParameterContainer() ?? {};
1457
+ const responseContainer = this.getResponseContainer() ?? {};
1458
+ const requestBodyContainer = this.getRequestBodyContainer() ?? {};
1459
+ const schemas_ = Object.keys(schemaContainer).reduce((acc, key) => {
1460
+ const schema = schemaContainer[key];
1641
1461
  return {
1642
1462
  ...acc,
1643
1463
  [key]: this.getSchemaByRef(schema, false, enums, key)
1644
1464
  };
1645
1465
  }, {});
1646
- const parameters_ = Object.keys(parameters).reduce((acc, key) => {
1647
- const parameter = parameters[key];
1466
+ const parameters_ = Object.keys(parameterContainer).reduce((acc, key) => {
1467
+ const parameter = parameterContainer[key];
1648
1468
  return {
1649
1469
  ...acc,
1650
1470
  [key]: this.getParameterByRef(parameter, enums, key)
1651
1471
  };
1652
1472
  }, {});
1653
- const responses_ = Object.keys(responses).reduce((acc, key) => {
1654
- const response = responses[key];
1473
+ const responses_ = Object.keys(responseContainer).reduce((acc, key) => {
1474
+ const response = responseContainer[key];
1655
1475
  return {
1656
1476
  ...acc,
1657
1477
  [key]: this.getResponseByRef(response)
1658
1478
  };
1659
1479
  }, {});
1660
- const requestBodies_ = Object.keys(requestBodies).reduce((acc, key) => {
1661
- const requestBody = requestBodies[key];
1480
+ const requestBodies_ = Object.keys(requestBodyContainer).reduce((acc, key) => {
1481
+ const requestBody = requestBodyContainer[key];
1662
1482
  return {
1663
1483
  ...acc,
1664
1484
  [key]: this.getRequestBodyByRef(requestBody, enums)
@@ -1675,15 +1495,16 @@ var V3 = class {
1675
1495
  Object.values(HttpMethods).forEach((method) => {
1676
1496
  const methodObject = pathObject[method];
1677
1497
  if (methodObject) {
1678
- const { deprecated, operationId, responses = {}, summary: summary_, description: description_, requestBody = { content: {} } } = methodObject;
1498
+ const { deprecated, operationId, responses, summary: summary_, description: description_, requestBody = { content: {} } } = methodObject;
1499
+ const responsesClone = responses ? { ...responses } : {};
1679
1500
  const { parameters: parameters_ = [] } = methodObject;
1680
1501
  const baseParameters = [...parameters, ...parameters_].map((parameter) => this.getParameterByRef(parameter, enums));
1681
1502
  const baseRequestBody = this.getRequestBodyByRef(requestBody, enums);
1682
1503
  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];
1504
+ if (Object.keys(responsesClone).length === 0) responsesClone[200] = { description: "Successful response" };
1505
+ const httpCodes = Object.keys(responsesClone);
1506
+ for (const code of httpCodes) if (code in responsesClone) {
1507
+ const response = responsesClone[code];
1687
1508
  const responseSchema = this.getResponseByRef(response);
1688
1509
  methodApis.push({
1689
1510
  method,
@@ -1715,244 +1536,246 @@ var V3 = class {
1715
1536
  }
1716
1537
  };
1717
1538
  //#endregion
1718
- //#region src/openapi/V3_1.ts
1719
- var V3_1 = class {
1539
+ //#region src/openapi/V2.ts
1540
+ var V2 = class extends VersionedProvider {
1720
1541
  doc;
1542
+ version = "v2";
1721
1543
  constructor(doc) {
1544
+ super();
1722
1545
  this.doc = doc;
1723
1546
  }
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];
1547
+ getSchemaContainer() {
1548
+ return this.doc.definitions;
1730
1549
  }
1731
- /**
1732
- * Is array schema.
1733
- */
1734
- isOpenAPIArraySchema(schema) {
1735
- return typeof schema === "object" && schema.type === "array";
1550
+ getParameterContainer() {
1551
+ return this.doc.parameters;
1736
1552
  }
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);
1553
+ getResponseContainer() {
1554
+ return this.doc.responses;
1751
1555
  }
1556
+ getRequestBodyContainer() {}
1752
1557
  /**
1753
- * OpenAPI parameter to base parameter.
1558
+ * V2 parameter shape differs from V3: top-level `items`/`properties`/`enum`
1559
+ * rather than nested under `schema`. Override accordingly.
1754
1560
  */
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));
1561
+ getParameterByRef(parameter, enums = [], upLevelSchemaKey = "") {
1562
+ if (Base.isRef(parameter)) {
1563
+ const refName = Base.ref2name(parameter.$ref, this.doc);
1564
+ const resolved = this.doc.parameters?.[refName];
1565
+ if (!resolved) throw new Error(`Parameter reference not found: ${parameter.$ref}`);
1566
+ parameter = resolved;
1567
+ }
1568
+ const p = parameter;
1569
+ const { name, required, description, type, items, enum: enum_, properties, schema } = p;
1570
+ if (enum_) {
1571
+ const enumType = Base.upperCamelCase(Base.normalize(upLevelSchemaKey)) + Base.upperCamelCase(Base.normalize(name));
1760
1572
  const enumSchema = {
1761
- name: type,
1762
- enum: [...new Set(parameterSchema.enum)]
1573
+ name: enumType,
1574
+ enum: [...new Set(enum_)]
1763
1575
  };
1764
1576
  const sameEnum = Base.findSameSchema(enumSchema, enums);
1765
- if (!sameEnum && Base.isValidEnumType(parameterSchema)) enums.push(enumSchema);
1577
+ if (!sameEnum && Base.isValidEnumType({
1578
+ type: enumType,
1579
+ enum: enum_
1580
+ })) enums.push(enumSchema);
1766
1581
  return {
1767
1582
  name,
1768
1583
  required,
1769
1584
  description,
1770
- deprecated,
1771
- in: schema.in,
1772
- schema: { type: sameEnum?.name ?? type }
1585
+ in: p.in,
1586
+ schema: { type: sameEnum?.name ?? enumType }
1773
1587
  };
1774
1588
  }
1589
+ if (items) return {
1590
+ name,
1591
+ required,
1592
+ description,
1593
+ in: p.in,
1594
+ schema: {
1595
+ type,
1596
+ items
1597
+ }
1598
+ };
1599
+ if (schema && Base.isRef(schema)) return {
1600
+ name,
1601
+ required,
1602
+ description,
1603
+ in: p.in,
1604
+ schema: { type: Base.capitalize(Base.ref2name(schema.$ref)) }
1605
+ };
1775
1606
  return {
1776
1607
  name,
1777
1608
  required,
1778
1609
  description,
1779
- deprecated,
1780
- in: schema.in,
1781
- schema: schema.schema && this.getSchemaByRef(schema.schema, false, enums, upLevelSchemaKey + Base.capitalize(name))
1610
+ in: p.in,
1611
+ schema: {
1612
+ type,
1613
+ properties
1614
+ }
1782
1615
  };
1783
1616
  }
1784
1617
  /**
1785
- * OpenAPI schema to base response
1618
+ * V2 response shape: a `schema` field directly, not `content`. V2 always
1619
+ * emits JSON.
1786
1620
  */
1787
1621
  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
- }));
1622
+ if (Base.isRef(schema)) schema = this.doc.responses[Base.ref2name(schema.$ref, this.doc)];
1623
+ const { schema: responseSchema } = schema;
1624
+ return [{
1625
+ type: "application/json",
1626
+ schema: responseSchema ? this.getSchemaByRef(responseSchema, true) : void 0
1627
+ }];
1805
1628
  }
1806
1629
  /**
1807
- * Transform all OpenAPI schema to Base Schema
1630
+ * V2 has no `requestBody` concept; parameters with `in: body` or
1631
+ * `in: formData` are split out and turned into a synthetic requestBody
1632
+ * here. A single body param named `body` is used directly; otherwise
1633
+ * the body / formData params are wrapped in a synthetic object.
1808
1634
  */
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
1635
  init() {
1874
- const { components = {}, paths = {} } = this.doc;
1636
+ const { paths = {} } = this.doc;
1875
1637
  const enums = [];
1876
- const { requestBodies = {}, responses = {}, parameters = {}, schemas = {} } = components;
1877
- const schemas_ = Object.keys(schemas).reduce((acc, key) => {
1878
- const schema = schemas[key];
1638
+ const schemaContainer = this.getSchemaContainer() ?? {};
1639
+ const parameterContainer = this.getParameterContainer() ?? {};
1640
+ const responseContainer = this.getResponseContainer() ?? {};
1641
+ const schemas_ = Object.keys(schemaContainer).reduce((acc, key) => {
1642
+ const schema = schemaContainer[key];
1879
1643
  return {
1880
1644
  ...acc,
1881
1645
  [key]: this.getSchemaByRef(schema, false, enums, key)
1882
1646
  };
1883
1647
  }, {});
1884
- const parameters_ = Object.keys(parameters).reduce((acc, key) => {
1885
- const parameter = parameters[key];
1648
+ const parameters_ = Object.keys(parameterContainer).reduce((acc, key) => {
1649
+ const parameter = parameterContainer[key];
1886
1650
  return {
1887
1651
  ...acc,
1888
1652
  [key]: this.getParameterByRef(parameter, enums, key)
1889
1653
  };
1890
1654
  }, {});
1891
- const responses_ = Object.keys(responses).reduce((acc, key) => {
1892
- const response = responses[key];
1655
+ const responses_ = Object.keys(responseContainer).reduce((acc, key) => {
1656
+ const response = responseContainer[key];
1893
1657
  return {
1894
1658
  ...acc,
1895
1659
  [key]: this.getResponseByRef(response)
1896
1660
  };
1897
1661
  }, {});
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) => {
1662
+ const apis = {};
1663
+ for (const path of Object.keys(paths)) {
1906
1664
  let pathObject = paths[path] ?? {};
1907
1665
  if (pathObject.$ref) {
1908
1666
  const resolved = this.resolvePathRef(pathObject.$ref);
1909
1667
  if (resolved) pathObject = resolved;
1910
1668
  }
1911
- const { parameters = [], description, summary } = pathObject;
1669
+ const { parameters = [] } = pathObject;
1912
1670
  const methodApis = [];
1913
1671
  Object.values(HttpMethods).forEach((method) => {
1914
1672
  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
- }
1673
+ if (!methodObject) return;
1674
+ const { deprecated, operationId, summary: summary_, description: description_, responses } = methodObject;
1675
+ const { parameters: parameters_ = [] } = methodObject;
1676
+ const baseParameters = [...parameters, ...parameters_].map((p) => this.getParameterByRef(p, enums));
1677
+ const uniqueParameterName = [...new Set(baseParameters.map((p) => p.name))];
1678
+ const responsesClone = responses ? { ...responses } : {};
1679
+ if (Object.keys(responsesClone).length === 0) responsesClone[200] = { description: "Successful response" };
1680
+ const inBody = baseParameters.filter((p) => p.in === "body" || p.in === "formData");
1681
+ const notInBody = baseParameters.filter((p) => p.in !== "body" && p.in !== "formData");
1682
+ const httpCodes = Object.keys(responsesClone);
1683
+ for (const code of httpCodes) if (code in responsesClone) {
1684
+ const response = responsesClone[code];
1685
+ const responseSchema = this.getResponseByRef(response);
1686
+ const inBodyOnlyHasBody = inBody.length === 1 && inBody[0].in === "body" && inBody[0].name === "body";
1687
+ methodApis.push({
1688
+ method,
1689
+ operationId,
1690
+ summary: summary_,
1691
+ deprecated,
1692
+ description: description_,
1693
+ parameters: uniqueParameterName.map((name) => notInBody.find((p) => p.name === name)).filter((p) => p !== void 0),
1694
+ responses: responseSchema,
1695
+ requestBody: inBody.length > 0 ? inBodyOnlyHasBody ? [{
1696
+ type: "application/json",
1697
+ schema: inBody[0].schema
1698
+ }] : [{
1699
+ type: "application/json",
1700
+ schema: {
1701
+ type: "object",
1702
+ properties: inBody.reduce((a, p) => {
1703
+ return {
1704
+ ...a,
1705
+ [p.name]: {
1706
+ type: p.schema?.type ?? "unknown",
1707
+ required: p.schema?.required,
1708
+ items: p.schema?.items,
1709
+ description: p.schema?.description
1710
+ }
1711
+ };
1712
+ }, {})
1713
+ }
1714
+ }] : void 0
1715
+ });
1716
+ break;
1938
1717
  }
1939
1718
  });
1940
- return {
1941
- ...acc,
1942
- [path]: methodApis
1943
- };
1944
- }, {});
1719
+ apis[path] = methodApis;
1720
+ }
1945
1721
  return {
1946
1722
  enums: Base.uniqueEnums(enums),
1947
1723
  schemas: schemas_,
1948
1724
  responses: responses_,
1949
1725
  parameters: parameters_,
1950
- requestBodies: requestBodies_,
1726
+ requestBodies: {},
1951
1727
  apis
1952
1728
  };
1953
1729
  }
1954
1730
  };
1955
1731
  //#endregion
1732
+ //#region src/openapi/V3.ts
1733
+ var V3 = class extends VersionedProvider {
1734
+ doc;
1735
+ version = "v3";
1736
+ constructor(doc) {
1737
+ super();
1738
+ this.doc = doc;
1739
+ }
1740
+ getSchemaContainer() {
1741
+ return this.doc.components?.schemas;
1742
+ }
1743
+ getParameterContainer() {
1744
+ return this.doc.components?.parameters;
1745
+ }
1746
+ getResponseContainer() {
1747
+ return this.doc.components?.responses;
1748
+ }
1749
+ getRequestBodyContainer() {
1750
+ return this.doc.components?.requestBodies;
1751
+ }
1752
+ };
1753
+ //#endregion
1754
+ //#region src/openapi/V3_1.ts
1755
+ var V3_1 = class extends VersionedProvider {
1756
+ doc;
1757
+ version = "v3_1";
1758
+ constructor(doc) {
1759
+ super();
1760
+ this.doc = doc;
1761
+ }
1762
+ formatRefName(name) {
1763
+ return Base.upperCamelCase(name);
1764
+ }
1765
+ getSchemaContainer() {
1766
+ return this.doc.components?.schemas;
1767
+ }
1768
+ getParameterContainer() {
1769
+ return this.doc.components?.parameters;
1770
+ }
1771
+ getResponseContainer() {
1772
+ return this.doc.components?.responses;
1773
+ }
1774
+ getRequestBodyContainer() {
1775
+ return this.doc.components?.requestBodies;
1776
+ }
1777
+ };
1778
+ //#endregion
1956
1779
  //#region src/openapi/index.ts
1957
1780
  const logger$1 = (0, _moccona_logger.createScopedLogger)("OpenAPI");
1958
1781
  let OpenAPIVersion = /* @__PURE__ */ function(OpenAPIVersion) {
@@ -2018,7 +1841,7 @@ async function codeGen(initOptions) {
2018
1841
  //#endregion
2019
1842
  //#region src/vite-plugin/index.ts
2020
1843
  const PLUGIN_NAME = "api-code-gen";
2021
- const logger = (0, _moccona_logger.createScopedLogger)("api-code-gen");
1844
+ const pluginLogger = (0, _moccona_logger.createScopedLogger)("api-code-gen");
2022
1845
  /**
2023
1846
  * Run TypeScript type checking on generated file
2024
1847
  */
@@ -2047,7 +1870,7 @@ async function validateSpecPath(specPath) {
2047
1870
  async function generateForOption(option) {
2048
1871
  const { name, typeCheck = true, verbose, ...restOptions } = option;
2049
1872
  try {
2050
- console.log(`\x1b[36m├─\x1b[0m ${name}`);
1873
+ logger.info(`Generating ${name}...`);
2051
1874
  const config = await loadConfig({
2052
1875
  name,
2053
1876
  cliOptions: {
@@ -2071,8 +1894,8 @@ async function generateForOption(option) {
2071
1894
  if (typeCheck && config.output) {
2072
1895
  const typeErrors = await runTypeCheck(config.output);
2073
1896
  if (typeErrors.length > 0) {
2074
- logger.warn(`Type check failed for ${config.output}`);
2075
- if (verbose) for (const error of typeErrors) logger.warn(` ${error}`);
1897
+ pluginLogger.warn(`Type check failed for ${config.output}`);
1898
+ if (verbose) for (const error of typeErrors) pluginLogger.warn(` ${error}`);
2076
1899
  }
2077
1900
  }
2078
1901
  return {
@@ -2113,45 +1936,47 @@ async function generateForOption(option) {
2113
1936
  */
2114
1937
  function apiCodeGenPlugin(options) {
2115
1938
  if (!Array.isArray(options) || options.length === 0) {
2116
- logger.warn("No API configurations provided to apiCodeGenPlugin");
1939
+ pluginLogger.warn("No API configurations provided to apiCodeGenPlugin");
2117
1940
  return { name: PLUGIN_NAME };
2118
1941
  }
2119
1942
  return {
2120
1943
  name: PLUGIN_NAME,
2121
1944
  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`);
1945
+ logger.heading("API Code Gen", env?.command);
2126
1946
  const results = await Promise.all(options.map(generateForOption));
2127
1947
  const successCount = results.filter((r) => r.success).length;
2128
1948
  const failCount = options.length - successCount;
2129
- console.log(`\x1b[1m\x1b[36m${"─".repeat(50)}\x1b[0m`);
1949
+ logger.divider();
2130
1950
  for (const result of results) if (result.success) {
2131
1951
  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"}`);
1952
+ if (stats) logger.item(`${name} → ${output} (${stats.endpoints} endpoints, ${stats.schemas} schemas) ${stats.duration}ms`, "green");
1953
+ else logger.item(`${name} → ${output || "N/A"}`, "green");
2134
1954
  } else {
2135
1955
  const { name, error } = result;
2136
1956
  if (isApicodegenError(error)) {
2137
- console.log(`\x1b[31m✗\x1b[0m ${name}`);
2138
- console.log(`\x1b[90m${formatError(error, true)}\x1b[0m`);
1957
+ logger.item(name, "red");
1958
+ logger.error(error, true);
2139
1959
  } else {
2140
1960
  const wrapped = wrapError(error, {
2141
- code: "E_GENERATION_FAILED",
1961
+ code: ErrorCodes.GENERATION_FAILED,
2142
1962
  message: `Failed to generate API "${name}"`
2143
1963
  });
2144
- console.log(`\x1b[31m✗\x1b[0m ${name}`);
2145
- console.log(`\x1b[90m${formatError(wrapped, true)}\x1b[0m`);
1964
+ logger.item(name, "red");
1965
+ logger.error(wrapped, true);
2146
1966
  }
2147
1967
  }
2148
- console.log(`\x1b[1m\x1b[36m${"─".repeat(50)}\x1b[0m`);
1968
+ logger.divider();
2149
1969
  const totalDuration = results.reduce((sum, r) => sum + (r.stats?.duration || 0), 0);
2150
1970
  const totalEndpoints = results.reduce((sum, r) => sum + (r.stats?.endpoints || 0), 0);
2151
1971
  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`);
1972
+ logger.summary({
1973
+ succeeded: successCount,
1974
+ failed: failCount,
1975
+ endpoints: totalEndpoints,
1976
+ schemas: totalSchemas,
1977
+ duration: totalDuration
1978
+ });
1979
+ logger.divider();
2155
1980
  return {};
2156
1981
  }
2157
1982
  };
@@ -2179,11 +2004,11 @@ exports.SchemaType = SchemaType;
2179
2004
  exports.SuccessHttpStatusCode = SuccessHttpStatusCode;
2180
2005
  exports.apiCodeGenPlugin = apiCodeGenPlugin;
2181
2006
  exports.codeGen = codeGen;
2182
- exports.configToCLIOptions = configToCLIOptions;
2183
2007
  exports.createErrors = createErrors;
2184
2008
  exports.formatError = formatError;
2185
2009
  exports.isApicodegenError = isApicodegenError;
2186
2010
  exports.loadConfig = loadConfig;
2011
+ exports.logger = logger;
2187
2012
  exports.printError = printError;
2188
2013
  exports.toProviderOptions = toProviderOptions;
2189
2014
  exports.wrapError = wrapError;