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