czh-api 1.0.4 → 1.0.6

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.
@@ -35,57 +35,227 @@ function convertOpenApiTypeToTypeScript(openApiType: string | undefined): string
35
35
  case 'number':
36
36
  return 'number';
37
37
  default:
38
- return 'any';
38
+ return openApiType;
39
39
  }
40
40
  }
41
41
 
42
42
  // 改进类型定义的辅助函数
43
- function isValidTypeIdentifier(typeName: string | undefined): boolean {
44
- if (!typeName) return false;
45
- return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(typeName);
46
- }
47
-
48
- function escapeRegex(value: string): string {
49
- return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
50
- }
51
-
52
- function resolveInterfaceTargetType(typeName: string | undefined): string | null {
53
- if (typeof typeName !== 'string' || typeName.length === 0) return null;
54
- if (isValidTypeIdentifier(typeName)) return typeName;
55
-
56
- const arrayMatch = typeName.match(/^([A-Za-z_$][A-Za-z0-9_$]*)\[\]$/);
57
- if (arrayMatch) {
58
- return arrayMatch[1];
59
- }
60
-
61
- return null;
62
- }
63
-
64
- function findInterfaceBlockRange(content: string, typeName: string): { start: number; end: number } | null {
65
- const startRegex = new RegExp(`export interface ${escapeRegex(typeName)}\\s*\\{`);
66
- const match = startRegex.exec(content);
67
- if (!match) return null;
68
-
69
- const start = match.index;
70
- const openBraceIndex = start + match[0].lastIndexOf('{');
71
- let depth = 0;
72
-
73
- for (let i = openBraceIndex; i < content.length; i++) {
74
- const ch = content[i];
75
- if (ch === '{') {
76
- depth++;
77
- } else if (ch === '}') {
78
- depth--;
79
- if (depth === 0) {
80
- return { start, end: i + 1 };
81
- }
82
- }
83
- }
84
-
85
- return null;
86
- }
87
-
88
- function improveTypeDefinitions(typesContent: string, endpoints: any[]): string {
43
+ function isValidTypeIdentifier(typeName: string | undefined): boolean {
44
+ if (!typeName) return false;
45
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(typeName);
46
+ }
47
+
48
+ function escapeRegex(value: string): string {
49
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
50
+ }
51
+
52
+ function resolveInterfaceTargetType(typeName: string | undefined): string | null {
53
+ if (typeof typeName !== 'string' || typeName.length === 0) return null;
54
+ if (isValidTypeIdentifier(typeName)) return typeName;
55
+
56
+ const arrayMatch = typeName.match(/^([A-Za-z_$][A-Za-z0-9_$]*)\[\]$/);
57
+ if (arrayMatch) {
58
+ return arrayMatch[1];
59
+ }
60
+
61
+ return null;
62
+ }
63
+
64
+ function findInterfaceBlockRange(content: string, typeName: string): { start: number; end: number } | null {
65
+ const startRegex = new RegExp(`export interface ${escapeRegex(typeName)}\\s*\\{`);
66
+ const match = startRegex.exec(content);
67
+ if (!match) return null;
68
+
69
+ const start = match.index;
70
+ const openBraceIndex = start + match[0].lastIndexOf('{');
71
+ let depth = 0;
72
+
73
+ for (let i = openBraceIndex; i < content.length; i++) {
74
+ const ch = content[i];
75
+ if (ch === '{') {
76
+ depth++;
77
+ } else if (ch === '}') {
78
+ depth--;
79
+ if (depth === 0) {
80
+ return { start, end: i + 1 };
81
+ }
82
+ }
83
+ }
84
+
85
+ return null;
86
+ }
87
+
88
+ const TS_BUILTIN_TYPE_NAMES = new Set([
89
+ 'string',
90
+ 'number',
91
+ 'boolean',
92
+ 'null',
93
+ 'undefined',
94
+ 'void',
95
+ 'any',
96
+ 'unknown',
97
+ 'never',
98
+ 'object',
99
+ 'Record',
100
+ 'Array',
101
+ 'Date',
102
+ 'Promise',
103
+ 'true',
104
+ 'false',
105
+ ]);
106
+
107
+ function extractTypeIdentifiers(typeExpr: string | undefined): string[] {
108
+ if (!typeExpr) return [];
109
+ const matches = typeExpr.match(/[A-Za-z_$][A-Za-z0-9_$]*/g) || [];
110
+ return [...new Set(matches.filter(name => !TS_BUILTIN_TYPE_NAMES.has(name)))];
111
+ }
112
+
113
+ function getSchemaNameFromRef(ref: string | undefined): string {
114
+ if (!ref) return '';
115
+ return ref.split('/').pop() || '';
116
+ }
117
+
118
+ function resolveSchemaTypeFromModuleSchemas(
119
+ schema: OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject | undefined,
120
+ moduleSchemas: { [typeName: string]: OpenAPIV3.SchemaObject },
121
+ visitedRefs: Set<string> = new Set()
122
+ ): string {
123
+ if (!schema) return 'any';
124
+
125
+ if ((schema as OpenAPIV3.ReferenceObject).$ref) {
126
+ const refName = getSchemaNameFromRef((schema as OpenAPIV3.ReferenceObject).$ref);
127
+ return refName || 'any';
128
+ }
129
+
130
+ const schemaObj = schema as OpenAPIV3.SchemaObject;
131
+
132
+ if (schemaObj.anyOf && Array.isArray(schemaObj.anyOf) && schemaObj.anyOf.length > 0) {
133
+ const types = schemaObj.anyOf
134
+ .map(item => resolveSchemaTypeFromModuleSchemas(item as OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject, moduleSchemas, visitedRefs))
135
+ .filter(Boolean);
136
+ if (types.length > 0) {
137
+ return [...new Set(types)].join(' | ');
138
+ }
139
+ }
140
+
141
+ if (schemaObj.oneOf && Array.isArray(schemaObj.oneOf) && schemaObj.oneOf.length > 0) {
142
+ const types = schemaObj.oneOf
143
+ .map(item => resolveSchemaTypeFromModuleSchemas(item as OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject, moduleSchemas, visitedRefs))
144
+ .filter(Boolean);
145
+ if (types.length > 0) {
146
+ return [...new Set(types)].join(' | ');
147
+ }
148
+ }
149
+
150
+ if (schemaObj.type === 'array') {
151
+ const itemType = resolveSchemaTypeFromModuleSchemas(
152
+ schemaObj.items as OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject | undefined,
153
+ moduleSchemas,
154
+ visitedRefs
155
+ );
156
+ return `${itemType || 'any'}[]`;
157
+ }
158
+
159
+ if (schemaObj.type === 'object' && schemaObj.additionalProperties) {
160
+ if (schemaObj.additionalProperties === true) {
161
+ return 'Record<string, any>';
162
+ }
163
+ const valueType = resolveSchemaTypeFromModuleSchemas(
164
+ schemaObj.additionalProperties as OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject,
165
+ moduleSchemas,
166
+ visitedRefs
167
+ );
168
+ return `Record<string, ${valueType || 'any'}>`;
169
+ }
170
+
171
+ if (schemaObj.type === 'object' && schemaObj.properties && Object.keys(schemaObj.properties).length > 0) {
172
+ const requiredSet = new Set(schemaObj.required || []);
173
+ const inlineFields = Object.entries(schemaObj.properties).map(([key, value]) => {
174
+ const fieldType = resolveSchemaTypeFromModuleSchemas(
175
+ value as OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject,
176
+ moduleSchemas,
177
+ visitedRefs
178
+ );
179
+ const optional = requiredSet.has(key) ? '' : '?';
180
+ return `${key}${optional}: ${fieldType || 'any'}`;
181
+ });
182
+ return `{ ${inlineFields.join('; ')} }`;
183
+ }
184
+
185
+ const baseType = convertOpenApiTypeToTypeScript(schemaObj.type);
186
+ if (!baseType) return 'any';
187
+ return schemaObj.nullable ? `${baseType} | null` : baseType;
188
+ }
189
+
190
+ function collectSchemaProperties(
191
+ schema: OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject | undefined,
192
+ moduleSchemas: { [typeName: string]: OpenAPIV3.SchemaObject },
193
+ visitedRefs: Set<string> = new Set()
194
+ ): { properties: Record<string, OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject>; required: Set<string> } {
195
+ const collected: { properties: Record<string, OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject>; required: Set<string> } = {
196
+ properties: {},
197
+ required: new Set<string>(),
198
+ };
199
+ if (!schema) return collected;
200
+
201
+ if ((schema as OpenAPIV3.ReferenceObject).$ref) {
202
+ const ref = (schema as OpenAPIV3.ReferenceObject).$ref;
203
+ if (!visitedRefs.has(ref)) {
204
+ visitedRefs.add(ref);
205
+ const refName = getSchemaNameFromRef(ref);
206
+ const refSchema = moduleSchemas[refName];
207
+ if (refSchema) {
208
+ const nested = collectSchemaProperties(refSchema, moduleSchemas, visitedRefs);
209
+ Object.assign(collected.properties, nested.properties);
210
+ nested.required.forEach(field => collected.required.add(field));
211
+ }
212
+ }
213
+ return collected;
214
+ }
215
+
216
+ const schemaObj = schema as OpenAPIV3.SchemaObject;
217
+
218
+ if (schemaObj.allOf && Array.isArray(schemaObj.allOf)) {
219
+ schemaObj.allOf.forEach(item => {
220
+ const nested = collectSchemaProperties(item as OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject, moduleSchemas, visitedRefs);
221
+ Object.assign(collected.properties, nested.properties);
222
+ nested.required.forEach(field => collected.required.add(field));
223
+ });
224
+ }
225
+
226
+ if (schemaObj.properties) {
227
+ Object.entries(schemaObj.properties).forEach(([name, value]) => {
228
+ collected.properties[name] = value as OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject;
229
+ });
230
+ }
231
+
232
+ (schemaObj.required || []).forEach(field => collected.required.add(field));
233
+ return collected;
234
+ }
235
+
236
+ function buildInterfaceDefinitionFromModuleSchemas(
237
+ typeName: string,
238
+ moduleSchemas: { [typeName: string]: OpenAPIV3.SchemaObject }
239
+ ): string | null {
240
+ const schema = moduleSchemas[typeName];
241
+ if (!schema) return null;
242
+
243
+ const { properties, required } = collectSchemaProperties(schema, moduleSchemas);
244
+ const entries = Object.entries(properties);
245
+ if (entries.length === 0) return null;
246
+
247
+ const lines = entries.map(([propName, propSchema]) => {
248
+ const optional = required.has(propName) ? '' : '?';
249
+ const propType = resolveSchemaTypeFromModuleSchemas(propSchema, moduleSchemas) || 'any';
250
+ const propDescription = (propSchema as OpenAPIV3.SchemaObject).description || '';
251
+ const comment = propDescription ? ` // ${propDescription}` : '';
252
+ return ` ${propName}${optional}: ${propType};${comment}`;
253
+ });
254
+
255
+ return `export interface ${typeName} {\n${lines.join('\n')}\n}`;
256
+ }
257
+
258
+ function improveTypeDefinitions(typesContent: string, endpoints: any[]): string {
89
259
  let improvedContent = typesContent;
90
260
 
91
261
  // 收集所有需要改进的类型定义
@@ -116,52 +286,52 @@ function improveTypeDefinitions(typesContent: string, endpoints: any[]): string
116
286
 
117
287
  endpoints.forEach(endpoint => {
118
288
  // 改进 params 类型 - 使用 paramsJsdocParams(仅包含 path/query 参数)
119
- const requestParamsTypeName = endpoint.requestParamsTypeName;
120
- if (requestParamsTypeName && isValidTypeIdentifier(requestParamsTypeName) && endpoint.paramsJsdocParams && endpoint.paramsJsdocParams.length > 0) {
121
- const paramsFields = buildFieldsFromJsdocParams(endpoint.paramsJsdocParams);
122
-
123
- if (paramsFields) {
124
- typeImprovements[requestParamsTypeName] = `export interface ${requestParamsTypeName} {
125
- ${paramsFields}
126
- }`;
127
- }
128
- }
289
+ const requestParamsTypeName = endpoint.requestParamsTypeName;
290
+ if (requestParamsTypeName && isValidTypeIdentifier(requestParamsTypeName) && endpoint.paramsJsdocParams && endpoint.paramsJsdocParams.length > 0) {
291
+ const paramsFields = buildFieldsFromJsdocParams(endpoint.paramsJsdocParams);
292
+
293
+ if (paramsFields) {
294
+ typeImprovements[requestParamsTypeName] = `export interface ${requestParamsTypeName} {
295
+ ${paramsFields}
296
+ }`;
297
+ }
298
+ }
129
299
 
130
300
  // 改进 requestBody 类型 - 使用 dataJsdocParams(仅包含 requestBody 参数)
131
- const requestBodyTypeName = endpoint.requestBodyTypeName;
132
- if (requestBodyTypeName && isValidTypeIdentifier(requestBodyTypeName) && endpoint.dataJsdocParams && endpoint.dataJsdocParams.length > 0) {
133
- const dataFields = buildFieldsFromJsdocParams(endpoint.dataJsdocParams);
134
-
135
- if (dataFields) {
136
- typeImprovements[requestBodyTypeName] = `export interface ${requestBodyTypeName} {
137
- ${dataFields}
138
- }`;
139
- }
140
- }
301
+ const requestBodyTypeName = endpoint.requestBodyTypeName;
302
+ if (requestBodyTypeName && isValidTypeIdentifier(requestBodyTypeName) && endpoint.dataJsdocParams && endpoint.dataJsdocParams.length > 0) {
303
+ const dataFields = buildFieldsFromJsdocParams(endpoint.dataJsdocParams);
304
+
305
+ if (dataFields) {
306
+ typeImprovements[requestBodyTypeName] = `export interface ${requestBodyTypeName} {
307
+ ${dataFields}
308
+ }`;
309
+ }
310
+ }
141
311
 
142
312
  // 改进 response 类型 - 使用 responseJsdocParams(包含响应字段信息)
143
- const responseTargetType = resolveInterfaceTargetType(endpoint.responseTypeName);
144
- if (responseTargetType && endpoint.responseTypeName !== 'void' && endpoint.responseJsdocParams && endpoint.responseJsdocParams.length > 0) {
145
- const responseFields = buildFieldsFromJsdocParams(endpoint.responseJsdocParams);
146
-
147
- if (responseFields) {
148
- typeImprovements[responseTargetType] = `export interface ${responseTargetType} {
149
- ${responseFields}
150
- }`;
151
- }
152
- }
313
+ const responseTargetType = resolveInterfaceTargetType(endpoint.responseTypeName);
314
+ if (responseTargetType && endpoint.responseTypeName !== 'void' && endpoint.responseJsdocParams && endpoint.responseJsdocParams.length > 0) {
315
+ const responseFields = buildFieldsFromJsdocParams(endpoint.responseJsdocParams);
316
+
317
+ if (responseFields) {
318
+ typeImprovements[responseTargetType] = `export interface ${responseTargetType} {
319
+ ${responseFields}
320
+ }`;
321
+ }
322
+ }
153
323
  });
154
324
 
155
325
  // 替换现有的类型定义
156
326
  Object.entries(typeImprovements).forEach(([typeName, newDefinition]) => {
157
327
  // 查找并替换现有的接口定义
158
- const blockRange = findInterfaceBlockRange(improvedContent, typeName);
159
- if (blockRange) {
160
- improvedContent =
161
- improvedContent.slice(0, blockRange.start) +
162
- newDefinition +
163
- improvedContent.slice(blockRange.end);
164
- } else {
328
+ const blockRange = findInterfaceBlockRange(improvedContent, typeName);
329
+ if (blockRange) {
330
+ improvedContent =
331
+ improvedContent.slice(0, blockRange.start) +
332
+ newDefinition +
333
+ improvedContent.slice(blockRange.end);
334
+ } else {
165
335
  // 如果没找到接口定义,添加到末尾
166
336
  improvedContent += '\n\n' + newDefinition;
167
337
  }
@@ -171,7 +341,7 @@ ${responseFields}
171
341
  }
172
342
 
173
343
  // 移除无用的类型别名
174
- function removeUselessTypeAliases(typesContent: string): string {
344
+ function removeUselessTypeAliases(typesContent: string): string {
175
345
  let cleanedContent = typesContent;
176
346
 
177
347
  // 收集要删除的类型别名及其对应的基础类型
@@ -238,33 +408,57 @@ function removeUselessTypeAliases(typesContent: string): string {
238
408
  // 移除孤立的类型注释(没有对应类型定义的注释)
239
409
  cleanedContent = cleanedContent.replace(/\/\*\*\n \* [^\n]*\n \*\/\n(?!export)/g, '');
240
410
 
241
- return cleanedContent;
242
- }
243
-
244
- function normalizeRef(refValue: string): string {
245
- const match = refValue.match(/^#\/components\/schemas\/([^/]+)$/);
246
- if (match) {
247
- return `#/definitions/${match[1]}`;
248
- }
249
- return refValue;
411
+ return cleanedContent;
412
+ }
413
+
414
+ function normalizeRef(refValue: string): string {
415
+ const match = refValue.match(/^#\/components\/schemas\/([^/]+)$/);
416
+ if (match) {
417
+ return `#/definitions/${match[1]}`;
418
+ }
419
+ return refValue;
420
+ }
421
+
422
+ function normalizeSchemaRefs<T>(value: T): T {
423
+ if (Array.isArray(value)) {
424
+ return value.map(item => normalizeSchemaRefs(item)) as T;
425
+ }
426
+
427
+ if (value && typeof value === 'object') {
428
+ const obj = value as Record<string, unknown>;
429
+ const normalized: Record<string, unknown> = {};
430
+
431
+ for (const key in obj) {
432
+ const currentValue = obj[key];
433
+ if (key === '$ref' && typeof currentValue === 'string') {
434
+ normalized[key] = normalizeRef(currentValue);
435
+ } else {
436
+ normalized[key] = normalizeSchemaRefs(currentValue);
437
+ }
438
+ }
439
+
440
+ return normalized as T;
441
+ }
442
+
443
+ return value;
250
444
  }
251
445
 
252
- function normalizeSchemaRefs<T>(value: T): T {
446
+ function stripNestedSchemaTitles<T>(value: T, depth: number = 0): T {
253
447
  if (Array.isArray(value)) {
254
- return value.map(item => normalizeSchemaRefs(item)) as T;
448
+ return value.map(item => stripNestedSchemaTitles(item, depth + 1)) as T;
255
449
  }
256
450
 
257
451
  if (value && typeof value === 'object') {
258
452
  const obj = value as Record<string, unknown>;
259
453
  const normalized: Record<string, unknown> = {};
260
454
 
261
- for (const key in obj) {
262
- const currentValue = obj[key];
263
- if (key === '$ref' && typeof currentValue === 'string') {
264
- normalized[key] = normalizeRef(currentValue);
265
- } else {
266
- normalized[key] = normalizeSchemaRefs(currentValue);
455
+ for (const [key, currentValue] of Object.entries(obj)) {
456
+ // json-schema-to-typescript may generate invalid type aliases from nested title values
457
+ // (e.g. Chinese punctuation or numeric-leading titles), so keep only root-level titles.
458
+ if (key === 'title' && depth > 0) {
459
+ continue;
267
460
  }
461
+ normalized[key] = stripNestedSchemaTitles(currentValue, depth + 1);
268
462
  }
269
463
 
270
464
  return normalized as T;
@@ -272,8 +466,8 @@ function normalizeSchemaRefs<T>(value: T): T {
272
466
 
273
467
  return value;
274
468
  }
275
-
276
- interface IConfig {
469
+
470
+ interface IConfig {
277
471
  url: string;
278
472
  outputDir: string;
279
473
  httpClientPath: string;
@@ -394,14 +588,16 @@ export const handleBuild = async () => {
394
588
  if (Object.keys(module.schemas).length > 0) {
395
589
  console.log(chalk.blue(`正在为模块 "${moduleName}" 生成类型文件,包含 ${Object.keys(module.schemas).length} 个 schema`));
396
590
  try {
397
- const normalizedModuleSchemas = normalizeSchemaRefs(module.schemas);
398
- const schemasWithTitles: { [key: string]: OpenAPIV3.SchemaObject } = {};
399
- for (const schemaName in normalizedModuleSchemas) {
400
- schemasWithTitles[schemaName] = {
401
- ...normalizedModuleSchemas[schemaName],
402
- title: schemaName,
403
- };
404
- }
591
+ const normalizedModuleSchemas = stripNestedSchemaTitles(
592
+ normalizeSchemaRefs(module.schemas)
593
+ );
594
+ const schemasWithTitles: { [key: string]: OpenAPIV3.SchemaObject } = {};
595
+ for (const schemaName in normalizedModuleSchemas) {
596
+ schemasWithTitles[schemaName] = {
597
+ ...normalizedModuleSchemas[schemaName],
598
+ title: schemaName,
599
+ };
600
+ }
405
601
 
406
602
  const rootSchemaForCompiler = {
407
603
  title: 'schemas',
@@ -452,10 +648,12 @@ export const handleBuild = async () => {
452
648
 
453
649
  // 尝试逐个验证 schema,过滤掉有问题的
454
650
  const validSchemas: { [key: string]: OpenAPIV3.SchemaObject } = {};
455
- const invalidSchemas: string[] = [];
456
- const normalizedModuleSchemas = normalizeSchemaRefs(module.schemas);
651
+ const invalidSchemas: string[] = [];
652
+ const normalizedModuleSchemas = stripNestedSchemaTitles(
653
+ normalizeSchemaRefs(module.schemas)
654
+ );
457
655
 
458
- for (const schemaName in normalizedModuleSchemas) {
656
+ for (const schemaName in normalizedModuleSchemas) {
459
657
  try {
460
658
  // 尝试单独编译每个 schema
461
659
  const testSchema = {
@@ -463,12 +661,12 @@ export const handleBuild = async () => {
463
661
  type: 'object',
464
662
  properties: {},
465
663
  additionalProperties: false,
466
- definitions: { [schemaName]: normalizedModuleSchemas[schemaName] },
467
- components: { schemas: { [schemaName]: normalizedModuleSchemas[schemaName] } }
664
+ definitions: { [schemaName]: normalizedModuleSchemas[schemaName] },
665
+ components: { schemas: { [schemaName]: normalizedModuleSchemas[schemaName] } }
468
666
  };
469
667
  await compile(testSchema as any, 'test', { unreachableDefinitions: true });
470
668
  validSchemas[schemaName] = {
471
- ...normalizedModuleSchemas[schemaName],
669
+ ...normalizedModuleSchemas[schemaName],
472
670
  title: schemaName
473
671
  };
474
672
  } catch (schemaError) {
@@ -543,6 +741,7 @@ export const handleBuild = async () => {
543
741
 
544
742
  // 创建类型定义映射
545
743
  const typeDefinitions: { [typeName: string]: string } = {};
744
+ const nestedReferencedTypes = new Set<string>();
546
745
 
547
746
  // 从 endpoints 中提取类型定义
548
747
  module.endpoints.forEach(endpoint => {
@@ -560,6 +759,12 @@ export const handleBuild = async () => {
560
759
  } else {
561
760
  type = convertOpenApiTypeToTypeScript(type);
562
761
  }
762
+
763
+ extractTypeIdentifiers(type).forEach(typeName => {
764
+ if (isValidTypeIdentifier(typeName)) {
765
+ nestedReferencedTypes.add(typeName);
766
+ }
767
+ });
563
768
 
564
769
  const comment = param.description ? ` // ${param.description}` : '';
565
770
  return ` ${param.name}${optional}: ${type};${comment}`;
@@ -567,53 +772,68 @@ export const handleBuild = async () => {
567
772
  .join('\n');
568
773
 
569
774
  // 处理 params 类型 - 使用 paramsJsdocParams
570
- const requestParamsTypeName = endpoint.requestParamsTypeName;
571
- if (requestParamsTypeName && isValidTypeIdentifier(requestParamsTypeName) && endpoint.paramsJsdocParams && endpoint.paramsJsdocParams.length > 0) {
572
- const paramsFields = buildFields(endpoint.paramsJsdocParams);
573
-
574
- if (paramsFields) {
575
- typeDefinitions[requestParamsTypeName] = `export interface ${requestParamsTypeName} {
576
- ${paramsFields}
577
- }`;
578
- }
579
- }
775
+ const requestParamsTypeName = endpoint.requestParamsTypeName;
776
+ if (requestParamsTypeName && isValidTypeIdentifier(requestParamsTypeName) && endpoint.paramsJsdocParams && endpoint.paramsJsdocParams.length > 0) {
777
+ const paramsFields = buildFields(endpoint.paramsJsdocParams);
778
+
779
+ if (paramsFields) {
780
+ typeDefinitions[requestParamsTypeName] = `export interface ${requestParamsTypeName} {
781
+ ${paramsFields}
782
+ }`;
783
+ }
784
+ }
580
785
 
581
786
  // 处理 data 类型 (requestBody) - 使用 dataJsdocParams
582
- const requestBodyTypeName = endpoint.requestBodyTypeName;
583
- if (requestBodyTypeName && isValidTypeIdentifier(requestBodyTypeName) && endpoint.dataJsdocParams && endpoint.dataJsdocParams.length > 0) {
584
- const dataFields = buildFields(endpoint.dataJsdocParams);
585
-
586
- if (dataFields) {
587
- typeDefinitions[requestBodyTypeName] = `export interface ${requestBodyTypeName} {
588
- ${dataFields}
589
- }`;
590
- }
591
- }
787
+ const requestBodyTypeName = endpoint.requestBodyTypeName;
788
+ if (requestBodyTypeName && isValidTypeIdentifier(requestBodyTypeName) && endpoint.dataJsdocParams && endpoint.dataJsdocParams.length > 0) {
789
+ const dataFields = buildFields(endpoint.dataJsdocParams);
790
+
791
+ if (dataFields) {
792
+ typeDefinitions[requestBodyTypeName] = `export interface ${requestBodyTypeName} {
793
+ ${dataFields}
794
+ }`;
795
+ }
796
+ }
592
797
 
593
798
  // 处理 response 类型 - 使用 responseJsdocParams
594
- const responseTargetType = resolveInterfaceTargetType(endpoint.responseTypeName);
595
- if (responseTargetType && endpoint.responseTypeName !== 'void' && endpoint.responseJsdocParams && endpoint.responseJsdocParams.length > 0) {
596
- const responseFields = buildFields(endpoint.responseJsdocParams);
597
-
598
- if (responseFields) {
599
- typeDefinitions[responseTargetType] = `export interface ${responseTargetType} {
600
- ${responseFields}
601
- }`;
602
- }
603
- }
799
+ const responseTargetType = resolveInterfaceTargetType(endpoint.responseTypeName);
800
+ if (responseTargetType && endpoint.responseTypeName !== 'void' && endpoint.responseJsdocParams && endpoint.responseJsdocParams.length > 0) {
801
+ const responseFields = buildFields(endpoint.responseJsdocParams);
802
+
803
+ if (responseFields) {
804
+ typeDefinitions[responseTargetType] = `export interface ${responseTargetType} {
805
+ ${responseFields}
806
+ }`;
807
+ }
808
+ }
604
809
  });
605
810
 
606
811
  // 为没有定义的类型添加基本定义
607
- allReferencedTypes.forEach(typeName => {
608
- if (!isValidTypeIdentifier(typeName)) {
609
- return;
610
- }
611
- if (!typeDefinitions[typeName]) {
612
- typeDefinitions[typeName] = `export interface ${typeName} {
613
- [key: string]: any;
614
- }`;
615
- }
616
- });
812
+ const fallbackReferencedTypes = [
813
+ ...new Set([
814
+ ...allReferencedTypes,
815
+ ...Object.keys(module.schemas || {}),
816
+ ...nestedReferencedTypes,
817
+ ])
818
+ ];
819
+ fallbackReferencedTypes.forEach(typeName => {
820
+ if (!isValidTypeIdentifier(typeName)) {
821
+ return;
822
+ }
823
+ if (!typeDefinitions[typeName]) {
824
+ const schemaBasedDefinition = buildInterfaceDefinitionFromModuleSchemas(
825
+ typeName,
826
+ module.schemas as { [typeName: string]: OpenAPIV3.SchemaObject }
827
+ );
828
+ if (schemaBasedDefinition) {
829
+ typeDefinitions[typeName] = schemaBasedDefinition;
830
+ return;
831
+ }
832
+ typeDefinitions[typeName] = `export interface ${typeName} {
833
+ [key: string]: any;
834
+ }`;
835
+ }
836
+ });
617
837
 
618
838
  const basicTypesContent = `/* eslint-disable */
619
839
  /**
@@ -687,4 +907,4 @@ ${Object.values(typeDefinitions).join('\n\n')}
687
907
  } catch (error) {
688
908
  console.error(chalk.red('An error occurred during build process:'), error);
689
909
  }
690
- };
910
+ };