czh-api 1.0.4 → 1.0.5
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 +13 -0
- package/README.md +4 -11
- package/dist/commands/build.js +152 -2
- package/dist/core/parser.js +82 -10
- package/package.json +1 -1
- package/src/commands/build.ts +220 -28
- package/src/core/parser.ts +111 -23
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
所有重要的版本更新都会记录在此文件中。
|
|
4
4
|
|
|
5
|
+
## [1.0.5] - 2026-03-19
|
|
6
|
+
|
|
7
|
+
### 修复
|
|
8
|
+
- 修复 FastAPI 场景下返回类型字段被错误降级为 `any` 的问题(如 `items.$ref`、`anyOf`、`oneOf`、`allOf` 组合场景)。
|
|
9
|
+
- 修复数组响应与嵌套对象类型在 fallback 生成流程中丢失字段的问题,避免出现仅有 `{ [key: string]: any }` 的空壳接口。
|
|
10
|
+
- 修复 `group_ids` 等多层结构类型解析不完整的问题,支持递归解析到更深层级(如 `number[] | null`)。
|
|
11
|
+
- 修复类型增强阶段对复杂类型名(数组、联合类型)处理不稳定导致的类型声明异常问题。
|
|
12
|
+
|
|
13
|
+
### 改进
|
|
14
|
+
- 增强 fallback 类型生成策略:优先基于 `module.schemas` 还原字段结构,再回退到 `any`,生成结果更可用。
|
|
15
|
+
- 增强类型依赖收集能力:从字段类型表达式中提取嵌套引用类型并自动补齐声明。
|
|
16
|
+
- 完善 README 模板示例并与当前默认模板保持一致(`api.hbs`、`index.hbs`、`types.hbs`)。
|
|
17
|
+
|
|
5
18
|
## [1.0.4] - 2026-03-19
|
|
6
19
|
|
|
7
20
|
### 修复
|
package/README.md
CHANGED
|
@@ -190,12 +190,7 @@ export const {{functionName}} = ({{#if hasParams}}params: {{requestParamsTypeNam
|
|
|
190
190
|
return http.request<{{responseTypeName}}>({
|
|
191
191
|
url: `{{path}}`,
|
|
192
192
|
method: '{{method}}',
|
|
193
|
-
{{#if hasParams}}
|
|
194
|
-
params,
|
|
195
|
-
{{/if}}
|
|
196
|
-
{{#if hasData}}
|
|
197
|
-
data,
|
|
198
|
-
{{/if}}
|
|
193
|
+
{{#if hasParams}}{{#unless (eq method 'put')}}{{#unless (eq method 'post')}}params,{{/unless}}{{/unless}}{{/if}}{{#if hasData}}data,{{/if}}
|
|
199
194
|
{{#if contentType}}
|
|
200
195
|
headers: { 'Content-Type': '{{contentType}}' },
|
|
201
196
|
{{/if}}
|
|
@@ -209,11 +204,9 @@ export const {{functionName}} = ({{#if hasParams}}params: {{requestParamsTypeNam
|
|
|
209
204
|
export const {{functionName}} = ({{#if hasParams}}params: {{requestParamsTypeName}}{{/if}}{{#if hasData}}{{#if hasParams}}, {{/if}}data: {{requestBodyTypeName}}{{/if}}) => {
|
|
210
205
|
return request.{{#if (eq method "delete")}}del{{else}}{{method}}{{/if}}<{{responseTypeName}}>({
|
|
211
206
|
url: `{{path}}`,
|
|
212
|
-
{{#if hasParams}}
|
|
213
|
-
|
|
214
|
-
{{
|
|
215
|
-
{{#if hasData}}
|
|
216
|
-
data,
|
|
207
|
+
{{#if hasParams}}{{#unless (eq method 'put')}}{{#unless (eq method 'post')}}params,{{/unless}}{{/unless}}{{/if}}{{#if hasData}}data,{{/if}}
|
|
208
|
+
{{#if contentType}}
|
|
209
|
+
headers: { 'Content-Type': '{{contentType}}' },
|
|
217
210
|
{{/if}}
|
|
218
211
|
});
|
|
219
212
|
};
|
package/dist/commands/build.js
CHANGED
|
@@ -48,7 +48,7 @@ function convertOpenApiTypeToTypeScript(openApiType) {
|
|
|
48
48
|
case 'number':
|
|
49
49
|
return 'number';
|
|
50
50
|
default:
|
|
51
|
-
return
|
|
51
|
+
return openApiType;
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
// 改进类型定义的辅助函数
|
|
@@ -93,6 +93,138 @@ function findInterfaceBlockRange(content, typeName) {
|
|
|
93
93
|
}
|
|
94
94
|
return null;
|
|
95
95
|
}
|
|
96
|
+
const TS_BUILTIN_TYPE_NAMES = new Set([
|
|
97
|
+
'string',
|
|
98
|
+
'number',
|
|
99
|
+
'boolean',
|
|
100
|
+
'null',
|
|
101
|
+
'undefined',
|
|
102
|
+
'void',
|
|
103
|
+
'any',
|
|
104
|
+
'unknown',
|
|
105
|
+
'never',
|
|
106
|
+
'object',
|
|
107
|
+
'Record',
|
|
108
|
+
'Array',
|
|
109
|
+
'Date',
|
|
110
|
+
'Promise',
|
|
111
|
+
'true',
|
|
112
|
+
'false',
|
|
113
|
+
]);
|
|
114
|
+
function extractTypeIdentifiers(typeExpr) {
|
|
115
|
+
if (!typeExpr)
|
|
116
|
+
return [];
|
|
117
|
+
const matches = typeExpr.match(/[A-Za-z_$][A-Za-z0-9_$]*/g) || [];
|
|
118
|
+
return [...new Set(matches.filter(name => !TS_BUILTIN_TYPE_NAMES.has(name)))];
|
|
119
|
+
}
|
|
120
|
+
function getSchemaNameFromRef(ref) {
|
|
121
|
+
if (!ref)
|
|
122
|
+
return '';
|
|
123
|
+
return ref.split('/').pop() || '';
|
|
124
|
+
}
|
|
125
|
+
function resolveSchemaTypeFromModuleSchemas(schema, moduleSchemas, visitedRefs = new Set()) {
|
|
126
|
+
if (!schema)
|
|
127
|
+
return 'any';
|
|
128
|
+
if (schema.$ref) {
|
|
129
|
+
const refName = getSchemaNameFromRef(schema.$ref);
|
|
130
|
+
return refName || 'any';
|
|
131
|
+
}
|
|
132
|
+
const schemaObj = schema;
|
|
133
|
+
if (schemaObj.anyOf && Array.isArray(schemaObj.anyOf) && schemaObj.anyOf.length > 0) {
|
|
134
|
+
const types = schemaObj.anyOf
|
|
135
|
+
.map(item => resolveSchemaTypeFromModuleSchemas(item, moduleSchemas, visitedRefs))
|
|
136
|
+
.filter(Boolean);
|
|
137
|
+
if (types.length > 0) {
|
|
138
|
+
return [...new Set(types)].join(' | ');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (schemaObj.oneOf && Array.isArray(schemaObj.oneOf) && schemaObj.oneOf.length > 0) {
|
|
142
|
+
const types = schemaObj.oneOf
|
|
143
|
+
.map(item => resolveSchemaTypeFromModuleSchemas(item, moduleSchemas, visitedRefs))
|
|
144
|
+
.filter(Boolean);
|
|
145
|
+
if (types.length > 0) {
|
|
146
|
+
return [...new Set(types)].join(' | ');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (schemaObj.type === 'array') {
|
|
150
|
+
const itemType = resolveSchemaTypeFromModuleSchemas(schemaObj.items, moduleSchemas, visitedRefs);
|
|
151
|
+
return `${itemType || 'any'}[]`;
|
|
152
|
+
}
|
|
153
|
+
if (schemaObj.type === 'object' && schemaObj.additionalProperties) {
|
|
154
|
+
if (schemaObj.additionalProperties === true) {
|
|
155
|
+
return 'Record<string, any>';
|
|
156
|
+
}
|
|
157
|
+
const valueType = resolveSchemaTypeFromModuleSchemas(schemaObj.additionalProperties, moduleSchemas, visitedRefs);
|
|
158
|
+
return `Record<string, ${valueType || 'any'}>`;
|
|
159
|
+
}
|
|
160
|
+
if (schemaObj.type === 'object' && schemaObj.properties && Object.keys(schemaObj.properties).length > 0) {
|
|
161
|
+
const requiredSet = new Set(schemaObj.required || []);
|
|
162
|
+
const inlineFields = Object.entries(schemaObj.properties).map(([key, value]) => {
|
|
163
|
+
const fieldType = resolveSchemaTypeFromModuleSchemas(value, moduleSchemas, visitedRefs);
|
|
164
|
+
const optional = requiredSet.has(key) ? '' : '?';
|
|
165
|
+
return `${key}${optional}: ${fieldType || 'any'}`;
|
|
166
|
+
});
|
|
167
|
+
return `{ ${inlineFields.join('; ')} }`;
|
|
168
|
+
}
|
|
169
|
+
const baseType = convertOpenApiTypeToTypeScript(schemaObj.type);
|
|
170
|
+
if (!baseType)
|
|
171
|
+
return 'any';
|
|
172
|
+
return schemaObj.nullable ? `${baseType} | null` : baseType;
|
|
173
|
+
}
|
|
174
|
+
function collectSchemaProperties(schema, moduleSchemas, visitedRefs = new Set()) {
|
|
175
|
+
const collected = {
|
|
176
|
+
properties: {},
|
|
177
|
+
required: new Set(),
|
|
178
|
+
};
|
|
179
|
+
if (!schema)
|
|
180
|
+
return collected;
|
|
181
|
+
if (schema.$ref) {
|
|
182
|
+
const ref = schema.$ref;
|
|
183
|
+
if (!visitedRefs.has(ref)) {
|
|
184
|
+
visitedRefs.add(ref);
|
|
185
|
+
const refName = getSchemaNameFromRef(ref);
|
|
186
|
+
const refSchema = moduleSchemas[refName];
|
|
187
|
+
if (refSchema) {
|
|
188
|
+
const nested = collectSchemaProperties(refSchema, moduleSchemas, visitedRefs);
|
|
189
|
+
Object.assign(collected.properties, nested.properties);
|
|
190
|
+
nested.required.forEach(field => collected.required.add(field));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return collected;
|
|
194
|
+
}
|
|
195
|
+
const schemaObj = schema;
|
|
196
|
+
if (schemaObj.allOf && Array.isArray(schemaObj.allOf)) {
|
|
197
|
+
schemaObj.allOf.forEach(item => {
|
|
198
|
+
const nested = collectSchemaProperties(item, moduleSchemas, visitedRefs);
|
|
199
|
+
Object.assign(collected.properties, nested.properties);
|
|
200
|
+
nested.required.forEach(field => collected.required.add(field));
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
if (schemaObj.properties) {
|
|
204
|
+
Object.entries(schemaObj.properties).forEach(([name, value]) => {
|
|
205
|
+
collected.properties[name] = value;
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
(schemaObj.required || []).forEach(field => collected.required.add(field));
|
|
209
|
+
return collected;
|
|
210
|
+
}
|
|
211
|
+
function buildInterfaceDefinitionFromModuleSchemas(typeName, moduleSchemas) {
|
|
212
|
+
const schema = moduleSchemas[typeName];
|
|
213
|
+
if (!schema)
|
|
214
|
+
return null;
|
|
215
|
+
const { properties, required } = collectSchemaProperties(schema, moduleSchemas);
|
|
216
|
+
const entries = Object.entries(properties);
|
|
217
|
+
if (entries.length === 0)
|
|
218
|
+
return null;
|
|
219
|
+
const lines = entries.map(([propName, propSchema]) => {
|
|
220
|
+
const optional = required.has(propName) ? '' : '?';
|
|
221
|
+
const propType = resolveSchemaTypeFromModuleSchemas(propSchema, moduleSchemas) || 'any';
|
|
222
|
+
const propDescription = propSchema.description || '';
|
|
223
|
+
const comment = propDescription ? ` // ${propDescription}` : '';
|
|
224
|
+
return ` ${propName}${optional}: ${propType};${comment}`;
|
|
225
|
+
});
|
|
226
|
+
return `export interface ${typeName} {\n${lines.join('\n')}\n}`;
|
|
227
|
+
}
|
|
96
228
|
function improveTypeDefinitions(typesContent, endpoints) {
|
|
97
229
|
let improvedContent = typesContent;
|
|
98
230
|
// 收集所有需要改进的类型定义
|
|
@@ -481,6 +613,7 @@ const handleBuild = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
481
613
|
console.log(chalk_1.default.blue(`为模块 "${moduleName}" 生成基于 JSDoc 的类型定义...`));
|
|
482
614
|
// 创建类型定义映射
|
|
483
615
|
const typeDefinitions = {};
|
|
616
|
+
const nestedReferencedTypes = new Set();
|
|
484
617
|
// 从 endpoints 中提取类型定义
|
|
485
618
|
module.endpoints.forEach(endpoint => {
|
|
486
619
|
// 辅助函数:将 jsdoc params 转换为字段
|
|
@@ -497,6 +630,11 @@ const handleBuild = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
497
630
|
else {
|
|
498
631
|
type = convertOpenApiTypeToTypeScript(type);
|
|
499
632
|
}
|
|
633
|
+
extractTypeIdentifiers(type).forEach(typeName => {
|
|
634
|
+
if (isValidTypeIdentifier(typeName)) {
|
|
635
|
+
nestedReferencedTypes.add(typeName);
|
|
636
|
+
}
|
|
637
|
+
});
|
|
500
638
|
const comment = param.description ? ` // ${param.description}` : '';
|
|
501
639
|
return ` ${param.name}${optional}: ${type};${comment}`;
|
|
502
640
|
})
|
|
@@ -533,11 +671,23 @@ ${responseFields}
|
|
|
533
671
|
}
|
|
534
672
|
});
|
|
535
673
|
// 为没有定义的类型添加基本定义
|
|
536
|
-
|
|
674
|
+
const fallbackReferencedTypes = [
|
|
675
|
+
...new Set([
|
|
676
|
+
...allReferencedTypes,
|
|
677
|
+
...Object.keys(module.schemas || {}),
|
|
678
|
+
...nestedReferencedTypes,
|
|
679
|
+
])
|
|
680
|
+
];
|
|
681
|
+
fallbackReferencedTypes.forEach(typeName => {
|
|
537
682
|
if (!isValidTypeIdentifier(typeName)) {
|
|
538
683
|
return;
|
|
539
684
|
}
|
|
540
685
|
if (!typeDefinitions[typeName]) {
|
|
686
|
+
const schemaBasedDefinition = buildInterfaceDefinitionFromModuleSchemas(typeName, module.schemas);
|
|
687
|
+
if (schemaBasedDefinition) {
|
|
688
|
+
typeDefinitions[typeName] = schemaBasedDefinition;
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
541
691
|
typeDefinitions[typeName] = `export interface ${typeName} {
|
|
542
692
|
[key: string]: any;
|
|
543
693
|
}`;
|
package/dist/core/parser.js
CHANGED
|
@@ -87,11 +87,68 @@ function convertOpenApiTypeToTypeScript(openApiType) {
|
|
|
87
87
|
case 'number':
|
|
88
88
|
return 'number';
|
|
89
89
|
default:
|
|
90
|
-
return
|
|
90
|
+
return openApiType;
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
|
+
function resolveSchemaToTypeScript(schema, allSchemas) {
|
|
94
|
+
if (!schema)
|
|
95
|
+
return 'any';
|
|
96
|
+
if (isReferenceObject(schema)) {
|
|
97
|
+
return getSchemaName(schema.$ref) || 'any';
|
|
98
|
+
}
|
|
99
|
+
if (schema.anyOf && Array.isArray(schema.anyOf) && schema.anyOf.length > 0) {
|
|
100
|
+
const unionTypes = schema.anyOf
|
|
101
|
+
.map(item => resolveSchemaToTypeScript(item, allSchemas))
|
|
102
|
+
.filter(Boolean);
|
|
103
|
+
if (unionTypes.length > 0) {
|
|
104
|
+
return [...new Set(unionTypes)].join(' | ');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (schema.oneOf && Array.isArray(schema.oneOf) && schema.oneOf.length > 0) {
|
|
108
|
+
const unionTypes = schema.oneOf
|
|
109
|
+
.map(item => resolveSchemaToTypeScript(item, allSchemas))
|
|
110
|
+
.filter(Boolean);
|
|
111
|
+
if (unionTypes.length > 0) {
|
|
112
|
+
return [...new Set(unionTypes)].join(' | ');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (schema.allOf && Array.isArray(schema.allOf) && schema.allOf.length > 0) {
|
|
116
|
+
const intersectionTypes = schema.allOf
|
|
117
|
+
.map(item => resolveSchemaToTypeScript(item, allSchemas))
|
|
118
|
+
.filter(Boolean);
|
|
119
|
+
if (intersectionTypes.length > 0) {
|
|
120
|
+
return [...new Set(intersectionTypes)].join(' & ');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (schema.type === 'array') {
|
|
124
|
+
const itemType = resolveSchemaToTypeScript(schema.items, allSchemas);
|
|
125
|
+
return `${itemType || 'any'}[]`;
|
|
126
|
+
}
|
|
127
|
+
if (schema.type === 'object') {
|
|
128
|
+
if (schema.properties && Object.keys(schema.properties).length > 0) {
|
|
129
|
+
const requiredSet = new Set(schema.required || []);
|
|
130
|
+
const inlineFields = Object.entries(schema.properties).map(([key, value]) => {
|
|
131
|
+
const fieldType = resolveSchemaToTypeScript(value, allSchemas);
|
|
132
|
+
const optional = requiredSet.has(key) ? '' : '?';
|
|
133
|
+
return `${key}${optional}: ${fieldType || 'any'}`;
|
|
134
|
+
});
|
|
135
|
+
return `{ ${inlineFields.join('; ')} }`;
|
|
136
|
+
}
|
|
137
|
+
if (schema.additionalProperties) {
|
|
138
|
+
if (schema.additionalProperties === true) {
|
|
139
|
+
return 'Record<string, any>';
|
|
140
|
+
}
|
|
141
|
+
const valueType = resolveSchemaToTypeScript(schema.additionalProperties, allSchemas);
|
|
142
|
+
return `Record<string, ${valueType || 'any'}>`;
|
|
143
|
+
}
|
|
144
|
+
return 'any';
|
|
145
|
+
}
|
|
146
|
+
const baseType = convertOpenApiTypeToTypeScript(schema.type);
|
|
147
|
+
const nullable = schema.nullable ? ' | null' : '';
|
|
148
|
+
return `${baseType}${nullable}`;
|
|
149
|
+
}
|
|
93
150
|
function extractJsdocParamsFromSchema(schema, allSchemas) {
|
|
94
|
-
var _a;
|
|
151
|
+
var _a, _b;
|
|
95
152
|
const params = [];
|
|
96
153
|
if (!schema)
|
|
97
154
|
return params;
|
|
@@ -106,9 +163,12 @@ function extractJsdocParamsFromSchema(schema, allSchemas) {
|
|
|
106
163
|
if (targetSchema === null || targetSchema === void 0 ? void 0 : targetSchema.properties) {
|
|
107
164
|
for (const propName in targetSchema.properties) {
|
|
108
165
|
const prop = targetSchema.properties[propName];
|
|
109
|
-
let propType =
|
|
166
|
+
let propType = resolveSchemaToTypeScript(prop, allSchemas);
|
|
167
|
+
const propDescription = isReferenceObject(prop)
|
|
168
|
+
? (((_a = allSchemas[getSchemaName(prop.$ref)]) === null || _a === void 0 ? void 0 : _a.description) || '')
|
|
169
|
+
: ((prop === null || prop === void 0 ? void 0 : prop.description) || '');
|
|
110
170
|
// 处理 anyOf 数组 (FastAPI 常用的联合类型)
|
|
111
|
-
if (prop.anyOf && Array.isArray(prop.anyOf)) {
|
|
171
|
+
if (false && prop.anyOf && Array.isArray(prop.anyOf)) {
|
|
112
172
|
const types = prop.anyOf.map(item => {
|
|
113
173
|
if (isReferenceObject(item)) {
|
|
114
174
|
return getSchemaName(item.$ref);
|
|
@@ -130,7 +190,7 @@ function extractJsdocParamsFromSchema(schema, allSchemas) {
|
|
|
130
190
|
}
|
|
131
191
|
}
|
|
132
192
|
// 处理 oneOf 数组
|
|
133
|
-
else if (prop.oneOf && Array.isArray(prop.oneOf)) {
|
|
193
|
+
else if (false && prop.oneOf && Array.isArray(prop.oneOf)) {
|
|
134
194
|
const types = prop.oneOf.map(item => {
|
|
135
195
|
if (isReferenceObject(item)) {
|
|
136
196
|
return getSchemaName(item.$ref);
|
|
@@ -152,14 +212,26 @@ function extractJsdocParamsFromSchema(schema, allSchemas) {
|
|
|
152
212
|
}
|
|
153
213
|
}
|
|
154
214
|
// 处理普通类型
|
|
155
|
-
else if (prop.type) {
|
|
156
|
-
|
|
215
|
+
else if (false && prop.type) {
|
|
216
|
+
const propSchema = prop;
|
|
217
|
+
if (propSchema.type === 'array' && propSchema.items) {
|
|
218
|
+
if (isReferenceObject(propSchema.items)) {
|
|
219
|
+
propType = `${getSchemaName(propSchema.items.$ref)}[]`;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
const itemType = convertOpenApiTypeToTypeScript(propSchema.items.type);
|
|
223
|
+
propType = `${itemType}[]`;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
propType = convertOpenApiTypeToTypeScript(propSchema.type);
|
|
228
|
+
}
|
|
157
229
|
}
|
|
158
230
|
params.push({
|
|
159
231
|
name: propName,
|
|
160
|
-
type: propType,
|
|
161
|
-
description:
|
|
162
|
-
required: (
|
|
232
|
+
type: propType || 'any',
|
|
233
|
+
description: propDescription,
|
|
234
|
+
required: (_b = targetSchema.required) === null || _b === void 0 ? void 0 : _b.includes(propName)
|
|
163
235
|
});
|
|
164
236
|
}
|
|
165
237
|
}
|
package/package.json
CHANGED
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,12 +32,12 @@ 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
|
|
39
|
-
}
|
|
40
|
-
}
|
|
35
|
+
case 'number':
|
|
36
|
+
return 'number';
|
|
37
|
+
default:
|
|
38
|
+
return openApiType;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
41
|
|
|
42
42
|
// 改进类型定义的辅助函数
|
|
43
43
|
function isValidTypeIdentifier(typeName: string | undefined): boolean {
|
|
@@ -85,6 +85,176 @@ function findInterfaceBlockRange(content: string, typeName: string): { start: nu
|
|
|
85
85
|
return null;
|
|
86
86
|
}
|
|
87
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
|
+
|
|
88
258
|
function improveTypeDefinitions(typesContent: string, endpoints: any[]): string {
|
|
89
259
|
let improvedContent = typesContent;
|
|
90
260
|
|
|
@@ -100,13 +270,13 @@ function improveTypeDefinitions(typesContent: string, endpoints: any[]): string
|
|
|
100
270
|
let type = param.type;
|
|
101
271
|
|
|
102
272
|
// 处理联合类型,确保正确的 TypeScript 语法
|
|
103
|
-
if (type && type.includes(' | ')) {
|
|
104
|
-
if (type.includes('null')) {
|
|
105
|
-
type = type.replace(/\s*\|\s*null/g, ' | null');
|
|
106
|
-
}
|
|
107
|
-
} else {
|
|
108
|
-
type = convertOpenApiTypeToTypeScript(type);
|
|
109
|
-
}
|
|
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
|
+
}
|
|
110
280
|
|
|
111
281
|
const comment = param.description ? ` // ${param.description}` : '';
|
|
112
282
|
return ` ${param.name}${optional}: ${type};${comment}`;
|
|
@@ -542,7 +712,8 @@ export const handleBuild = async () => {
|
|
|
542
712
|
console.log(chalk.blue(`为模块 "${moduleName}" 生成基于 JSDoc 的类型定义...`));
|
|
543
713
|
|
|
544
714
|
// 创建类型定义映射
|
|
545
|
-
const typeDefinitions: { [typeName: string]: string } = {};
|
|
715
|
+
const typeDefinitions: { [typeName: string]: string } = {};
|
|
716
|
+
const nestedReferencedTypes = new Set<string>();
|
|
546
717
|
|
|
547
718
|
// 从 endpoints 中提取类型定义
|
|
548
719
|
module.endpoints.forEach(endpoint => {
|
|
@@ -553,17 +724,23 @@ export const handleBuild = async () => {
|
|
|
553
724
|
const optional = !param.required ? '?' : '';
|
|
554
725
|
let type = param.type;
|
|
555
726
|
|
|
556
|
-
if (type && type.includes(' | ')) {
|
|
557
|
-
if (type.includes('null')) {
|
|
558
|
-
type = type.replace(/\s*\|\s*null/g, ' | null');
|
|
559
|
-
}
|
|
560
|
-
} else {
|
|
561
|
-
type = convertOpenApiTypeToTypeScript(type);
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
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
|
+
})
|
|
567
744
|
.join('\n');
|
|
568
745
|
|
|
569
746
|
// 处理 params 类型 - 使用 paramsJsdocParams
|
|
@@ -604,11 +781,26 @@ ${responseFields}
|
|
|
604
781
|
});
|
|
605
782
|
|
|
606
783
|
// 为没有定义的类型添加基本定义
|
|
607
|
-
|
|
784
|
+
const fallbackReferencedTypes = [
|
|
785
|
+
...new Set([
|
|
786
|
+
...allReferencedTypes,
|
|
787
|
+
...Object.keys(module.schemas || {}),
|
|
788
|
+
...nestedReferencedTypes,
|
|
789
|
+
])
|
|
790
|
+
];
|
|
791
|
+
fallbackReferencedTypes.forEach(typeName => {
|
|
608
792
|
if (!isValidTypeIdentifier(typeName)) {
|
|
609
793
|
return;
|
|
610
794
|
}
|
|
611
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
|
+
}
|
|
612
804
|
typeDefinitions[typeName] = `export interface ${typeName} {
|
|
613
805
|
[key: string]: any;
|
|
614
806
|
}`;
|
package/src/core/parser.ts
CHANGED
|
@@ -111,7 +111,7 @@ function getModuleName(path: string, pathPrefixes: Array<{ path: string; package
|
|
|
111
111
|
return parts[0] || 'default';
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
function convertOpenApiTypeToTypeScript(openApiType: string | undefined): string {
|
|
114
|
+
function convertOpenApiTypeToTypeScript(openApiType: string | undefined): string {
|
|
115
115
|
if (!openApiType) return 'any';
|
|
116
116
|
|
|
117
117
|
switch (openApiType) {
|
|
@@ -125,12 +125,88 @@ function convertOpenApiTypeToTypeScript(openApiType: string | undefined): string
|
|
|
125
125
|
return 'boolean';
|
|
126
126
|
case 'string':
|
|
127
127
|
return 'string';
|
|
128
|
-
case 'number':
|
|
129
|
-
return 'number';
|
|
130
|
-
default:
|
|
131
|
-
return
|
|
132
|
-
}
|
|
133
|
-
}
|
|
128
|
+
case 'number':
|
|
129
|
+
return 'number';
|
|
130
|
+
default:
|
|
131
|
+
return openApiType;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function resolveSchemaToTypeScript(
|
|
136
|
+
schema: OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject | undefined,
|
|
137
|
+
allSchemas: { [key: string]: any }
|
|
138
|
+
): string {
|
|
139
|
+
if (!schema) return 'any';
|
|
140
|
+
|
|
141
|
+
if (isReferenceObject(schema)) {
|
|
142
|
+
return getSchemaName(schema.$ref) || 'any';
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (schema.anyOf && Array.isArray(schema.anyOf) && schema.anyOf.length > 0) {
|
|
146
|
+
const unionTypes = schema.anyOf
|
|
147
|
+
.map(item => resolveSchemaToTypeScript(item as OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject, allSchemas))
|
|
148
|
+
.filter(Boolean);
|
|
149
|
+
if (unionTypes.length > 0) {
|
|
150
|
+
return [...new Set(unionTypes)].join(' | ');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (schema.oneOf && Array.isArray(schema.oneOf) && schema.oneOf.length > 0) {
|
|
155
|
+
const unionTypes = schema.oneOf
|
|
156
|
+
.map(item => resolveSchemaToTypeScript(item as OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject, allSchemas))
|
|
157
|
+
.filter(Boolean);
|
|
158
|
+
if (unionTypes.length > 0) {
|
|
159
|
+
return [...new Set(unionTypes)].join(' | ');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (schema.allOf && Array.isArray(schema.allOf) && schema.allOf.length > 0) {
|
|
164
|
+
const intersectionTypes = schema.allOf
|
|
165
|
+
.map(item => resolveSchemaToTypeScript(item as OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject, allSchemas))
|
|
166
|
+
.filter(Boolean);
|
|
167
|
+
if (intersectionTypes.length > 0) {
|
|
168
|
+
return [...new Set(intersectionTypes)].join(' & ');
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (schema.type === 'array') {
|
|
173
|
+
const itemType = resolveSchemaToTypeScript(
|
|
174
|
+
schema.items as OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject | undefined,
|
|
175
|
+
allSchemas
|
|
176
|
+
);
|
|
177
|
+
return `${itemType || 'any'}[]`;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (schema.type === 'object') {
|
|
181
|
+
if (schema.properties && Object.keys(schema.properties).length > 0) {
|
|
182
|
+
const requiredSet = new Set(schema.required || []);
|
|
183
|
+
const inlineFields = Object.entries(schema.properties).map(([key, value]) => {
|
|
184
|
+
const fieldType = resolveSchemaToTypeScript(
|
|
185
|
+
value as OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject,
|
|
186
|
+
allSchemas
|
|
187
|
+
);
|
|
188
|
+
const optional = requiredSet.has(key) ? '' : '?';
|
|
189
|
+
return `${key}${optional}: ${fieldType || 'any'}`;
|
|
190
|
+
});
|
|
191
|
+
return `{ ${inlineFields.join('; ')} }`;
|
|
192
|
+
}
|
|
193
|
+
if (schema.additionalProperties) {
|
|
194
|
+
if (schema.additionalProperties === true) {
|
|
195
|
+
return 'Record<string, any>';
|
|
196
|
+
}
|
|
197
|
+
const valueType = resolveSchemaToTypeScript(
|
|
198
|
+
schema.additionalProperties as OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject,
|
|
199
|
+
allSchemas
|
|
200
|
+
);
|
|
201
|
+
return `Record<string, ${valueType || 'any'}>`;
|
|
202
|
+
}
|
|
203
|
+
return 'any';
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const baseType = convertOpenApiTypeToTypeScript(schema.type);
|
|
207
|
+
const nullable = schema.nullable ? ' | null' : '';
|
|
208
|
+
return `${baseType}${nullable}`;
|
|
209
|
+
}
|
|
134
210
|
|
|
135
211
|
function extractJsdocParamsFromSchema(schema: OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject, allSchemas: { [key: string]: any }): Required<Endpoint>['jsdocParams'] {
|
|
136
212
|
const params: Required<Endpoint>['jsdocParams'] = [];
|
|
@@ -146,13 +222,15 @@ function extractJsdocParamsFromSchema(schema: OpenAPIV3.SchemaObject | OpenAPIV3
|
|
|
146
222
|
|
|
147
223
|
if (targetSchema?.properties) {
|
|
148
224
|
for (const propName in targetSchema.properties) {
|
|
149
|
-
const prop = targetSchema.properties[propName] as OpenAPIV3.SchemaObject;
|
|
150
|
-
|
|
151
|
-
|
|
225
|
+
const prop = targetSchema.properties[propName] as OpenAPIV3.SchemaObject | OpenAPIV3.ReferenceObject;
|
|
226
|
+
let propType = resolveSchemaToTypeScript(prop, allSchemas);
|
|
227
|
+
const propDescription = isReferenceObject(prop)
|
|
228
|
+
? ((allSchemas[getSchemaName(prop.$ref)] as OpenAPIV3.SchemaObject | undefined)?.description || '')
|
|
229
|
+
: (prop?.description || '');
|
|
152
230
|
|
|
153
231
|
// 处理 anyOf 数组 (FastAPI 常用的联合类型)
|
|
154
|
-
if (prop.anyOf && Array.isArray(prop.anyOf)) {
|
|
155
|
-
const types = prop.anyOf
|
|
232
|
+
if (false && (prop as OpenAPIV3.SchemaObject).anyOf && Array.isArray((prop as OpenAPIV3.SchemaObject).anyOf)) {
|
|
233
|
+
const types = (prop as OpenAPIV3.SchemaObject).anyOf!.map(item => {
|
|
156
234
|
if (isReferenceObject(item)) {
|
|
157
235
|
return getSchemaName(item.$ref);
|
|
158
236
|
} else {
|
|
@@ -173,8 +251,8 @@ function extractJsdocParamsFromSchema(schema: OpenAPIV3.SchemaObject | OpenAPIV3
|
|
|
173
251
|
}
|
|
174
252
|
}
|
|
175
253
|
// 处理 oneOf 数组
|
|
176
|
-
else if (prop.oneOf && Array.isArray(prop.oneOf)) {
|
|
177
|
-
const types = prop.oneOf
|
|
254
|
+
else if (false && (prop as OpenAPIV3.SchemaObject).oneOf && Array.isArray((prop as OpenAPIV3.SchemaObject).oneOf)) {
|
|
255
|
+
const types = (prop as OpenAPIV3.SchemaObject).oneOf!.map(item => {
|
|
178
256
|
if (isReferenceObject(item)) {
|
|
179
257
|
return getSchemaName(item.$ref);
|
|
180
258
|
} else {
|
|
@@ -195,16 +273,26 @@ function extractJsdocParamsFromSchema(schema: OpenAPIV3.SchemaObject | OpenAPIV3
|
|
|
195
273
|
}
|
|
196
274
|
}
|
|
197
275
|
// 处理普通类型
|
|
198
|
-
else if (prop.type) {
|
|
199
|
-
|
|
200
|
-
|
|
276
|
+
else if (false && (prop as OpenAPIV3.SchemaObject).type) {
|
|
277
|
+
const propSchema: any = prop as any;
|
|
278
|
+
if (propSchema.type === 'array' && propSchema.items) {
|
|
279
|
+
if (isReferenceObject(propSchema.items)) {
|
|
280
|
+
propType = `${getSchemaName(propSchema.items.$ref)}[]`;
|
|
281
|
+
} else {
|
|
282
|
+
const itemType = convertOpenApiTypeToTypeScript((propSchema.items as OpenAPIV3.SchemaObject).type);
|
|
283
|
+
propType = `${itemType}[]`;
|
|
284
|
+
}
|
|
285
|
+
} else {
|
|
286
|
+
propType = convertOpenApiTypeToTypeScript(propSchema.type);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
201
289
|
|
|
202
|
-
params.push({
|
|
203
|
-
name: propName,
|
|
204
|
-
type: propType,
|
|
205
|
-
description:
|
|
206
|
-
required: targetSchema.required?.includes(propName)
|
|
207
|
-
});
|
|
290
|
+
params.push({
|
|
291
|
+
name: propName,
|
|
292
|
+
type: propType || 'any',
|
|
293
|
+
description: propDescription,
|
|
294
|
+
required: targetSchema.required?.includes(propName)
|
|
295
|
+
});
|
|
208
296
|
}
|
|
209
297
|
}
|
|
210
298
|
return params;
|