@moccona/apicodegen 0.0.8 → 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.
@@ -240,29 +240,6 @@ var ApicodegenError = class ApicodegenError extends Error {
240
240
  }
241
241
  };
242
242
  /**
243
- * ANSI color codes for terminal output
244
- */
245
- const Colors = {
246
- reset: "\x1B[0m",
247
- bold: "\x1B[1m",
248
- red: "\x1B[31m",
249
- green: "\x1B[32m",
250
- yellow: "\x1B[33m",
251
- blue: "\x1B[34m",
252
- cyan: "\x1B[36m",
253
- gray: "\x1B[90m",
254
- brightRed: "\x1B[91m",
255
- brightGreen: "\x1B[92m"
256
- };
257
- /**
258
- * Format error for CLI output
259
- */
260
- function formatError(error, verbose = false) {
261
- if (error instanceof ApicodegenError) return error.toString(verbose);
262
- 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}` : ""}`;
263
- return `${Colors.red}${Colors.bold}Error${Colors.reset}: ${String(error)}`;
264
- }
265
- /**
266
243
  * Create error with common patterns
267
244
  */
268
245
  const createErrors = {
@@ -399,6 +376,68 @@ function isApicodegenError(error) {
399
376
  return error instanceof ApicodegenError;
400
377
  }
401
378
  //#endregion
379
+ //#region src/core/logger.ts
380
+ const cyan = (s) => `\x1b[36m${s}\x1b[0m`;
381
+ const green = (s) => `\x1b[32m${s}\x1b[0m`;
382
+ const red = (s) => `\x1b[31m${s}\x1b[0m`;
383
+ const blue = (s) => `\x1b[34m${s}\x1b[0m`;
384
+ const yellow = (s) => `\x1b[33m${s}\x1b[0m`;
385
+ const magenta = (s) => `\x1b[35m${s}\x1b[0m`;
386
+ const gray = (s) => `\x1b[90m${s}\x1b[0m`;
387
+ const bold = (s) => `\x1b[1m${s}\x1b[0m`;
388
+ const logger$1 = {
389
+ success(msg) {
390
+ console.log(`${green("✓")} ${msg}`);
391
+ },
392
+ error(err, verbose = false) {
393
+ if (isApicodegenError(err)) console.error(`${red("✗")} ${err.toString(verbose)}`);
394
+ else if (err instanceof Error) {
395
+ const msg = `Error: ${err.message}`;
396
+ console.error(`${red("✗")} ${msg}${verbose && err.stack ? `\n${gray(err.stack)}` : ""}`);
397
+ } else console.error(`${red("✗")} ${String(err)}`);
398
+ },
399
+ info(msg) {
400
+ console.log(`${blue("ℹ")} ${msg}`);
401
+ },
402
+ warn(msg) {
403
+ console.log(`${yellow("⚠")} ${msg}`);
404
+ },
405
+ loading(msg) {
406
+ console.log(`${yellow("🔄")} ${msg}`);
407
+ },
408
+ watching(msg) {
409
+ console.log(`${magenta("⟳")} ${msg}`);
410
+ },
411
+ fileChange(filePath) {
412
+ console.log(`${yellow("↓")} ${filePath}`);
413
+ },
414
+ fileAdd(filePath) {
415
+ console.log(`${green("+")} ${filePath}`);
416
+ },
417
+ shutdown() {
418
+ console.log(`\n${gray("👋 Shutting down...")}`);
419
+ },
420
+ divider(width = 50) {
421
+ console.log(`${bold(cyan("─".repeat(width)))}`);
422
+ },
423
+ heading(text, mode, width = 50) {
424
+ console.log(`${bold(cyan("─".repeat(width)))}`);
425
+ console.log(`${bold(cyan(text))}`);
426
+ console.log(`${gray("Mode:")} ${mode || "unknown"}`);
427
+ console.log(`${bold(cyan("─".repeat(width)))}`);
428
+ },
429
+ item(label, color = "green") {
430
+ const icon = color === "green" ? "✓" : color === "red" ? "✗" : "⚠";
431
+ console.log(`${color === "green" ? green(icon) : color === "red" ? red(icon) : yellow(icon)} ${label}`);
432
+ },
433
+ summary(stats) {
434
+ const { succeeded, failed, endpoints, schemas, duration } = stats;
435
+ const label = `API Code Gen - Complete (${succeeded} succeeded${failed > 0 ? `, ${failed} failed` : ""}, ${endpoints} endpoints, ${schemas} schemas, ${duration}ms)`;
436
+ if (failed === 0) console.log(`${green("✓")} ${label}`);
437
+ else console.log(`${yellow("⚠")} ${label}`);
438
+ }
439
+ };
440
+ //#endregion
402
441
  //#region src/core/base/Adaptor.ts
403
442
  /**
404
443
  * Base adapter for tool
@@ -572,7 +611,9 @@ var Base = class Base {
572
611
  */
573
612
  static camelCase(text) {
574
613
  text = text.trim();
575
- return text.split("_").filter(Boolean).map((t, index) => index === 0 ? t : Base.capitalize(t)).join("");
614
+ const parts = text.split("_").filter(Boolean);
615
+ while (parts[0]?.match(/^\d/)) parts.shift();
616
+ return parts.map((t, index) => index === 0 ? t : Base.capitalize(t)).join("");
576
617
  }
577
618
  /**
578
619
  * Converts a string to UpperCamelCase.
@@ -762,10 +803,19 @@ var Generator = class Generator {
762
803
  return createPrinter().printFile(sourceFile);
763
804
  }
764
805
  static async write(code, filepath) {
806
+ const { mkdir } = await import("node:fs/promises");
807
+ const { dirname } = await import("node:path");
765
808
  try {
809
+ await mkdir(dirname(filepath), { recursive: true });
766
810
  await writeFile(filepath, code);
767
811
  } catch (error) {
768
- console.error(error);
812
+ throw new ApicodegenError({
813
+ code: ErrorCodes.OUTPUT_DIR_MISSING,
814
+ message: "Failed to write generated code to output file",
815
+ location: filepath,
816
+ cause: error instanceof Error ? error : new Error(String(error)),
817
+ suggestions: ["Verify the output directory path is writable", "Check that the parent directory exists or can be created"]
818
+ });
769
819
  }
770
820
  }
771
821
  /**
@@ -801,9 +851,12 @@ var Generator = class Generator {
801
851
  static addComments(node, comments) {
802
852
  if (!Array.isArray(comments) || comments.filter(Boolean).length === 0) return;
803
853
  const formatComment = (comment) => {
804
- return comment.tag ? ` @${comment.tag} ${comment.comment ?? ""}` : ` ${comment.comment}`;
854
+ if (comment.tag === "returns") return `* @returns {${comment.type}} ${comment.comment ?? ""}`;
855
+ if (comment.tag === "param") return comment.comment ? `* @param ${comment.paramName} - ${comment.comment}` : `* @param ${comment.paramName}`;
856
+ if (comment.tag) return `* @${comment.tag} ${comment.comment ?? ""}`;
857
+ return `* ${comment.comment}`;
805
858
  };
806
- const formattedComments = "*\n" + comments.map(formatComment).join("\n").trim() + "\n";
859
+ const formattedComments = comments.map(formatComment).join("\n").trim() + "\n";
807
860
  addSyntheticLeadingComment(node, SyntaxKind.MultiLineCommentTrivia, formattedComments, true);
808
861
  }
809
862
  /**
@@ -820,6 +873,53 @@ var Generator = class Generator {
820
873
  const nonArraySchema = schema;
821
874
  return nonArraySchema.format === "blob" || nonArraySchema.format === "binary" || nonArraySchema.type === "file";
822
875
  }
876
+ static schemaToTypeString(schema) {
877
+ if (schema.type === "array") {
878
+ const arraySchema = schema;
879
+ return arraySchema.items ? `${Generator.schemaToTypeString(arraySchema.items)}[]` : "unknown";
880
+ }
881
+ const singleSchema = schema;
882
+ if (schema.type === "string") return "string";
883
+ if (schema.type === "number" || schema.type === "integer") return "number";
884
+ if (schema.type === "boolean") return "boolean";
885
+ if (schema.type === "object" || schema.properties) return "object";
886
+ if (singleSchema.format === "binary" || singleSchema.type === "file") return "Blob";
887
+ if (singleSchema.format === "blob") return "Blob";
888
+ if (singleSchema.ref) return singleSchema.ref;
889
+ return "unknown";
890
+ }
891
+ static generateParamTags(parameters, requestBody) {
892
+ const tags = [];
893
+ for (const p of parameters) {
894
+ const paramName = Base.camelCase(Base.normalize(p.name));
895
+ let paramType = "unknown";
896
+ if (p.schema) paramType = Generator.schemaToTypeString(p.schema);
897
+ const isOptional = p.required === false;
898
+ tags.push({
899
+ tag: "param",
900
+ paramName,
901
+ type: `${paramType}${isOptional ? " | undefined" : ""}`,
902
+ comment: p.description ?? ""
903
+ });
904
+ }
905
+ if (requestBody?.schema && "properties" in requestBody.schema) {
906
+ const properties = requestBody.schema.properties;
907
+ const required = requestBody.schema.required;
908
+ const requiredArray = Array.isArray(required) ? required : [];
909
+ for (const [key, schema] of Object.entries(properties ?? {})) {
910
+ const paramName = `req.${key}`;
911
+ const paramType = Generator.schemaToTypeString(schema);
912
+ const isOptional = !requiredArray.includes(key);
913
+ tags.push({
914
+ tag: "param",
915
+ paramName,
916
+ type: `${paramType}${isOptional ? " | undefined" : ""}`,
917
+ comment: schema.description ?? ""
918
+ });
919
+ }
920
+ }
921
+ return tags;
922
+ }
823
923
  static toRequestBodyTypeNode(schema) {
824
924
  return factory.createParameterDeclaration(void 0, void 0, factory.createIdentifier("req"), void 0, Generator.toTypeNode(schema));
825
925
  }
@@ -898,8 +998,8 @@ var Generator = class Generator {
898
998
  factory.createIdentifier("file"),
899
999
  factory.createPropertyAccessExpression(factory.createAsExpression(factory.createIdentifier("file"), factory.createTypeReferenceNode(factory.createIdentifier("File"), void 0)), factory.createIdentifier("name"))
900
1000
  ]))])));
901
- 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))])])));
902
- 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))])]))));
1001
+ 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" || Generator.isBinarySchema(schemaByKey) || schemaByKey.isRef ? factory.createElementAccessExpression(factory.createIdentifier("req"), factory.createStringLiteral(key)) : schemaByKey.type === "array" || schemaByKey.type === "object" ? factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier("JSON"), factory.createIdentifier("stringify")), void 0, [factory.createElementAccessExpression(factory.createIdentifier("req"), factory.createStringLiteral(key))]) : factory.createCallExpression(factory.createIdentifier("String"), void 0, [factory.createElementAccessExpression(factory.createIdentifier("req"), factory.createStringLiteral(key))])])));
1002
+ 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" || Generator.isBinarySchema(schemaByKey) || schemaByKey.isRef ? factory.createElementAccessExpression(factory.createIdentifier("req"), factory.createStringLiteral(key)) : schemaByKey.type === "array" || schemaByKey.type === "object" ? factory.createCallExpression(factory.createPropertyAccessExpression(factory.createIdentifier("JSON"), factory.createIdentifier("stringify")), void 0, [factory.createElementAccessExpression(factory.createIdentifier("req"), factory.createStringLiteral(key))]) : factory.createCallExpression(factory.createIdentifier("String"), void 0, [factory.createElementAccessExpression(factory.createIdentifier("req"), factory.createStringLiteral(key))])]))));
903
1003
  });
904
1004
  return statements;
905
1005
  }
@@ -911,7 +1011,7 @@ var Generator = class Generator {
911
1011
  const parametersShouldNotPutInFormData = parameters.filter((p) => !parametersShouldPutInFormData.includes(p));
912
1012
  const isRequestBodyContainsBinary = requestBody?.schema && "properties" in requestBody.schema && Object.values(requestBody.schema?.properties ?? {}).some((p) => Generator.isBinarySchema(p));
913
1013
  const hasBinaryInParameters = parameters.some((p) => p?.schema && Generator.isBinarySchema(p.schema));
914
- const shouldPutParametersOrBodyInFormData = isFormDataRequest || isRequestBodyBinary || hasBinaryInParameters || isRequestBodyContainsBinary || parametersShouldPutInFormData.length > 0;
1014
+ const shouldPutParametersOrBodyInFormData = !!isFormDataRequest && (isRequestBodyBinary || hasBinaryInParameters || isRequestBodyContainsBinary || parametersShouldPutInFormData.length > 0);
915
1015
  return factory.createBlock([...shouldPutParametersOrBodyInFormData ? Generator.toFormDataStatement(parametersShouldPutInFormData, requestBody?.schema) : [], ...adapter.client(uri, method, parametersShouldNotPutInFormData, requestBody, response, adapter, shouldPutParametersOrBodyInFormData, shouldParseResponseToJSON)]);
916
1016
  }
917
1017
  static schemaToStatemets(parsedDoc, adaptor, options) {
@@ -938,10 +1038,11 @@ var Generator = class Generator {
938
1038
  const shouldAddExtraMethodNameSuffix = requestBody.length > 1;
939
1039
  for (const req of requestBody) {
940
1040
  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));
1041
+ const mergedDescription = [description, summary].filter(Boolean).join(". ");
941
1042
  Generator.addComments(statement, [
942
- description && { comment: description },
943
- summary && { comment: summary },
944
- deprecated && { tag: "deprecated" }
1043
+ mergedDescription && { comment: mergedDescription },
1044
+ deprecated && { tag: "deprecated" },
1045
+ ...Generator.generateParamTags(parameters, req)
945
1046
  ].filter(Boolean));
946
1047
  statements.push(statement);
947
1048
  }
@@ -1051,12 +1152,12 @@ var FetchAdapter = class extends Adapter {
1051
1152
  }
1052
1153
  };
1053
1154
  //#endregion
1054
- //#region src/openapi/V2.ts
1055
- var V2 = class {
1056
- doc;
1057
- constructor(doc) {
1058
- this.doc = doc;
1059
- }
1155
+ //#region src/openapi/VersionedProvider.ts
1156
+ /**
1157
+ * Abstract base class. Subclasses implement the four container accessors
1158
+ * and a version tag. The shared logic lives here.
1159
+ */
1160
+ var VersionedProvider = class {
1060
1161
  /**
1061
1162
  * Resolves a path $ref to the actual path object.
1062
1163
  */
@@ -1068,281 +1169,37 @@ var V2 = class {
1068
1169
  * Is array schema.
1069
1170
  */
1070
1171
  isOpenAPIArraySchema(schema) {
1071
- return typeof schema === "object" && schema.type === "array";
1172
+ return typeof schema === "object" && schema !== null && schema.type === "array";
1072
1173
  }
1073
1174
  /**
1074
- * OpenAPI schema to base schema.
1175
+ * OpenAPI schema to base schema. Override for version-specific quirks
1176
+ * (V3_1 throws on missing ref; V3 returns `{ type: 'unknown' }`).
1075
1177
  */
1076
1178
  getSchemaByRef(schema, reserveRef = false, enums = [], upLevelSchemaKey = "") {
1077
1179
  let refName = "";
1078
1180
  if (Base.isRef(schema)) {
1079
- refName = Base.upperCamelCase(Base.ref2name(schema.$ref));
1181
+ refName = this.formatRefName(Base.ref2name(schema.$ref));
1080
1182
  if (reserveRef) return { type: upLevelSchemaKey + refName };
1081
- if (!this.doc.definitions) this.doc.definitions = {};
1082
- schema = this.doc.definitions[Base.ref2name(schema.$ref, this.doc)];
1183
+ const resolvedSchema = this.getSchemaContainer()?.[Base.ref2name(schema.$ref, this.doc)];
1184
+ if (!resolvedSchema) return { type: "unknown" };
1185
+ schema = resolvedSchema;
1083
1186
  }
1084
1187
  return this.toBaseSchema(schema, enums, "", upLevelSchemaKey + refName);
1085
1188
  }
1086
1189
  /**
1087
- * Transform all OpenAPI schema to Base Schema
1088
- */
1089
- toBaseSchema(schema, enums = [], schemaKey = "", upLevelSchemaKey = "") {
1090
- if (!schema) return { type: "unknown" };
1091
- if (Base.isRef(schema)) return this.getSchemaByRef(schema, true);
1092
- if (this.isOpenAPIArraySchema(schema)) {
1093
- const { type, description, items, required } = schema;
1094
- return {
1095
- type,
1096
- required: !!required,
1097
- description,
1098
- items: this.toBaseSchema(items, enums, schemaKey, upLevelSchemaKey)
1099
- };
1100
- } else {
1101
- const { required = [], allOf, anyOf, description, enum: enum_, format, oneOf, properties = {} } = schema;
1102
- let { type } = schema;
1103
- if (enum_ && type !== "boolean") {
1104
- const enumObject = {
1105
- name: Base.upperCamelCase(Base.normalize(upLevelSchemaKey)) + Base.upperCamelCase(Base.normalize(schemaKey)),
1106
- enum: [...new Set(enum_)]
1107
- };
1108
- const sameObject = Base.findSameSchema(enumObject, enums);
1109
- if (!sameObject && Base.isValidEnumType(schema)) enums.push(enumObject);
1110
- return {
1111
- type: sameObject ? sameObject.name : Base.isBooleanEnum(schema) ? "boolean" : enumObject.name,
1112
- required,
1113
- description
1114
- };
1115
- }
1116
- if (type === void 0 && Object.keys(properties).length > 0) type = "object";
1117
- return {
1118
- type,
1119
- required,
1120
- description,
1121
- enum: enum_,
1122
- format,
1123
- allOf: allOf?.map((s) => Base.isRef(s) ? {
1124
- ...s,
1125
- ref: s.$ref,
1126
- type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1127
- } : this.toBaseSchema(s, enums)),
1128
- anyOf: anyOf?.map((s) => Base.isRef(s) ? {
1129
- ...s,
1130
- ref: s.$ref,
1131
- type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1132
- } : this.toBaseSchema(s, enums)),
1133
- oneOf: oneOf?.map((s) => Base.isRef(s) ? {
1134
- ...s,
1135
- ref: s.$ref,
1136
- type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1137
- } : this.toBaseSchema(s, enums)),
1138
- properties: Object.keys(properties).reduce((acc, p) => {
1139
- const propSchema = properties[p];
1140
- return {
1141
- ...acc,
1142
- [p]: Base.isRef(propSchema) ? { type: Base.capitalize(Base.ref2name(propSchema.$ref, this.doc)) } : this.toBaseSchema(propSchema, enums, p, upLevelSchemaKey)
1143
- };
1144
- }, {})
1145
- };
1146
- }
1147
- }
1148
- /**
1149
- * OpenAPI parameter to base parameter.
1150
- */
1151
- getParameterByRef(parameter, enums = [], upLevelSchemaKey = "") {
1152
- if (Base.isRef(parameter)) {
1153
- const refName = Base.ref2name(parameter.$ref, this.doc);
1154
- const resolved = this.doc.parameters?.[refName];
1155
- if (!resolved) throw new Error(`Parameter reference not found: ${parameter.$ref}`);
1156
- parameter = resolved;
1157
- }
1158
- const p = parameter;
1159
- const { name, required, description, type, items, enum: enum_, properties, schema } = p;
1160
- if (enum_) {
1161
- const type = Base.upperCamelCase(Base.normalize(upLevelSchemaKey)) + Base.upperCamelCase(Base.normalize(name));
1162
- const enumSchema = {
1163
- name: type,
1164
- enum: [...new Set(enum_)]
1165
- };
1166
- const sameEnum = Base.findSameSchema(enumSchema, enums);
1167
- if (!sameEnum && Base.isValidEnumType({
1168
- type,
1169
- enum: enum_
1170
- })) enums.push(enumSchema);
1171
- return {
1172
- name,
1173
- required,
1174
- description,
1175
- in: p.in,
1176
- schema: { type: sameEnum?.name ?? type }
1177
- };
1178
- }
1179
- if (items) return {
1180
- name,
1181
- required,
1182
- description,
1183
- in: p.in,
1184
- schema: {
1185
- type,
1186
- items
1187
- }
1188
- };
1189
- if (schema && Base.isRef(schema)) return {
1190
- name,
1191
- required,
1192
- description,
1193
- in: p.in,
1194
- schema: { type: Base.capitalize(Base.ref2name(schema.$ref)) }
1195
- };
1196
- return {
1197
- name,
1198
- required,
1199
- description,
1200
- in: p.in,
1201
- schema: {
1202
- type,
1203
- properties
1204
- }
1205
- };
1206
- }
1207
- /**
1208
- * OpenAPI schema to base response
1209
- */
1210
- getResponseByRef(schema) {
1211
- if (Base.isRef(schema)) schema = this.doc.responses[Base.ref2name(schema.$ref, this.doc)];
1212
- const { schema: responseSchema } = schema;
1213
- return [{
1214
- type: "application/json",
1215
- schema: responseSchema && this.getSchemaByRef(responseSchema, true)
1216
- }];
1217
- }
1218
- init() {
1219
- const { definitions = {}, responses = {}, paths = {} } = this.doc;
1220
- const enums = [];
1221
- const definitions_ = Object.keys(definitions).reduce((acc, key) => {
1222
- const schema = definitions[key];
1223
- return {
1224
- ...acc,
1225
- [key]: this.getSchemaByRef(schema, false, enums, key)
1226
- };
1227
- }, {});
1228
- const responses_ = Object.keys(responses).reduce((acc, key) => {
1229
- const response = responses[key];
1230
- return {
1231
- ...acc,
1232
- [key]: this.getResponseByRef(response)
1233
- };
1234
- }, {});
1235
- const apis = Object.keys(paths).reduce((acc, path) => {
1236
- let pathObject = paths[path] ?? {};
1237
- if (pathObject.$ref) {
1238
- const resolved = this.resolvePathRef(pathObject.$ref);
1239
- if (resolved) pathObject = resolved;
1240
- }
1241
- const { parameters = [] } = pathObject;
1242
- const methodApis = [];
1243
- Object.values(HttpMethods).forEach((method) => {
1244
- const methodObject = pathObject[method];
1245
- if (methodObject) {
1246
- const { deprecated, operationId, summary: summary_, description: description_, responses = {} } = methodObject;
1247
- const { parameters: parameters_ = [] } = methodObject;
1248
- const baseParameters = [...parameters, ...parameters_].map((parameter) => this.getParameterByRef(parameter, enums));
1249
- const uniqueParameterName = [...new Set(baseParameters.map((p) => p.name))];
1250
- if (Object.keys(responses).length === 0) Object.assign(responses, { 200: { description: "Successful response" } });
1251
- const inBody = baseParameters.filter((p) => p.in === "body" || p.in === "formData");
1252
- const notInBody = baseParameters.filter((p) => p.in !== "body" && p.in !== "formData");
1253
- const httpCodes = Object.keys(responses);
1254
- for (const code of httpCodes) if (code in responses) {
1255
- const response = responses[code];
1256
- const responseSchema = this.getResponseByRef(response);
1257
- const inBodyOnlyHasBody = inBody && inBody.length === 1 && inBody[0].in === "body" && inBody[0].name === "body";
1258
- methodApis.push({
1259
- method,
1260
- operationId,
1261
- summary: summary_,
1262
- deprecated,
1263
- description: description_,
1264
- parameters: uniqueParameterName.map((name) => notInBody.find((p) => p.name === name)).filter(Boolean),
1265
- responses: responseSchema,
1266
- requestBody: inBody.length > 0 ? inBodyOnlyHasBody ? [{
1267
- type: "application/json",
1268
- schema: inBody[0].schema
1269
- }] : [{
1270
- type: "application/json",
1271
- schema: {
1272
- type: "object",
1273
- properties: inBody.reduce((a, p) => {
1274
- return {
1275
- ...a,
1276
- [p.name]: {
1277
- type: p.schema?.type ?? "unknown",
1278
- required: p.schema?.required,
1279
- items: p.schema?.items,
1280
- description: p.schema?.description
1281
- }
1282
- };
1283
- }, {})
1284
- }
1285
- }] : void 0
1286
- });
1287
- break;
1288
- }
1289
- }
1290
- });
1291
- return {
1292
- ...acc,
1293
- [path]: methodApis
1294
- };
1295
- }, {});
1296
- return {
1297
- enums: Base.uniqueEnums(enums),
1298
- schemas: definitions_,
1299
- responses: responses_,
1300
- parameters: {},
1301
- requestBodies: {},
1302
- apis
1303
- };
1304
- }
1305
- };
1306
- //#endregion
1307
- //#region src/openapi/V3.ts
1308
- var V3 = class {
1309
- doc;
1310
- constructor(doc) {
1311
- this.doc = doc;
1312
- }
1313
- /**
1314
- * Resolves a path $ref to the actual path object.
1315
- */
1316
- resolvePathRef($ref) {
1317
- const refName = Base.ref2name($ref, this.doc);
1318
- return this.doc.paths?.[refName];
1319
- }
1320
- /**
1321
- * Is array schema.
1322
- */
1323
- isOpenAPIArraySchema(schema) {
1324
- return typeof schema === "object" && schema.type === "array";
1325
- }
1326
- /**
1327
- * OpenAPI schema to base schema.
1190
+ * Format a ref name for the schema's `type` field.
1191
+ * V3 uses `capitalize`; V3_1 uses `upperCamelCase` (preserved for compat).
1328
1192
  */
1329
- getSchemaByRef(schema, reserveRef = false, enums = [], upLevelSchemaKey = "") {
1330
- let refName = "";
1331
- if (Base.isRef(schema)) {
1332
- refName = Base.capitalize(Base.ref2name(schema.$ref));
1333
- if (reserveRef) return { type: upLevelSchemaKey + refName };
1334
- const resolvedSchema = this.doc.components?.schemas?.[Base.ref2name(schema.$ref, this.doc)];
1335
- if (!resolvedSchema) return { type: "unknown" };
1336
- schema = resolvedSchema;
1337
- }
1338
- return this.toBaseSchema(schema, enums, "", upLevelSchemaKey + refName);
1193
+ formatRefName(name) {
1194
+ return Base.capitalize(name);
1339
1195
  }
1340
1196
  /**
1341
- * OpenAPI parameter to base parameter.
1197
+ * OpenAPI parameter to base parameter. Override in V2 — its parameter
1198
+ * shape is structurally different (top-level `items`/`properties`/`enum`).
1342
1199
  */
1343
1200
  getParameterByRef(schema, enums = [], upLevelSchemaKey = "") {
1344
1201
  if (Base.isRef(schema)) {
1345
- const resolvedSchema = this.doc.components?.parameters?.[Base.ref2name(schema.$ref, this.doc)];
1202
+ const resolvedSchema = this.getParameterContainer()?.[Base.ref2name(schema.$ref, this.doc)];
1346
1203
  if (!resolvedSchema) return {
1347
1204
  name: "unknown",
1348
1205
  in: "query"
@@ -1373,37 +1230,38 @@ var V3 = class {
1373
1230
  description,
1374
1231
  deprecated,
1375
1232
  in: schema.in,
1376
- schema: schema.schema && this.getSchemaByRef(schema.schema, false, enums, upLevelSchemaKey + Base.capitalize(name))
1233
+ schema: schema.schema ? this.getSchemaByRef(schema.schema, false, enums, upLevelSchemaKey + Base.capitalize(name)) : void 0
1377
1234
  };
1378
1235
  }
1379
1236
  /**
1380
- * OpenAPI schema to base response
1237
+ * OpenAPI schema to base response. Override in V2 (its response shape
1238
+ * lacks the `content` wrapper).
1381
1239
  */
1382
1240
  getResponseByRef(schema) {
1383
1241
  if (Base.isRef(schema)) {
1384
- const resolvedSchema = this.doc.components?.responses?.[Base.ref2name(schema.$ref, this.doc)];
1242
+ const resolvedSchema = this.getResponseContainer()?.[Base.ref2name(schema.$ref, this.doc)];
1385
1243
  if (!resolvedSchema) return [];
1386
1244
  schema = resolvedSchema;
1387
1245
  }
1388
1246
  const { content = {} } = schema;
1389
1247
  return Object.keys(content).map((c) => ({
1390
1248
  type: c,
1391
- schema: content[c].schema && this.getSchemaByRef(content[c].schema, true)
1249
+ schema: content[c].schema ? this.getSchemaByRef(content[c].schema, true) : void 0
1392
1250
  }));
1393
1251
  }
1394
1252
  /**
1395
- * OpenAPI schema to requestBody.
1253
+ * OpenAPI schema to requestBody. V2 has no requestBody concept.
1396
1254
  */
1397
1255
  getRequestBodyByRef(schema, enums = []) {
1398
1256
  if (Base.isRef(schema)) {
1399
- const resolvedSchema = this.doc.components?.requestBodies?.[Base.ref2name(schema.$ref, this.doc)];
1257
+ const resolvedSchema = this.getRequestBodyContainer()?.[Base.ref2name(schema.$ref, this.doc)];
1400
1258
  if (!resolvedSchema) return [];
1401
1259
  schema = resolvedSchema;
1402
1260
  }
1403
1261
  const { content = {} } = schema;
1404
1262
  return Object.keys(content).map((c) => ({
1405
1263
  type: c,
1406
- schema: content[c].schema && this.getSchemaByRef(content[c].schema, false, enums)
1264
+ schema: content[c].schema ? this.getSchemaByRef(content[c].schema, false, enums) : void 0
1407
1265
  }));
1408
1266
  }
1409
1267
  /**
@@ -1414,89 +1272,98 @@ var V3 = class {
1414
1272
  if (Base.isRef(schema)) return this.getSchemaByRef(schema, true);
1415
1273
  if (this.isOpenAPIArraySchema(schema)) {
1416
1274
  const { type, description, items, required } = schema;
1275
+ const itemsSchema = items ? this.toBaseSchema(items, enums, schemaKey, upLevelSchemaKey) : { type: "unknown" };
1417
1276
  return {
1418
1277
  type,
1419
1278
  required: !!required,
1420
1279
  description,
1421
- items: this.toBaseSchema(items, enums, schemaKey, upLevelSchemaKey)
1280
+ items: itemsSchema
1422
1281
  };
1423
- } else {
1424
- const { required = [], allOf, anyOf, description, deprecated, enum: enum_, format, oneOf, properties = {} } = schema;
1425
- let { type } = schema;
1426
- if (enum_ && type !== "boolean") {
1427
- const enumObject = {
1428
- name: Base.upperCamelCase(Base.normalize(upLevelSchemaKey)) + Base.upperCamelCase(Base.normalize(schemaKey)),
1429
- enum: [...new Set(enum_)]
1430
- };
1431
- const sameObject = Base.findSameSchema(enumObject, enums);
1432
- if (!sameObject && Base.isValidEnumType(schema)) enums.push(enumObject);
1433
- return {
1434
- type: sameObject ? sameObject.name : Base.isBooleanEnum(schema) ? "boolean" : enumObject.name,
1435
- required,
1436
- description,
1437
- deprecated
1438
- };
1439
- }
1440
- if (type === void 0 && Object.keys(properties).length > 0) type = "object";
1282
+ }
1283
+ const { required = [], allOf, anyOf, description, deprecated, enum: enum_, format, oneOf, properties = {} } = schema;
1284
+ let { type } = schema;
1285
+ if (enum_ && type !== "boolean") {
1286
+ const enumObject = {
1287
+ name: Base.upperCamelCase(Base.normalize(upLevelSchemaKey)) + Base.upperCamelCase(Base.normalize(schemaKey)),
1288
+ enum: [...new Set(enum_)]
1289
+ };
1290
+ const sameObject = Base.findSameSchema(enumObject, enums);
1291
+ if (!sameObject && Base.isValidEnumType(schema)) enums.push(enumObject);
1441
1292
  return {
1442
- type,
1293
+ type: sameObject ? sameObject.name : Base.isBooleanEnum(schema) ? "boolean" : enumObject.name,
1443
1294
  required,
1444
1295
  description,
1445
- deprecated,
1446
- enum: enum_,
1447
- format,
1448
- allOf: allOf?.map((s) => Base.isRef(s) ? {
1449
- ...s,
1450
- ref: s.$ref,
1451
- type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1452
- } : this.toBaseSchema(s, enums)),
1453
- anyOf: anyOf?.map((s) => Base.isRef(s) ? {
1454
- ...s,
1455
- ref: s.$ref,
1456
- type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1457
- } : this.toBaseSchema(s, enums)),
1458
- oneOf: oneOf?.map((s) => Base.isRef(s) ? {
1459
- ...s,
1460
- ref: s.$ref,
1461
- type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1462
- } : this.toBaseSchema(s, enums)),
1463
- properties: Object.keys(properties).reduce((acc, p) => {
1464
- const propSchema = properties[p];
1465
- return {
1466
- ...acc,
1467
- [p]: Base.isRef(propSchema) ? { type: Base.capitalize(Base.ref2name(propSchema.$ref, this.doc)) } : this.toBaseSchema(propSchema, enums, p, upLevelSchemaKey)
1468
- };
1469
- }, {})
1296
+ deprecated
1470
1297
  };
1471
1298
  }
1299
+ if (type === void 0 && Object.keys(properties).length > 0) type = "object";
1300
+ return {
1301
+ type,
1302
+ required,
1303
+ description,
1304
+ deprecated,
1305
+ enum: enum_,
1306
+ format,
1307
+ allOf: allOf?.map((s) => Base.isRef(s) ? {
1308
+ ...s,
1309
+ ref: s.$ref,
1310
+ type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1311
+ } : this.toBaseSchema(s, enums)),
1312
+ anyOf: anyOf?.map((s) => Base.isRef(s) ? {
1313
+ ...s,
1314
+ ref: s.$ref,
1315
+ type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1316
+ } : this.toBaseSchema(s, enums)),
1317
+ oneOf: oneOf?.map((s) => Base.isRef(s) ? {
1318
+ ...s,
1319
+ ref: s.$ref,
1320
+ type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1321
+ } : this.toBaseSchema(s, enums)),
1322
+ properties: Object.keys(properties).reduce((acc, p) => {
1323
+ const propSchema = properties[p];
1324
+ return {
1325
+ ...acc,
1326
+ [p]: Base.isRef(propSchema) ? {
1327
+ type: Base.capitalize(Base.ref2name(propSchema.$ref, this.doc)),
1328
+ isRef: true
1329
+ } : this.toBaseSchema(propSchema, enums, p, upLevelSchemaKey)
1330
+ };
1331
+ }, {})
1332
+ };
1472
1333
  }
1334
+ /**
1335
+ * Run the parsing pipeline and return a ProviderInitResult.
1336
+ */
1473
1337
  init() {
1474
- const { components = {}, paths = {} } = this.doc;
1338
+ const { paths = {} } = this.doc;
1475
1339
  const enums = [];
1476
- const { requestBodies = {}, responses = {}, parameters = {}, schemas = {} } = components;
1477
- const schemas_ = Object.keys(schemas).reduce((acc, key) => {
1478
- const schema = schemas[key];
1340
+ const schemaContainer = this.getSchemaContainer() ?? {};
1341
+ const parameterContainer = this.getParameterContainer() ?? {};
1342
+ const responseContainer = this.getResponseContainer() ?? {};
1343
+ const requestBodyContainer = this.getRequestBodyContainer() ?? {};
1344
+ const schemas_ = Object.keys(schemaContainer).reduce((acc, key) => {
1345
+ const schema = schemaContainer[key];
1479
1346
  return {
1480
1347
  ...acc,
1481
1348
  [key]: this.getSchemaByRef(schema, false, enums, key)
1482
1349
  };
1483
1350
  }, {});
1484
- const parameters_ = Object.keys(parameters).reduce((acc, key) => {
1485
- const parameter = parameters[key];
1351
+ const parameters_ = Object.keys(parameterContainer).reduce((acc, key) => {
1352
+ const parameter = parameterContainer[key];
1486
1353
  return {
1487
1354
  ...acc,
1488
1355
  [key]: this.getParameterByRef(parameter, enums, key)
1489
1356
  };
1490
1357
  }, {});
1491
- const responses_ = Object.keys(responses).reduce((acc, key) => {
1492
- const response = responses[key];
1358
+ const responses_ = Object.keys(responseContainer).reduce((acc, key) => {
1359
+ const response = responseContainer[key];
1493
1360
  return {
1494
1361
  ...acc,
1495
1362
  [key]: this.getResponseByRef(response)
1496
1363
  };
1497
1364
  }, {});
1498
- const requestBodies_ = Object.keys(requestBodies).reduce((acc, key) => {
1499
- const requestBody = requestBodies[key];
1365
+ const requestBodies_ = Object.keys(requestBodyContainer).reduce((acc, key) => {
1366
+ const requestBody = requestBodyContainer[key];
1500
1367
  return {
1501
1368
  ...acc,
1502
1369
  [key]: this.getRequestBodyByRef(requestBody, enums)
@@ -1513,15 +1380,16 @@ var V3 = class {
1513
1380
  Object.values(HttpMethods).forEach((method) => {
1514
1381
  const methodObject = pathObject[method];
1515
1382
  if (methodObject) {
1516
- const { deprecated, operationId, responses = {}, summary: summary_, description: description_, requestBody = { content: {} } } = methodObject;
1383
+ const { deprecated, operationId, responses, summary: summary_, description: description_, requestBody = { content: {} } } = methodObject;
1384
+ const responsesClone = responses ? { ...responses } : {};
1517
1385
  const { parameters: parameters_ = [] } = methodObject;
1518
1386
  const baseParameters = [...parameters, ...parameters_].map((parameter) => this.getParameterByRef(parameter, enums));
1519
1387
  const baseRequestBody = this.getRequestBodyByRef(requestBody, enums);
1520
1388
  const uniqueParameterName = [...new Set(baseParameters.map((p) => p.name))];
1521
- if (Object.keys(responses).length === 0) Object.assign(responses, { 200: { description: "Successful response" } });
1522
- const httpCodes = Object.keys(responses);
1523
- for (const code of httpCodes) if (code in responses) {
1524
- const response = responses[code];
1389
+ if (Object.keys(responsesClone).length === 0) responsesClone[200] = { description: "Successful response" };
1390
+ const httpCodes = Object.keys(responsesClone);
1391
+ for (const code of httpCodes) if (code in responsesClone) {
1392
+ const response = responsesClone[code];
1525
1393
  const responseSchema = this.getResponseByRef(response);
1526
1394
  methodApis.push({
1527
1395
  method,
@@ -1553,243 +1421,248 @@ var V3 = class {
1553
1421
  }
1554
1422
  };
1555
1423
  //#endregion
1556
- //#region src/openapi/V3_1.ts
1557
- var V3_1 = class {
1424
+ //#region src/openapi/V2.ts
1425
+ var V2 = class extends VersionedProvider {
1558
1426
  doc;
1427
+ version = "v2";
1559
1428
  constructor(doc) {
1429
+ super();
1560
1430
  this.doc = doc;
1561
1431
  }
1562
- /**
1563
- * Resolves a path $ref to the actual path object.
1564
- */
1565
- resolvePathRef($ref) {
1566
- const refName = Base.ref2name($ref, this.doc);
1567
- return this.doc.paths?.[refName];
1432
+ getSchemaContainer() {
1433
+ return this.doc.definitions;
1568
1434
  }
1569
- /**
1570
- * Is array schema.
1571
- */
1572
- isOpenAPIArraySchema(schema) {
1573
- return typeof schema === "object" && schema.type === "array";
1435
+ getParameterContainer() {
1436
+ return this.doc.parameters;
1574
1437
  }
1575
- /**
1576
- * OpenAPI schema to base schema.
1577
- */
1578
- getSchemaByRef(schema, reserveRef = false, enums = [], upLevelSchemaKey = "") {
1579
- let refName = "";
1580
- if (Base.isRef(schema)) {
1581
- refName = Base.upperCamelCase(Base.ref2name(schema.$ref));
1582
- if (reserveRef) return { type: upLevelSchemaKey + refName };
1583
- if (!this.doc.components) this.doc.components = { schemas: {} };
1584
- const resolvedSchema = this.doc.components.schemas?.[Base.ref2name(schema.$ref, this.doc)];
1585
- if (!resolvedSchema) throw new Error(`Schema reference not found: ${refName}`);
1586
- schema = resolvedSchema;
1587
- }
1588
- return this.toBaseSchema(schema, enums, "", upLevelSchemaKey + refName);
1438
+ getResponseContainer() {
1439
+ return this.doc.responses;
1589
1440
  }
1441
+ getRequestBodyContainer() {}
1590
1442
  /**
1591
- * OpenAPI parameter to base parameter.
1443
+ * V2 parameter shape differs from V3: top-level `items`/`properties`/`enum`
1444
+ * rather than nested under `schema`. Override accordingly.
1592
1445
  */
1593
- getParameterByRef(schema, enums = [], upLevelSchemaKey = "") {
1594
- if (Base.isRef(schema)) schema = this.doc.components?.parameters?.[Base.ref2name(schema.$ref, this.doc)];
1595
- const { name, required, deprecated, description, schema: parameterSchema } = schema;
1596
- if (parameterSchema && !Base.isRef(parameterSchema) && parameterSchema.enum) {
1597
- const type = Base.upperCamelCase(Base.normalize(upLevelSchemaKey)) + Base.upperCamelCase(Base.normalize(name));
1446
+ getParameterByRef(parameter, enums = [], upLevelSchemaKey = "") {
1447
+ if (Base.isRef(parameter)) {
1448
+ const refName = Base.ref2name(parameter.$ref, this.doc);
1449
+ const resolved = this.doc.parameters?.[refName];
1450
+ if (!resolved) throw new Error(`Parameter reference not found: ${parameter.$ref}`);
1451
+ parameter = resolved;
1452
+ }
1453
+ const p = parameter;
1454
+ const { name, required, description, type, items, enum: enum_, properties, schema } = p;
1455
+ if (enum_) {
1456
+ const enumType = Base.upperCamelCase(Base.normalize(upLevelSchemaKey)) + Base.upperCamelCase(Base.normalize(name));
1598
1457
  const enumSchema = {
1599
- name: type,
1600
- enum: [...new Set(parameterSchema.enum)]
1458
+ name: enumType,
1459
+ enum: [...new Set(enum_)]
1601
1460
  };
1602
1461
  const sameEnum = Base.findSameSchema(enumSchema, enums);
1603
- if (!sameEnum && Base.isValidEnumType(parameterSchema)) enums.push(enumSchema);
1462
+ if (!sameEnum && Base.isValidEnumType({
1463
+ type: enumType,
1464
+ enum: enum_
1465
+ })) enums.push(enumSchema);
1604
1466
  return {
1605
1467
  name,
1606
1468
  required,
1607
1469
  description,
1608
- deprecated,
1609
- in: schema.in,
1610
- schema: { type: sameEnum?.name ?? type }
1470
+ in: p.in,
1471
+ schema: { type: sameEnum?.name ?? enumType }
1611
1472
  };
1612
1473
  }
1474
+ if (items) return {
1475
+ name,
1476
+ required,
1477
+ description,
1478
+ in: p.in,
1479
+ schema: {
1480
+ type,
1481
+ items
1482
+ }
1483
+ };
1484
+ if (schema && Base.isRef(schema)) return {
1485
+ name,
1486
+ required,
1487
+ description,
1488
+ in: p.in,
1489
+ schema: { type: Base.capitalize(Base.ref2name(schema.$ref)) }
1490
+ };
1613
1491
  return {
1614
1492
  name,
1615
1493
  required,
1616
1494
  description,
1617
- deprecated,
1618
- in: schema.in,
1619
- schema: schema.schema && this.getSchemaByRef(schema.schema, false, enums, upLevelSchemaKey + Base.capitalize(name))
1495
+ in: p.in,
1496
+ schema: {
1497
+ type,
1498
+ properties
1499
+ }
1620
1500
  };
1621
1501
  }
1622
1502
  /**
1623
- * OpenAPI schema to base response
1503
+ * V2 response shape: a `schema` field directly, not `content`. V2 always
1504
+ * emits JSON.
1624
1505
  */
1625
1506
  getResponseByRef(schema) {
1626
- if (Base.isRef(schema)) schema = this.doc.components?.responses?.[Base.ref2name(schema.$ref, this.doc)];
1627
- const { content = {} } = schema;
1628
- return Object.keys(content).map((c) => ({
1629
- type: c,
1630
- schema: content[c].schema && this.getSchemaByRef(content[c].schema, true)
1631
- }));
1632
- }
1633
- /**
1634
- * OpenAPI schema to requestBody.
1635
- */
1636
- getRequestBodyByRef(schema, enums = []) {
1637
- if (Base.isRef(schema)) schema = this.doc.components?.requestBodies?.[Base.ref2name(schema.$ref, this.doc)];
1638
- const { content = {} } = schema;
1639
- return Object.keys(content).map((c) => ({
1640
- type: c,
1641
- schema: content[c].schema && this.getSchemaByRef(content[c].schema, true, enums)
1642
- }));
1507
+ if (Base.isRef(schema)) schema = this.doc.responses[Base.ref2name(schema.$ref, this.doc)];
1508
+ const { schema: responseSchema } = schema;
1509
+ return [{
1510
+ type: "application/json",
1511
+ schema: responseSchema ? this.getSchemaByRef(responseSchema, true) : void 0
1512
+ }];
1643
1513
  }
1644
1514
  /**
1645
- * Transform all OpenAPI schema to Base Schema
1515
+ * V2 has no `requestBody` concept; parameters with `in: body` or
1516
+ * `in: formData` are split out and turned into a synthetic requestBody
1517
+ * here. A single body param named `body` is used directly; otherwise
1518
+ * the body / formData params are wrapped in a synthetic object.
1646
1519
  */
1647
- toBaseSchema(schema, enums = [], schemaKey = "", upLevelSchemaKey = "") {
1648
- if (!schema) return { type: "unknown" };
1649
- if (Base.isRef(schema)) return this.getSchemaByRef(schema, true);
1650
- if (this.isOpenAPIArraySchema(schema)) {
1651
- const { type, description, items, required } = schema;
1652
- return {
1653
- type,
1654
- required: !!required,
1655
- description,
1656
- items: this.toBaseSchema(items, enums, schemaKey, upLevelSchemaKey)
1657
- };
1658
- } else {
1659
- const { required = [], allOf, anyOf, description, deprecated, enum: enum_, format, oneOf, properties = {} } = schema;
1660
- let { type } = schema;
1661
- if (enum_ && type !== "boolean") {
1662
- const enumObject = {
1663
- name: Base.upperCamelCase(Base.normalize(upLevelSchemaKey)) + Base.upperCamelCase(Base.normalize(schemaKey)),
1664
- enum: [...new Set(enum_)]
1665
- };
1666
- const sameObject = Base.findSameSchema(enumObject, enums);
1667
- if (!sameObject && Base.isValidEnumType(schema)) enums.push(enumObject);
1668
- return {
1669
- type: sameObject ? sameObject.name : Base.isBooleanEnum(schema) ? "boolean" : enumObject.name,
1670
- required,
1671
- description,
1672
- deprecated
1673
- };
1674
- }
1675
- if (type === void 0 && Object.keys(properties).length > 0) type = "object";
1676
- return {
1677
- type,
1678
- required,
1679
- description,
1680
- deprecated,
1681
- enum: enum_,
1682
- format,
1683
- allOf: allOf?.map((s) => Base.isRef(s) ? {
1684
- ...s,
1685
- ref: s.$ref,
1686
- type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1687
- } : this.toBaseSchema(s, enums)),
1688
- anyOf: anyOf?.map((s) => Base.isRef(s) ? {
1689
- ...s,
1690
- ref: s.$ref,
1691
- type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1692
- } : this.toBaseSchema(s, enums)),
1693
- oneOf: oneOf?.map((s) => Base.isRef(s) ? {
1694
- ...s,
1695
- ref: s.$ref,
1696
- type: Base.capitalize(Base.ref2name(s.$ref, this.doc))
1697
- } : this.toBaseSchema(s, enums)),
1698
- properties: Object.keys(properties).reduce((acc, p) => {
1699
- const propSchema = properties[p];
1700
- return {
1701
- ...acc,
1702
- [p]: Base.isRef(propSchema) ? { type: Base.capitalize(Base.ref2name(propSchema.$ref, this.doc)) } : this.toBaseSchema(propSchema, enums, p, upLevelSchemaKey)
1703
- };
1704
- }, {})
1705
- };
1706
- }
1707
- }
1708
1520
  init() {
1709
- const { components = {}, paths = {} } = this.doc;
1521
+ const { paths = {} } = this.doc;
1710
1522
  const enums = [];
1711
- const { requestBodies = {}, responses = {}, parameters = {}, schemas = {} } = components;
1712
- const schemas_ = Object.keys(schemas).reduce((acc, key) => {
1713
- const schema = schemas[key];
1523
+ const schemaContainer = this.getSchemaContainer() ?? {};
1524
+ const parameterContainer = this.getParameterContainer() ?? {};
1525
+ const responseContainer = this.getResponseContainer() ?? {};
1526
+ const schemas_ = Object.keys(schemaContainer).reduce((acc, key) => {
1527
+ const schema = schemaContainer[key];
1714
1528
  return {
1715
1529
  ...acc,
1716
1530
  [key]: this.getSchemaByRef(schema, false, enums, key)
1717
1531
  };
1718
1532
  }, {});
1719
- const parameters_ = Object.keys(parameters).reduce((acc, key) => {
1720
- const parameter = parameters[key];
1533
+ const parameters_ = Object.keys(parameterContainer).reduce((acc, key) => {
1534
+ const parameter = parameterContainer[key];
1721
1535
  return {
1722
1536
  ...acc,
1723
1537
  [key]: this.getParameterByRef(parameter, enums, key)
1724
1538
  };
1725
1539
  }, {});
1726
- const responses_ = Object.keys(responses).reduce((acc, key) => {
1727
- const response = responses[key];
1540
+ const responses_ = Object.keys(responseContainer).reduce((acc, key) => {
1541
+ const response = responseContainer[key];
1728
1542
  return {
1729
1543
  ...acc,
1730
1544
  [key]: this.getResponseByRef(response)
1731
1545
  };
1732
1546
  }, {});
1733
- const requestBodies_ = Object.keys(requestBodies).reduce((acc, key) => {
1734
- const requestBody = requestBodies[key];
1735
- return {
1736
- ...acc,
1737
- [key]: this.getRequestBodyByRef(requestBody, enums)
1738
- };
1739
- }, {});
1740
- const apis = Object.keys(paths).reduce((acc, path) => {
1547
+ const apis = {};
1548
+ for (const path of Object.keys(paths)) {
1741
1549
  let pathObject = paths[path] ?? {};
1742
1550
  if (pathObject.$ref) {
1743
1551
  const resolved = this.resolvePathRef(pathObject.$ref);
1744
1552
  if (resolved) pathObject = resolved;
1745
1553
  }
1746
- const { parameters = [], description, summary } = pathObject;
1554
+ const { parameters = [] } = pathObject;
1747
1555
  const methodApis = [];
1748
1556
  Object.values(HttpMethods).forEach((method) => {
1749
1557
  const methodObject = pathObject[method];
1750
- if (methodObject) {
1751
- const { deprecated, operationId, summary: summary_, description: description_, responses = {}, requestBody = { content: {} } } = methodObject;
1752
- const { parameters: parameters_ = [] } = methodObject;
1753
- const baseParameters = [...parameters, ...parameters_].map((parameter) => this.getParameterByRef(parameter, enums));
1754
- const baseRequestBody = this.getRequestBodyByRef(requestBody, enums);
1755
- const uniqueParameterName = [...new Set(baseParameters.map((p) => p.name))];
1756
- if (Object.keys(responses).length === 0) Object.assign(responses, { 200: { description: "Successful response" } });
1757
- const httpCodes = Object.keys(responses);
1758
- for (const code of httpCodes) if (code in responses) {
1759
- const response = responses[code];
1760
- const responseSchema = this.getResponseByRef(response);
1761
- methodApis.push({
1762
- method,
1763
- operationId,
1764
- summary: summary_ ?? summary,
1765
- description: description_ ?? description,
1766
- deprecated,
1767
- parameters: uniqueParameterName.map((name) => baseParameters.find((p) => p.name === name)).filter((p) => p !== void 0),
1768
- responses: responseSchema,
1769
- requestBody: baseRequestBody
1770
- });
1771
- break;
1772
- }
1558
+ if (!methodObject) return;
1559
+ const { deprecated, operationId, summary: summary_, description: description_, responses } = methodObject;
1560
+ const { parameters: parameters_ = [] } = methodObject;
1561
+ const baseParameters = [...parameters, ...parameters_].map((p) => this.getParameterByRef(p, enums));
1562
+ const uniqueParameterName = [...new Set(baseParameters.map((p) => p.name))];
1563
+ const responsesClone = responses ? { ...responses } : {};
1564
+ if (Object.keys(responsesClone).length === 0) responsesClone[200] = { description: "Successful response" };
1565
+ const inBody = baseParameters.filter((p) => p.in === "body" || p.in === "formData");
1566
+ const notInBody = baseParameters.filter((p) => p.in !== "body" && p.in !== "formData");
1567
+ const httpCodes = Object.keys(responsesClone);
1568
+ for (const code of httpCodes) if (code in responsesClone) {
1569
+ const response = responsesClone[code];
1570
+ const responseSchema = this.getResponseByRef(response);
1571
+ const inBodyOnlyHasBody = inBody.length === 1 && inBody[0].in === "body" && inBody[0].name === "body";
1572
+ methodApis.push({
1573
+ method,
1574
+ operationId,
1575
+ summary: summary_,
1576
+ deprecated,
1577
+ description: description_,
1578
+ parameters: uniqueParameterName.map((name) => notInBody.find((p) => p.name === name)).filter((p) => p !== void 0),
1579
+ responses: responseSchema,
1580
+ requestBody: inBody.length > 0 ? inBodyOnlyHasBody ? [{
1581
+ type: "application/json",
1582
+ schema: inBody[0].schema
1583
+ }] : [{
1584
+ type: "application/json",
1585
+ schema: {
1586
+ type: "object",
1587
+ properties: inBody.reduce((a, p) => {
1588
+ return {
1589
+ ...a,
1590
+ [p.name]: {
1591
+ type: p.schema?.type ?? "unknown",
1592
+ required: p.schema?.required,
1593
+ items: p.schema?.items,
1594
+ description: p.schema?.description
1595
+ }
1596
+ };
1597
+ }, {})
1598
+ }
1599
+ }] : void 0
1600
+ });
1601
+ break;
1773
1602
  }
1774
1603
  });
1775
- return {
1776
- ...acc,
1777
- [path]: methodApis
1778
- };
1779
- }, {});
1604
+ apis[path] = methodApis;
1605
+ }
1780
1606
  return {
1781
1607
  enums: Base.uniqueEnums(enums),
1782
1608
  schemas: schemas_,
1783
1609
  responses: responses_,
1784
1610
  parameters: parameters_,
1785
- requestBodies: requestBodies_,
1611
+ requestBodies: {},
1786
1612
  apis
1787
1613
  };
1788
1614
  }
1789
1615
  };
1790
1616
  //#endregion
1617
+ //#region src/openapi/V3.ts
1618
+ var V3 = class extends VersionedProvider {
1619
+ doc;
1620
+ version = "v3";
1621
+ constructor(doc) {
1622
+ super();
1623
+ this.doc = doc;
1624
+ }
1625
+ getSchemaContainer() {
1626
+ return this.doc.components?.schemas;
1627
+ }
1628
+ getParameterContainer() {
1629
+ return this.doc.components?.parameters;
1630
+ }
1631
+ getResponseContainer() {
1632
+ return this.doc.components?.responses;
1633
+ }
1634
+ getRequestBodyContainer() {
1635
+ return this.doc.components?.requestBodies;
1636
+ }
1637
+ };
1638
+ //#endregion
1639
+ //#region src/openapi/V3_1.ts
1640
+ var V3_1 = class extends VersionedProvider {
1641
+ doc;
1642
+ version = "v3_1";
1643
+ constructor(doc) {
1644
+ super();
1645
+ this.doc = doc;
1646
+ }
1647
+ formatRefName(name) {
1648
+ return Base.upperCamelCase(name);
1649
+ }
1650
+ getSchemaContainer() {
1651
+ return this.doc.components?.schemas;
1652
+ }
1653
+ getParameterContainer() {
1654
+ return this.doc.components?.parameters;
1655
+ }
1656
+ getResponseContainer() {
1657
+ return this.doc.components?.responses;
1658
+ }
1659
+ getRequestBodyContainer() {
1660
+ return this.doc.components?.requestBodies;
1661
+ }
1662
+ };
1663
+ //#endregion
1791
1664
  //#region src/openapi/index.ts
1792
- const logger$1 = createScopedLogger("OpenAPI");
1665
+ const logger = createScopedLogger("OpenAPI");
1793
1666
  function getDocVersion(doc) {
1794
1667
  switch ((doc.openapi || doc.swagger).slice(0, 3)) {
1795
1668
  case "3.1": return "v3_1";
@@ -1801,7 +1674,7 @@ function getDocVersion(doc) {
1801
1674
  var OpenAPIProvider = class extends Provider {
1802
1675
  parse(doc) {
1803
1676
  const version = getDocVersion(doc);
1804
- logger$1.debug(`openapi version ${version}`);
1677
+ logger.debug(`openapi version ${version}`);
1805
1678
  switch (version) {
1806
1679
  case "v2": return new V2(doc).init();
1807
1680
  case "v3": return new V3(doc).init();
@@ -1819,9 +1692,9 @@ function getAdaptor(type) {
1819
1692
  async function codeGen(initOptions) {
1820
1693
  const startTime = Date.now();
1821
1694
  const { verbose } = initOptions;
1822
- if (verbose) logger$1.setLevel("debug");
1823
- else logger$1.setLevel("info");
1824
- logger$1.info(`Fetch document from ${initOptions.docURL}`);
1695
+ if (verbose) logger.setLevel("debug");
1696
+ else logger.setLevel("info");
1697
+ logger.info(`Fetch document from ${initOptions.docURL}`);
1825
1698
  const { enums, schemas, parameters, responses, requestBodies, apis } = new OpenAPIProvider(initOptions, await Base.fetchDoc(initOptions.docURL, initOptions.requestOptions));
1826
1699
  const adaptor = getAdaptor(initOptions.adaptor ?? "fetch");
1827
1700
  const code = await Generator.genCode({
@@ -1846,7 +1719,7 @@ async function codeGen(initOptions) {
1846
1719
  //#endregion
1847
1720
  //#region src/vite-plugin/index.ts
1848
1721
  const PLUGIN_NAME = "api-code-gen";
1849
- const logger = createScopedLogger("api-code-gen");
1722
+ const pluginLogger = createScopedLogger("api-code-gen");
1850
1723
  /**
1851
1724
  * Run TypeScript type checking on generated file
1852
1725
  */
@@ -1875,7 +1748,7 @@ async function validateSpecPath(specPath) {
1875
1748
  async function generateForOption(option) {
1876
1749
  const { name, typeCheck = true, verbose, ...restOptions } = option;
1877
1750
  try {
1878
- console.log(`\x1b[36m├─\x1b[0m ${name}`);
1751
+ logger$1.info(`Generating ${name}...`);
1879
1752
  const config = await loadConfig({
1880
1753
  name,
1881
1754
  cliOptions: {
@@ -1899,8 +1772,8 @@ async function generateForOption(option) {
1899
1772
  if (typeCheck && config.output) {
1900
1773
  const typeErrors = await runTypeCheck(config.output);
1901
1774
  if (typeErrors.length > 0) {
1902
- logger.warn(`Type check failed for ${config.output}`);
1903
- if (verbose) for (const error of typeErrors) logger.warn(` ${error}`);
1775
+ pluginLogger.warn(`Type check failed for ${config.output}`);
1776
+ if (verbose) for (const error of typeErrors) pluginLogger.warn(` ${error}`);
1904
1777
  }
1905
1778
  }
1906
1779
  return {
@@ -1941,45 +1814,47 @@ async function generateForOption(option) {
1941
1814
  */
1942
1815
  function apiCodeGenPlugin(options) {
1943
1816
  if (!Array.isArray(options) || options.length === 0) {
1944
- logger.warn("No API configurations provided to apiCodeGenPlugin");
1817
+ pluginLogger.warn("No API configurations provided to apiCodeGenPlugin");
1945
1818
  return { name: PLUGIN_NAME };
1946
1819
  }
1947
1820
  return {
1948
1821
  name: PLUGIN_NAME,
1949
1822
  async config(_config, env) {
1950
- console.log(`\x1b[1m\x1b[36m${"".repeat(50)}\x1b[0m`);
1951
- console.log(`\x1b[1m\x1b[36mAPI Code Gen\x1b[0m`);
1952
- console.log(`\x1b[90mMode:\x1b[0m ${env?.command || "unknown"}`);
1953
- console.log(`\x1b[1m\x1b[36m${"─".repeat(50)}\x1b[0m`);
1823
+ logger$1.heading("API Code Gen", env?.command);
1954
1824
  const results = await Promise.all(options.map(generateForOption));
1955
1825
  const successCount = results.filter((r) => r.success).length;
1956
1826
  const failCount = options.length - successCount;
1957
- console.log(`\x1b[1m\x1b[36m${"─".repeat(50)}\x1b[0m`);
1827
+ logger$1.divider();
1958
1828
  for (const result of results) if (result.success) {
1959
1829
  const { name, output, stats } = result;
1960
- if (stats) console.log(`\x1b[32m✓\x1b[0m ${name} → ${output} (${stats.endpoints} endpoints, ${stats.schemas} schemas) ${stats.duration}ms`);
1961
- else console.log(`\x1b[32m✓\x1b[0m ${name} → ${output || "N/A"}`);
1830
+ if (stats) logger$1.item(`${name} → ${output} (${stats.endpoints} endpoints, ${stats.schemas} schemas) ${stats.duration}ms`, "green");
1831
+ else logger$1.item(`${name} → ${output || "N/A"}`, "green");
1962
1832
  } else {
1963
1833
  const { name, error } = result;
1964
1834
  if (isApicodegenError(error)) {
1965
- console.log(`\x1b[31m✗\x1b[0m ${name}`);
1966
- console.log(`\x1b[90m${formatError(error, true)}\x1b[0m`);
1835
+ logger$1.item(name, "red");
1836
+ logger$1.error(error, true);
1967
1837
  } else {
1968
1838
  const wrapped = wrapError(error, {
1969
- code: "E_GENERATION_FAILED",
1839
+ code: ErrorCodes.GENERATION_FAILED,
1970
1840
  message: `Failed to generate API "${name}"`
1971
1841
  });
1972
- console.log(`\x1b[31m✗\x1b[0m ${name}`);
1973
- console.log(`\x1b[90m${formatError(wrapped, true)}\x1b[0m`);
1842
+ logger$1.item(name, "red");
1843
+ logger$1.error(wrapped, true);
1974
1844
  }
1975
1845
  }
1976
- console.log(`\x1b[1m\x1b[36m${"─".repeat(50)}\x1b[0m`);
1846
+ logger$1.divider();
1977
1847
  const totalDuration = results.reduce((sum, r) => sum + (r.stats?.duration || 0), 0);
1978
1848
  const totalEndpoints = results.reduce((sum, r) => sum + (r.stats?.endpoints || 0), 0);
1979
1849
  const totalSchemas = results.reduce((sum, r) => sum + (r.stats?.schemas || 0), 0);
1980
- 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)`);
1981
- 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)`);
1982
- console.log(`\x1b[1m\x1b[36m${"─".repeat(50)}\x1b[0m`);
1850
+ logger$1.summary({
1851
+ succeeded: successCount,
1852
+ failed: failCount,
1853
+ endpoints: totalEndpoints,
1854
+ schemas: totalSchemas,
1855
+ duration: totalDuration
1856
+ });
1857
+ logger$1.divider();
1983
1858
  return {};
1984
1859
  }
1985
1860
  };