czh-api 1.0.5 → 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.
- package/CHANGELOG.md +9 -0
- package/api.json +39529 -0
- package/dist/commands/build.js +35 -16
- package/package.json +1 -1
- package/src/commands/build.ts +405 -377
package/src/commands/build.ts
CHANGED
|
@@ -18,8 +18,8 @@ import { compile } from 'json-schema-to-typescript';
|
|
|
18
18
|
import { Converter } from '@apiture/openapi-down-convert';
|
|
19
19
|
|
|
20
20
|
// 统一的类型转换函数
|
|
21
|
-
function convertOpenApiTypeToTypeScript(openApiType: string | undefined): string {
|
|
22
|
-
if (!openApiType) return 'any';
|
|
21
|
+
function convertOpenApiTypeToTypeScript(openApiType: string | undefined): string {
|
|
22
|
+
if (!openApiType) return 'any';
|
|
23
23
|
|
|
24
24
|
switch (openApiType) {
|
|
25
25
|
case 'integer':
|
|
@@ -32,230 +32,230 @@ function convertOpenApiTypeToTypeScript(openApiType: string | undefined): string
|
|
|
32
32
|
return 'boolean';
|
|
33
33
|
case 'string':
|
|
34
34
|
return 'string';
|
|
35
|
-
case 'number':
|
|
36
|
-
return 'number';
|
|
37
|
-
default:
|
|
38
|
-
return openApiType;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
35
|
+
case 'number':
|
|
36
|
+
return 'number';
|
|
37
|
+
default:
|
|
38
|
+
return openApiType;
|
|
39
|
+
}
|
|
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
|
-
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 {
|
|
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 {
|
|
259
259
|
let improvedContent = typesContent;
|
|
260
260
|
|
|
261
261
|
// 收集所有需要改进的类型定义
|
|
@@ -270,13 +270,13 @@ function improveTypeDefinitions(typesContent: string, endpoints: any[]): string
|
|
|
270
270
|
let type = param.type;
|
|
271
271
|
|
|
272
272
|
// 处理联合类型,确保正确的 TypeScript 语法
|
|
273
|
-
if (type && type.includes(' | ')) {
|
|
274
|
-
if (type.includes('null')) {
|
|
275
|
-
type = type.replace(/\s*\|\s*null/g, ' | null');
|
|
276
|
-
}
|
|
277
|
-
} else {
|
|
278
|
-
type = convertOpenApiTypeToTypeScript(type);
|
|
279
|
-
}
|
|
273
|
+
if (type && type.includes(' | ')) {
|
|
274
|
+
if (type.includes('null')) {
|
|
275
|
+
type = type.replace(/\s*\|\s*null/g, ' | null');
|
|
276
|
+
}
|
|
277
|
+
} else {
|
|
278
|
+
type = convertOpenApiTypeToTypeScript(type);
|
|
279
|
+
}
|
|
280
280
|
|
|
281
281
|
const comment = param.description ? ` // ${param.description}` : '';
|
|
282
282
|
return ` ${param.name}${optional}: ${type};${comment}`;
|
|
@@ -286,52 +286,52 @@ function improveTypeDefinitions(typesContent: string, endpoints: any[]): string
|
|
|
286
286
|
|
|
287
287
|
endpoints.forEach(endpoint => {
|
|
288
288
|
// 改进 params 类型 - 使用 paramsJsdocParams(仅包含 path/query 参数)
|
|
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
|
-
}
|
|
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
|
+
}
|
|
299
299
|
|
|
300
300
|
// 改进 requestBody 类型 - 使用 dataJsdocParams(仅包含 requestBody 参数)
|
|
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
|
-
}
|
|
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
|
+
}
|
|
311
311
|
|
|
312
312
|
// 改进 response 类型 - 使用 responseJsdocParams(包含响应字段信息)
|
|
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
|
-
}
|
|
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
|
+
}
|
|
323
323
|
});
|
|
324
324
|
|
|
325
325
|
// 替换现有的类型定义
|
|
326
326
|
Object.entries(typeImprovements).forEach(([typeName, newDefinition]) => {
|
|
327
327
|
// 查找并替换现有的接口定义
|
|
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 {
|
|
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 {
|
|
335
335
|
// 如果没找到接口定义,添加到末尾
|
|
336
336
|
improvedContent += '\n\n' + newDefinition;
|
|
337
337
|
}
|
|
@@ -341,7 +341,7 @@ ${responseFields}
|
|
|
341
341
|
}
|
|
342
342
|
|
|
343
343
|
// 移除无用的类型别名
|
|
344
|
-
function removeUselessTypeAliases(typesContent: string): string {
|
|
344
|
+
function removeUselessTypeAliases(typesContent: string): string {
|
|
345
345
|
let cleanedContent = typesContent;
|
|
346
346
|
|
|
347
347
|
// 收集要删除的类型别名及其对应的基础类型
|
|
@@ -408,33 +408,57 @@ function removeUselessTypeAliases(typesContent: string): string {
|
|
|
408
408
|
// 移除孤立的类型注释(没有对应类型定义的注释)
|
|
409
409
|
cleanedContent = cleanedContent.replace(/\/\*\*\n \* [^\n]*\n \*\/\n(?!export)/g, '');
|
|
410
410
|
|
|
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;
|
|
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;
|
|
420
444
|
}
|
|
421
445
|
|
|
422
|
-
function
|
|
446
|
+
function stripNestedSchemaTitles<T>(value: T, depth: number = 0): T {
|
|
423
447
|
if (Array.isArray(value)) {
|
|
424
|
-
return value.map(item =>
|
|
448
|
+
return value.map(item => stripNestedSchemaTitles(item, depth + 1)) as T;
|
|
425
449
|
}
|
|
426
450
|
|
|
427
451
|
if (value && typeof value === 'object') {
|
|
428
452
|
const obj = value as Record<string, unknown>;
|
|
429
453
|
const normalized: Record<string, unknown> = {};
|
|
430
454
|
|
|
431
|
-
for (const key
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
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;
|
|
437
460
|
}
|
|
461
|
+
normalized[key] = stripNestedSchemaTitles(currentValue, depth + 1);
|
|
438
462
|
}
|
|
439
463
|
|
|
440
464
|
return normalized as T;
|
|
@@ -442,8 +466,8 @@ function normalizeSchemaRefs<T>(value: T): T {
|
|
|
442
466
|
|
|
443
467
|
return value;
|
|
444
468
|
}
|
|
445
|
-
|
|
446
|
-
interface IConfig {
|
|
469
|
+
|
|
470
|
+
interface IConfig {
|
|
447
471
|
url: string;
|
|
448
472
|
outputDir: string;
|
|
449
473
|
httpClientPath: string;
|
|
@@ -564,14 +588,16 @@ export const handleBuild = async () => {
|
|
|
564
588
|
if (Object.keys(module.schemas).length > 0) {
|
|
565
589
|
console.log(chalk.blue(`正在为模块 "${moduleName}" 生成类型文件,包含 ${Object.keys(module.schemas).length} 个 schema`));
|
|
566
590
|
try {
|
|
567
|
-
const normalizedModuleSchemas =
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
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
|
+
}
|
|
575
601
|
|
|
576
602
|
const rootSchemaForCompiler = {
|
|
577
603
|
title: 'schemas',
|
|
@@ -622,10 +648,12 @@ export const handleBuild = async () => {
|
|
|
622
648
|
|
|
623
649
|
// 尝试逐个验证 schema,过滤掉有问题的
|
|
624
650
|
const validSchemas: { [key: string]: OpenAPIV3.SchemaObject } = {};
|
|
625
|
-
const invalidSchemas: string[] = [];
|
|
626
|
-
const normalizedModuleSchemas =
|
|
651
|
+
const invalidSchemas: string[] = [];
|
|
652
|
+
const normalizedModuleSchemas = stripNestedSchemaTitles(
|
|
653
|
+
normalizeSchemaRefs(module.schemas)
|
|
654
|
+
);
|
|
627
655
|
|
|
628
|
-
for (const schemaName in normalizedModuleSchemas) {
|
|
656
|
+
for (const schemaName in normalizedModuleSchemas) {
|
|
629
657
|
try {
|
|
630
658
|
// 尝试单独编译每个 schema
|
|
631
659
|
const testSchema = {
|
|
@@ -633,12 +661,12 @@ export const handleBuild = async () => {
|
|
|
633
661
|
type: 'object',
|
|
634
662
|
properties: {},
|
|
635
663
|
additionalProperties: false,
|
|
636
|
-
definitions: { [schemaName]: normalizedModuleSchemas[schemaName] },
|
|
637
|
-
components: { schemas: { [schemaName]: normalizedModuleSchemas[schemaName] } }
|
|
664
|
+
definitions: { [schemaName]: normalizedModuleSchemas[schemaName] },
|
|
665
|
+
components: { schemas: { [schemaName]: normalizedModuleSchemas[schemaName] } }
|
|
638
666
|
};
|
|
639
667
|
await compile(testSchema as any, 'test', { unreachableDefinitions: true });
|
|
640
668
|
validSchemas[schemaName] = {
|
|
641
|
-
...normalizedModuleSchemas[schemaName],
|
|
669
|
+
...normalizedModuleSchemas[schemaName],
|
|
642
670
|
title: schemaName
|
|
643
671
|
};
|
|
644
672
|
} catch (schemaError) {
|
|
@@ -712,8 +740,8 @@ export const handleBuild = async () => {
|
|
|
712
740
|
console.log(chalk.blue(`为模块 "${moduleName}" 生成基于 JSDoc 的类型定义...`));
|
|
713
741
|
|
|
714
742
|
// 创建类型定义映射
|
|
715
|
-
const typeDefinitions: { [typeName: string]: string } = {};
|
|
716
|
-
const nestedReferencedTypes = new Set<string>();
|
|
743
|
+
const typeDefinitions: { [typeName: string]: string } = {};
|
|
744
|
+
const nestedReferencedTypes = new Set<string>();
|
|
717
745
|
|
|
718
746
|
// 从 endpoints 中提取类型定义
|
|
719
747
|
module.endpoints.forEach(endpoint => {
|
|
@@ -724,88 +752,88 @@ export const handleBuild = async () => {
|
|
|
724
752
|
const optional = !param.required ? '?' : '';
|
|
725
753
|
let type = param.type;
|
|
726
754
|
|
|
727
|
-
if (type && type.includes(' | ')) {
|
|
728
|
-
if (type.includes('null')) {
|
|
729
|
-
type = type.replace(/\s*\|\s*null/g, ' | null');
|
|
730
|
-
}
|
|
731
|
-
} else {
|
|
732
|
-
type = convertOpenApiTypeToTypeScript(type);
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
extractTypeIdentifiers(type).forEach(typeName => {
|
|
736
|
-
if (isValidTypeIdentifier(typeName)) {
|
|
737
|
-
nestedReferencedTypes.add(typeName);
|
|
738
|
-
}
|
|
739
|
-
});
|
|
740
|
-
|
|
741
|
-
const comment = param.description ? ` // ${param.description}` : '';
|
|
742
|
-
return ` ${param.name}${optional}: ${type};${comment}`;
|
|
743
|
-
})
|
|
755
|
+
if (type && type.includes(' | ')) {
|
|
756
|
+
if (type.includes('null')) {
|
|
757
|
+
type = type.replace(/\s*\|\s*null/g, ' | null');
|
|
758
|
+
}
|
|
759
|
+
} else {
|
|
760
|
+
type = convertOpenApiTypeToTypeScript(type);
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
extractTypeIdentifiers(type).forEach(typeName => {
|
|
764
|
+
if (isValidTypeIdentifier(typeName)) {
|
|
765
|
+
nestedReferencedTypes.add(typeName);
|
|
766
|
+
}
|
|
767
|
+
});
|
|
768
|
+
|
|
769
|
+
const comment = param.description ? ` // ${param.description}` : '';
|
|
770
|
+
return ` ${param.name}${optional}: ${type};${comment}`;
|
|
771
|
+
})
|
|
744
772
|
.join('\n');
|
|
745
773
|
|
|
746
774
|
// 处理 params 类型 - 使用 paramsJsdocParams
|
|
747
|
-
const requestParamsTypeName = endpoint.requestParamsTypeName;
|
|
748
|
-
if (requestParamsTypeName && isValidTypeIdentifier(requestParamsTypeName) && endpoint.paramsJsdocParams && endpoint.paramsJsdocParams.length > 0) {
|
|
749
|
-
const paramsFields = buildFields(endpoint.paramsJsdocParams);
|
|
750
|
-
|
|
751
|
-
if (paramsFields) {
|
|
752
|
-
typeDefinitions[requestParamsTypeName] = `export interface ${requestParamsTypeName} {
|
|
753
|
-
${paramsFields}
|
|
754
|
-
}`;
|
|
755
|
-
}
|
|
756
|
-
}
|
|
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
|
+
}
|
|
757
785
|
|
|
758
786
|
// 处理 data 类型 (requestBody) - 使用 dataJsdocParams
|
|
759
|
-
const requestBodyTypeName = endpoint.requestBodyTypeName;
|
|
760
|
-
if (requestBodyTypeName && isValidTypeIdentifier(requestBodyTypeName) && endpoint.dataJsdocParams && endpoint.dataJsdocParams.length > 0) {
|
|
761
|
-
const dataFields = buildFields(endpoint.dataJsdocParams);
|
|
762
|
-
|
|
763
|
-
if (dataFields) {
|
|
764
|
-
typeDefinitions[requestBodyTypeName] = `export interface ${requestBodyTypeName} {
|
|
765
|
-
${dataFields}
|
|
766
|
-
}`;
|
|
767
|
-
}
|
|
768
|
-
}
|
|
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
|
+
}
|
|
769
797
|
|
|
770
798
|
// 处理 response 类型 - 使用 responseJsdocParams
|
|
771
|
-
const responseTargetType = resolveInterfaceTargetType(endpoint.responseTypeName);
|
|
772
|
-
if (responseTargetType && endpoint.responseTypeName !== 'void' && endpoint.responseJsdocParams && endpoint.responseJsdocParams.length > 0) {
|
|
773
|
-
const responseFields = buildFields(endpoint.responseJsdocParams);
|
|
774
|
-
|
|
775
|
-
if (responseFields) {
|
|
776
|
-
typeDefinitions[responseTargetType] = `export interface ${responseTargetType} {
|
|
777
|
-
${responseFields}
|
|
778
|
-
}`;
|
|
779
|
-
}
|
|
780
|
-
}
|
|
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
|
+
}
|
|
781
809
|
});
|
|
782
810
|
|
|
783
811
|
// 为没有定义的类型添加基本定义
|
|
784
|
-
const fallbackReferencedTypes = [
|
|
785
|
-
...new Set([
|
|
786
|
-
...allReferencedTypes,
|
|
787
|
-
...Object.keys(module.schemas || {}),
|
|
788
|
-
...nestedReferencedTypes,
|
|
789
|
-
])
|
|
790
|
-
];
|
|
791
|
-
fallbackReferencedTypes.forEach(typeName => {
|
|
792
|
-
if (!isValidTypeIdentifier(typeName)) {
|
|
793
|
-
return;
|
|
794
|
-
}
|
|
795
|
-
if (!typeDefinitions[typeName]) {
|
|
796
|
-
const schemaBasedDefinition = buildInterfaceDefinitionFromModuleSchemas(
|
|
797
|
-
typeName,
|
|
798
|
-
module.schemas as { [typeName: string]: OpenAPIV3.SchemaObject }
|
|
799
|
-
);
|
|
800
|
-
if (schemaBasedDefinition) {
|
|
801
|
-
typeDefinitions[typeName] = schemaBasedDefinition;
|
|
802
|
-
return;
|
|
803
|
-
}
|
|
804
|
-
typeDefinitions[typeName] = `export interface ${typeName} {
|
|
805
|
-
[key: string]: any;
|
|
806
|
-
}`;
|
|
807
|
-
}
|
|
808
|
-
});
|
|
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
|
+
});
|
|
809
837
|
|
|
810
838
|
const basicTypesContent = `/* eslint-disable */
|
|
811
839
|
/**
|
|
@@ -879,4 +907,4 @@ ${Object.values(typeDefinitions).join('\n\n')}
|
|
|
879
907
|
} catch (error) {
|
|
880
908
|
console.error(chalk.red('An error occurred during build process:'), error);
|
|
881
909
|
}
|
|
882
|
-
};
|
|
910
|
+
};
|