@@ -18,6 +18,7 @@ import {
1818} from 'lodash' ;
1919import { minimatch } from 'minimatch' ;
2020import nunjucks from 'nunjucks' ;
21+ import type { OpenAPIV3 } from 'openapi-types' ;
2122import { join } from 'path' ;
2223import { rimrafSync } from 'rimraf' ;
2324
@@ -651,6 +652,7 @@ export default class ServiceGenerator {
651652 newApi . requestBody as RequestBodyObject
652653 ) ;
653654 const response = this . getResponseTP ( newApi . responses ) ;
655+ // console.log(this.resolveObject(newApi.responses))
654656 const file = this . getFileTP (
655657 newApi . requestBody as RequestBodyObject
656658 ) ;
@@ -690,6 +692,24 @@ export default class ServiceGenerator {
690692 response . type = `${ this . config . namespace } .${ responseName } ` ;
691693 }
692694
695+ const responsesType = this . getResponsesType (
696+ newApi . responses ,
697+ functionName
698+ ) ;
699+
700+ // 如果有多个响应类型,生成对应的类型定义
701+ if ( responsesType ) {
702+ const responsesTypeName = upperFirst (
703+ `${ functionName } Responses`
704+ ) ;
705+ this . interfaceTPConfigs . push ( {
706+ typeName : responsesTypeName ,
707+ type : responsesType ,
708+ isEnum : false ,
709+ props : [ ] ,
710+ } ) ;
711+ }
712+
693713 let formattedPath = newApi . path . replace (
694714 / : ( [ ^ / ] * ) | { ( [ ^ } ] * ) } / gi,
695715 ( _ , str , str2 ) => `$\{${ str || str2 } }`
@@ -1091,6 +1111,137 @@ export default class ServiceGenerator {
10911111 return responseSchema ;
10921112 }
10931113
1114+ /**
1115+ * 生成多状态码响应类型定义
1116+ * 将 OpenAPI 的 responses 对象转换为 TypeScript 类型定义
1117+ * 例如:{ 200: ResponseType, 400: unknown, 404: unknown }
1118+ *
1119+ * @param responses OpenAPI 响应对象
1120+ * @param functionName 函数名称,用于生成主响应类型名称
1121+ * @returns 多状态码响应类型定义字符串,如果没有响应则返回 null
1122+ */
1123+ private getResponsesType (
1124+ responses : ResponsesObject = { } ,
1125+ functionName : string
1126+ ) {
1127+ if ( isEmpty ( responses ) ) {
1128+ return null ;
1129+ }
1130+
1131+ const { components } = this . openAPIData ;
1132+ // 生成主响应类型名称
1133+ const mainResponseTypeName = upperFirst ( `${ functionName } Response` ) ;
1134+ const responseEntries = this . parseResponseEntries ( responses , components ) ;
1135+
1136+ const responseTypes = responseEntries . map (
1137+ ( { statusCode, type, description = '' } ) => {
1138+ // 检查是否已存在对应的主响应类型,如果存在则复用,避免重复定义
1139+ const existType = this . interfaceTPConfigs . find (
1140+ ( item ) => item . typeName === mainResponseTypeName
1141+ ) ;
1142+ const lastType = existType ? mainResponseTypeName : type ;
1143+
1144+ // 格式化描述文本,让描述支持换行
1145+ const formattedDescription = lineBreakReg . test ( description )
1146+ ? description . split ( '\n' ) ?. join ( '\n * ' )
1147+ : description ;
1148+
1149+ // 生成带注释的类型定义
1150+ return formattedDescription
1151+ ? ` /**\n * ${ formattedDescription } \n */\n ${ statusCode } : ${ lastType } ;`
1152+ : ` ${ statusCode } : ${ lastType } ;` ;
1153+ }
1154+ ) ;
1155+
1156+ // 返回完整的对象类型定义
1157+ return `{\n${ responseTypes . join ( '\n' ) } \n}` ;
1158+ }
1159+
1160+ /**
1161+ * 解析响应条目,提取每个状态码对应的类型和描述信息
1162+ *
1163+ * @param responses OpenAPI 响应对象
1164+ * @param components OpenAPI 组件对象,用于解析引用类型
1165+ * @returns 响应条目数组,包含状态码、类型和描述
1166+ */
1167+ private parseResponseEntries (
1168+ responses : ResponsesObject ,
1169+ components : OpenAPIV3 . ComponentsObject
1170+ ) {
1171+ return keys ( responses ) . map ( ( statusCode ) => {
1172+ const response = this . resolveRefObject (
1173+ responses [ statusCode ] as ResponseObject
1174+ ) ;
1175+
1176+ if ( ! response ) {
1177+ return { statusCode, type : 'unknown' , description : '' } ;
1178+ }
1179+
1180+ const responseType = this . getResponseTypeFromContent (
1181+ response ,
1182+ components
1183+ ) ;
1184+ const description = response . description || '' ;
1185+
1186+ return { statusCode, type : responseType , description } ;
1187+ } ) ;
1188+ }
1189+
1190+ /**
1191+ * 从响应内容中提取 TypeScript 类型
1192+ * 处理不同的媒体类型和 schema 类型
1193+ *
1194+ * @param response 响应对象
1195+ * @param components OpenAPI 组件对象
1196+ * @returns TypeScript 类型字符串
1197+ */
1198+ private getResponseTypeFromContent (
1199+ response : ResponseObject ,
1200+ components : OpenAPIV3 . ComponentsObject
1201+ ) : string {
1202+ if ( ! response . content ) {
1203+ return 'unknown' ;
1204+ }
1205+
1206+ const resContent : ContentObject = response . content ;
1207+ const resContentMediaTypes = keys ( resContent ) ;
1208+ const mediaType = resContentMediaTypes . includes ( 'application/json' )
1209+ ? 'application/json'
1210+ : resContentMediaTypes [ 0 ] ;
1211+
1212+ if ( ! isObject ( resContent ) || ! mediaType ) {
1213+ return 'unknown' ;
1214+ }
1215+
1216+ let schema = ( resContent [ mediaType ] . schema ||
1217+ DEFAULT_SCHEMA ) as SchemaObject ;
1218+
1219+ if ( isReferenceObject ( schema ) ) {
1220+ const refName = getLastRefName ( schema . $ref ) ;
1221+ const childrenSchema = components . schemas [ refName ] ;
1222+
1223+ // 如果配置了 dataFields,尝试从指定字段提取类型
1224+ if ( isNonArraySchemaObject ( childrenSchema ) && this . config . dataFields ) {
1225+ schema = ( this . config . dataFields
1226+ . map ( ( field ) => childrenSchema . properties [ field ] )
1227+ . filter ( Boolean ) ?. [ 0 ] ||
1228+ resContent [ mediaType ] . schema ||
1229+ DEFAULT_SCHEMA ) as SchemaObject ;
1230+ }
1231+
1232+ return this . getType ( schema ) ;
1233+ } else if ( isSchemaObject ( schema ) ) {
1234+ // 设置属性的 required 状态
1235+ keys ( schema . properties ) . map ( ( fieldName ) => {
1236+ schema . properties [ fieldName ] [ 'required' ] =
1237+ schema . required ?. includes ( fieldName ) ?? false ;
1238+ } ) ;
1239+ return this . getType ( schema ) ;
1240+ } else {
1241+ return this . getType ( schema ) ;
1242+ }
1243+ }
1244+
10941245 private getParamsTP (
10951246 parameters : ( ParameterObject | ReferenceObject ) [ ] = [ ] ,
10961247 path : string = null
0 commit comments