swagger2api-v3 1.1.7 → 1.1.9
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/README.md +19 -5
- package/dist/.swagger2api.schema.json +120 -0
- package/dist/cli/index.js +119 -47
- package/dist/config/validator.d.ts +7 -0
- package/dist/config/validator.js +218 -0
- package/dist/core/generator.d.ts +7 -1
- package/dist/core/generator.js +40 -56
- package/dist/core/parser.d.ts +21 -1
- package/dist/core/parser.js +86 -77
- package/dist/index.d.ts +6 -0
- package/dist/index.js +21 -13
- package/dist/types/index.d.ts +79 -38
- package/dist/utils/comment.d.ts +23 -0
- package/dist/utils/comment.js +47 -0
- package/dist/utils/file.d.ts +23 -0
- package/dist/utils/file.js +98 -0
- package/dist/utils/index.d.ts +4 -99
- package/dist/utils/index.js +6 -566
- package/dist/utils/naming.d.ts +51 -0
- package/dist/utils/naming.js +124 -0
- package/dist/utils/type.d.ts +41 -0
- package/dist/utils/type.js +304 -0
- package/package.json +7 -6
package/dist/core/generator.js
CHANGED
|
@@ -35,7 +35,10 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.CodeGenerator = void 0;
|
|
37
37
|
const path = __importStar(require("path"));
|
|
38
|
+
const child_process_1 = require("child_process");
|
|
39
|
+
const util_1 = require("util");
|
|
38
40
|
const utils_1 = require("../utils");
|
|
41
|
+
const execPromise = (0, util_1.promisify)(child_process_1.exec);
|
|
39
42
|
/**
|
|
40
43
|
* 代码生成器
|
|
41
44
|
*/
|
|
@@ -95,13 +98,12 @@ class CodeGenerator {
|
|
|
95
98
|
* @returns 类型文件内容
|
|
96
99
|
*/
|
|
97
100
|
generateTypesContent(types) {
|
|
98
|
-
const header = [
|
|
101
|
+
const header = this.generateHeader([
|
|
99
102
|
'/**',
|
|
100
103
|
' * API 类型定义',
|
|
101
104
|
' * 此文件由 swagger2api-v3 自动生成,请勿手动修改',
|
|
102
|
-
' */'
|
|
103
|
-
|
|
104
|
-
].join('\n');
|
|
105
|
+
' */'
|
|
106
|
+
]);
|
|
105
107
|
const typeDefinitions = types
|
|
106
108
|
.map((type) => {
|
|
107
109
|
const comment = type.description
|
|
@@ -118,7 +120,7 @@ class CodeGenerator {
|
|
|
118
120
|
return `${comment}${definition}`;
|
|
119
121
|
})
|
|
120
122
|
.join('\n\n');
|
|
121
|
-
return `${header}${typeDefinitions}\n`;
|
|
123
|
+
return `${header}\n\n${typeDefinitions}\n`;
|
|
122
124
|
}
|
|
123
125
|
/**
|
|
124
126
|
* 按标签生成API文件
|
|
@@ -158,11 +160,12 @@ class CodeGenerator {
|
|
|
158
160
|
generateApiFileContent(apis, types, tag) {
|
|
159
161
|
const importTemplate = this.config.importTemplate || "import { request } from '@/utils'";
|
|
160
162
|
const header = [
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
163
|
+
this.generateHeader([
|
|
164
|
+
'/**',
|
|
165
|
+
` * ${tag ? `${tag} ` : ''}API 接口`,
|
|
166
|
+
' * 此文件由 swagger2api-v3 自动生成,请勿手动修改',
|
|
167
|
+
' */'
|
|
168
|
+
]),
|
|
166
169
|
importTemplate + ';'
|
|
167
170
|
];
|
|
168
171
|
// 收集当前文件实际使用的类型
|
|
@@ -233,7 +236,7 @@ class CodeGenerator {
|
|
|
233
236
|
}
|
|
234
237
|
/**
|
|
235
238
|
* 生成直接参数形式
|
|
236
|
-
* @param parameters
|
|
239
|
+
* @param parameters OpenAPI 参数数组
|
|
237
240
|
* @returns 函数参数字符串
|
|
238
241
|
*/
|
|
239
242
|
generateDirectParameters(parameters, isJavaScript = false) {
|
|
@@ -241,7 +244,6 @@ class CodeGenerator {
|
|
|
241
244
|
const queryParams = parameters.filter((p) => p.in === 'query');
|
|
242
245
|
const pathParams = parameters.filter((p) => p.in === 'path');
|
|
243
246
|
const bodyParams = parameters.filter((p) => p.in === 'body');
|
|
244
|
-
const formParams = parameters.filter((p) => p.in === 'formData');
|
|
245
247
|
// 合并路径参数和查询参数为一个params对象
|
|
246
248
|
const allParams = [...pathParams, ...queryParams];
|
|
247
249
|
if (allParams.length > 0) {
|
|
@@ -274,21 +276,6 @@ class CodeGenerator {
|
|
|
274
276
|
params.push(`data: ${bodyType}`);
|
|
275
277
|
}
|
|
276
278
|
}
|
|
277
|
-
// 表单参数
|
|
278
|
-
if (formParams.length > 0) {
|
|
279
|
-
if (isJavaScript) {
|
|
280
|
-
params.push('data');
|
|
281
|
-
}
|
|
282
|
-
else {
|
|
283
|
-
const formType = formParams
|
|
284
|
-
.map((p) => {
|
|
285
|
-
const optional = p.required ? '' : '?';
|
|
286
|
-
return `${p.name}${optional}: ${p.type}`;
|
|
287
|
-
})
|
|
288
|
-
.join(', ');
|
|
289
|
-
params.push(`data: { ${formType} }`);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
279
|
// 添加可选的config参数
|
|
293
280
|
params.push(isJavaScript ? 'config' : 'config?: any');
|
|
294
281
|
return params.join(', ');
|
|
@@ -299,9 +286,6 @@ class CodeGenerator {
|
|
|
299
286
|
* @returns 类型字符串
|
|
300
287
|
*/
|
|
301
288
|
getTypeFromSchema(schema) {
|
|
302
|
-
if (schema.$ref) {
|
|
303
|
-
return schema.$ref.split('/').pop() || 'any';
|
|
304
|
-
}
|
|
305
289
|
return (0, utils_1.swaggerTypeToTsType)(schema);
|
|
306
290
|
}
|
|
307
291
|
/**
|
|
@@ -395,7 +379,7 @@ class CodeGenerator {
|
|
|
395
379
|
// 检查是否包含 data 字段且类型为 Record<string, any>
|
|
396
380
|
const hasDataField = definition.includes('data: Record<string, any>;');
|
|
397
381
|
// 检查是否包含其他常见的响应容器字段
|
|
398
|
-
const hasCommonFields = ['code', 'message', 'success', 'status'].some((field) =>
|
|
382
|
+
const hasCommonFields = ['code', 'message', 'success', 'status'].some((field) => new RegExp(`\\b${field}\\??:`).test(definition));
|
|
399
383
|
return hasDataField && hasCommonFields;
|
|
400
384
|
}
|
|
401
385
|
/**
|
|
@@ -430,13 +414,9 @@ class CodeGenerator {
|
|
|
430
414
|
}
|
|
431
415
|
// 请求体数据
|
|
432
416
|
const bodyParams = api.parameters.filter((p) => p.in === 'body');
|
|
433
|
-
const formParams = api.parameters.filter((p) => p.in === 'formData');
|
|
434
417
|
if (bodyParams.length > 0) {
|
|
435
418
|
config.push('data');
|
|
436
419
|
}
|
|
437
|
-
else if (formParams.length > 0) {
|
|
438
|
-
config.push('data');
|
|
439
|
-
}
|
|
440
420
|
// 在通用请求风格下添加 method 字段
|
|
441
421
|
if (includeMethod) {
|
|
442
422
|
config.push(`method: '${api.method}'`);
|
|
@@ -456,26 +436,20 @@ class CodeGenerator {
|
|
|
456
436
|
this.config.options?.generateModels !== false) {
|
|
457
437
|
exports.push("export * from './types';");
|
|
458
438
|
}
|
|
459
|
-
if (this.config.
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
const
|
|
463
|
-
|
|
439
|
+
if (this.config.options?.generateApis !== false) {
|
|
440
|
+
if (this.config.groupByTags) {
|
|
441
|
+
// 按标签导出
|
|
442
|
+
for (const tag of groupedApis.keys()) {
|
|
443
|
+
const folderName = this.getTagFileName(tag);
|
|
444
|
+
exports.push(`export * from './${folderName}';`);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
else {
|
|
448
|
+
// 导出单个API文件
|
|
449
|
+
exports.push("export * from './api';");
|
|
464
450
|
}
|
|
465
451
|
}
|
|
466
|
-
|
|
467
|
-
// 导出单个API文件
|
|
468
|
-
exports.push("export * from './api';");
|
|
469
|
-
}
|
|
470
|
-
const content = [
|
|
471
|
-
'/**',
|
|
472
|
-
' * API 入口文件',
|
|
473
|
-
' * 此文件由 swagger2api-v3 自动生成,请勿手动修改',
|
|
474
|
-
' */',
|
|
475
|
-
'',
|
|
476
|
-
...exports,
|
|
477
|
-
''
|
|
478
|
-
].join('\n');
|
|
452
|
+
const content = [this.generateHeader(), '', ...exports, ''].join('\n');
|
|
479
453
|
const ext = this.config.generator === 'javascript' ? 'js' : 'ts';
|
|
480
454
|
const filePath = path.join(this.config.output, `index.${ext}`);
|
|
481
455
|
(0, utils_1.writeFile)(filePath, content);
|
|
@@ -498,6 +472,19 @@ class CodeGenerator {
|
|
|
498
472
|
return (0, utils_1.toCamelCase)(cleanTag);
|
|
499
473
|
}
|
|
500
474
|
}
|
|
475
|
+
/**
|
|
476
|
+
* 生成文件头部注释
|
|
477
|
+
* @param defaultHeader 默认头部注释
|
|
478
|
+
* @returns 文件头部注释内容
|
|
479
|
+
*/
|
|
480
|
+
generateHeader(defaultHeader = [
|
|
481
|
+
'/**',
|
|
482
|
+
' * API 入口文件',
|
|
483
|
+
' * 此文件由 swagger2api-v3 自动生成,请勿手动修改',
|
|
484
|
+
' */'
|
|
485
|
+
]) {
|
|
486
|
+
return this.config.headerComment?.trim() || defaultHeader.join('\n');
|
|
487
|
+
}
|
|
501
488
|
/**
|
|
502
489
|
* 在所有文件生成完成后运行lint命令
|
|
503
490
|
*/
|
|
@@ -505,9 +492,6 @@ class CodeGenerator {
|
|
|
505
492
|
if (!this.config.lint)
|
|
506
493
|
return;
|
|
507
494
|
try {
|
|
508
|
-
const { exec } = require('child_process');
|
|
509
|
-
const util = require('util');
|
|
510
|
-
const execPromise = util.promisify(exec);
|
|
511
495
|
console.log(`🎨 Running lint command: ${this.config.lint} ${this.config.output}`);
|
|
512
496
|
const result = await execPromise(`${this.config.lint} ${this.config.output}`);
|
|
513
497
|
if (result.stdout) {
|
package/dist/core/parser.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export declare class SwaggerParser {
|
|
|
7
7
|
private config;
|
|
8
8
|
constructor(document: SwaggerDocument, config: SwaggerConfig);
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* 获取 OpenAPI components.schemas
|
|
11
11
|
* @returns schemas 对象
|
|
12
12
|
*/
|
|
13
13
|
private getAllSchemas;
|
|
@@ -37,6 +37,20 @@ export declare class SwaggerParser {
|
|
|
37
37
|
* @returns 类型信息
|
|
38
38
|
*/
|
|
39
39
|
private parseTypeDefinition;
|
|
40
|
+
/**
|
|
41
|
+
* 获取枚举成员名称
|
|
42
|
+
* @param schema 枚举 schema
|
|
43
|
+
* @param value 枚举值
|
|
44
|
+
* @param index 枚举值索引
|
|
45
|
+
* @returns 枚举成员名称
|
|
46
|
+
*/
|
|
47
|
+
private getEnumMemberName;
|
|
48
|
+
/**
|
|
49
|
+
* 解析本地 $ref 引用对象
|
|
50
|
+
* @param value 可能带有 $ref 的对象
|
|
51
|
+
* @returns 引用解析后的对象
|
|
52
|
+
*/
|
|
53
|
+
private resolveReference;
|
|
40
54
|
/**
|
|
41
55
|
* 按标签分组API
|
|
42
56
|
* @param apis API接口数组
|
|
@@ -53,6 +67,12 @@ export declare class SwaggerParser {
|
|
|
53
67
|
* @returns 基础URL字符串
|
|
54
68
|
*/
|
|
55
69
|
getBaseUrl(): string;
|
|
70
|
+
/**
|
|
71
|
+
* 解析 OpenAPI server 地址
|
|
72
|
+
* @param server OpenAPI server 对象
|
|
73
|
+
* @returns 替换默认变量后的 server URL
|
|
74
|
+
*/
|
|
75
|
+
private resolveServerUrl;
|
|
56
76
|
/**
|
|
57
77
|
* 获取API文档信息
|
|
58
78
|
* @returns API文档基本信息
|
package/dist/core/parser.js
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SwaggerParser = void 0;
|
|
4
4
|
const utils_1 = require("../utils");
|
|
5
|
+
const HTTP_METHODS = [
|
|
6
|
+
'get',
|
|
7
|
+
'post',
|
|
8
|
+
'put',
|
|
9
|
+
'delete',
|
|
10
|
+
'patch',
|
|
11
|
+
'head',
|
|
12
|
+
'options'
|
|
13
|
+
];
|
|
5
14
|
/**
|
|
6
15
|
* Swagger文档解析器
|
|
7
16
|
*/
|
|
@@ -11,14 +20,11 @@ class SwaggerParser {
|
|
|
11
20
|
this.config = config;
|
|
12
21
|
}
|
|
13
22
|
/**
|
|
14
|
-
*
|
|
23
|
+
* 获取 OpenAPI components.schemas
|
|
15
24
|
* @returns schemas 对象
|
|
16
25
|
*/
|
|
17
26
|
getAllSchemas() {
|
|
18
|
-
return {
|
|
19
|
-
...(this.document.definitions || {}),
|
|
20
|
-
...(this.document.components?.schemas || {})
|
|
21
|
-
};
|
|
27
|
+
return this.document.components?.schemas || {};
|
|
22
28
|
}
|
|
23
29
|
/**
|
|
24
30
|
* 解析所有API接口
|
|
@@ -28,16 +34,7 @@ class SwaggerParser {
|
|
|
28
34
|
const apis = [];
|
|
29
35
|
const paths = this.document.paths;
|
|
30
36
|
for (const [path, pathItem] of Object.entries(paths)) {
|
|
31
|
-
const
|
|
32
|
-
'get',
|
|
33
|
-
'post',
|
|
34
|
-
'put',
|
|
35
|
-
'delete',
|
|
36
|
-
'patch',
|
|
37
|
-
'head',
|
|
38
|
-
'options'
|
|
39
|
-
];
|
|
40
|
-
for (const method of methods) {
|
|
37
|
+
for (const method of HTTP_METHODS) {
|
|
41
38
|
const operation = pathItem[method];
|
|
42
39
|
if (!operation)
|
|
43
40
|
continue;
|
|
@@ -60,22 +57,20 @@ class SwaggerParser {
|
|
|
60
57
|
const allParameters = [
|
|
61
58
|
...(globalParameters || []),
|
|
62
59
|
...(operation.parameters || [])
|
|
63
|
-
];
|
|
60
|
+
].map((parameter) => this.resolveReference(parameter));
|
|
64
61
|
// 处理 OpenAPI 3.0 requestBody
|
|
65
62
|
if (operation.requestBody) {
|
|
66
|
-
const requestBody = operation.requestBody;
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
allParameters.push(bodyParam);
|
|
78
|
-
}
|
|
63
|
+
const requestBody = this.resolveReference(operation.requestBody);
|
|
64
|
+
const schema = (0, utils_1.getSchemaFromContent)(requestBody.content);
|
|
65
|
+
if (schema) {
|
|
66
|
+
const bodyParam = {
|
|
67
|
+
name: 'body',
|
|
68
|
+
in: 'body',
|
|
69
|
+
required: requestBody.required || false,
|
|
70
|
+
schema,
|
|
71
|
+
type: 'object'
|
|
72
|
+
};
|
|
73
|
+
allParameters.push(bodyParam);
|
|
79
74
|
}
|
|
80
75
|
}
|
|
81
76
|
// 生成函数名
|
|
@@ -99,24 +94,22 @@ class SwaggerParser {
|
|
|
99
94
|
// 应用前缀忽略规则
|
|
100
95
|
functionName = (0, utils_1.stripMethodNamePrefixes)(functionName, this.config.methodNameIgnorePrefix);
|
|
101
96
|
// 获取响应类型
|
|
102
|
-
const responseType = (0, utils_1.getResponseType)(operation.responses);
|
|
97
|
+
const responseType = (0, utils_1.getResponseType)(operation.responses, this.getAllSchemas());
|
|
103
98
|
// 获取请求体类型
|
|
104
99
|
const bodyParam = allParameters.find((p) => p.in === 'body');
|
|
105
|
-
const requestBodyType = bodyParam
|
|
100
|
+
const requestBodyType = bodyParam?.schema
|
|
106
101
|
? (0, utils_1.swaggerTypeToTsType)(bodyParam.schema)
|
|
107
102
|
: undefined;
|
|
108
103
|
// 解析参数信息
|
|
109
104
|
const parameters = allParameters.map((param) => {
|
|
110
|
-
const type = param.
|
|
111
|
-
? (0, utils_1.swaggerTypeToTsType)(param.schema)
|
|
112
|
-
: (0, utils_1.swaggerTypeToTsType)({ type: param.type || 'string' });
|
|
105
|
+
const type = (0, utils_1.swaggerTypeToTsType)((0, utils_1.swaggerParameterToSchema)(param), this.getAllSchemas());
|
|
113
106
|
return {
|
|
114
107
|
name: param.name,
|
|
115
108
|
type,
|
|
116
109
|
in: param.in,
|
|
117
110
|
required: param.required || false,
|
|
118
111
|
description: param.description,
|
|
119
|
-
schema: param
|
|
112
|
+
schema: (0, utils_1.swaggerParameterToSchema)(param)
|
|
120
113
|
};
|
|
121
114
|
});
|
|
122
115
|
return {
|
|
@@ -138,7 +131,6 @@ class SwaggerParser {
|
|
|
138
131
|
const types = [];
|
|
139
132
|
// Debug log
|
|
140
133
|
console.log('解析类型定义...');
|
|
141
|
-
console.log('Has definitions:', !!this.document.definitions);
|
|
142
134
|
console.log('Has components:', !!this.document.components);
|
|
143
135
|
if (this.document.components) {
|
|
144
136
|
console.log('Has schemas:', !!this.document.components.schemas);
|
|
@@ -146,15 +138,7 @@ class SwaggerParser {
|
|
|
146
138
|
console.log('Schema keys:', Object.keys(this.document.components.schemas));
|
|
147
139
|
}
|
|
148
140
|
}
|
|
149
|
-
// 解析
|
|
150
|
-
if (this.document.definitions) {
|
|
151
|
-
for (const [name, schema] of Object.entries(this.document.definitions)) {
|
|
152
|
-
const sanitizedName = (0, utils_1.sanitizeTypeName)(name); // Use it
|
|
153
|
-
const typeInfo = this.parseTypeDefinition(sanitizedName, schema);
|
|
154
|
-
types.push(typeInfo);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
// 解析 OpenAPI 3.0 components.schemas
|
|
141
|
+
// 解析 OpenAPI 3.x components.schemas
|
|
158
142
|
if (this.document.components?.schemas) {
|
|
159
143
|
for (const [name, schema] of Object.entries(this.document.components.schemas)) {
|
|
160
144
|
const sanitizedName = (0, utils_1.sanitizeTypeName)(name); // Use it
|
|
@@ -194,28 +178,14 @@ class SwaggerParser {
|
|
|
194
178
|
else if (schema.type === 'array') {
|
|
195
179
|
// 数组类型 - 生成指向 items 类型的别名(不带 [])
|
|
196
180
|
// 在引用时会自动添加 []
|
|
197
|
-
const itemType = (0, utils_1.swaggerTypeToTsType)(schema.items, allSchemas);
|
|
181
|
+
const itemType = (0, utils_1.swaggerTypeToTsType)(schema.items || {}, allSchemas);
|
|
198
182
|
definition = `export type ${typeName} = ${itemType};`;
|
|
199
183
|
}
|
|
200
184
|
else if (schema.enum) {
|
|
201
185
|
// 枚举类型
|
|
202
186
|
const enumValues = schema.enum
|
|
203
187
|
.map((value, index) => {
|
|
204
|
-
|
|
205
|
-
// 优先使用 x-enum-varnames 或 x-enumNames 扩展字段
|
|
206
|
-
if ((schema['x-enum-varnames'] && schema['x-enum-varnames'][index]) ||
|
|
207
|
-
(schema['x-enumNames'] && schema['x-enumNames'][index])) {
|
|
208
|
-
key =
|
|
209
|
-
schema['x-enum-varnames']?.[index] ||
|
|
210
|
-
schema['x-enumNames']?.[index];
|
|
211
|
-
}
|
|
212
|
-
else if (/^\d+$/.test(value)) {
|
|
213
|
-
// 对于数字枚举,使用 VALUE_ 前缀
|
|
214
|
-
key = `VALUE_${value}`;
|
|
215
|
-
}
|
|
216
|
-
else {
|
|
217
|
-
key = value.toUpperCase();
|
|
218
|
-
}
|
|
188
|
+
const key = this.getEnumMemberName(schema, value, index);
|
|
219
189
|
return ` ${key} = '${value}'`;
|
|
220
190
|
})
|
|
221
191
|
.join(',\n');
|
|
@@ -232,6 +202,43 @@ class SwaggerParser {
|
|
|
232
202
|
description: schema.description
|
|
233
203
|
};
|
|
234
204
|
}
|
|
205
|
+
/**
|
|
206
|
+
* 获取枚举成员名称
|
|
207
|
+
* @param schema 枚举 schema
|
|
208
|
+
* @param value 枚举值
|
|
209
|
+
* @param index 枚举值索引
|
|
210
|
+
* @returns 枚举成员名称
|
|
211
|
+
*/
|
|
212
|
+
getEnumMemberName(schema, value, index) {
|
|
213
|
+
const extensionName = schema['x-enum-varnames']?.[index] || schema['x-enumNames']?.[index];
|
|
214
|
+
if (extensionName) {
|
|
215
|
+
return extensionName;
|
|
216
|
+
}
|
|
217
|
+
const strValue = String(value);
|
|
218
|
+
if (/^\d+$/.test(strValue)) {
|
|
219
|
+
return `VALUE_${strValue}`;
|
|
220
|
+
}
|
|
221
|
+
return strValue.toUpperCase();
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* 解析本地 $ref 引用对象
|
|
225
|
+
* @param value 可能带有 $ref 的对象
|
|
226
|
+
* @returns 引用解析后的对象
|
|
227
|
+
*/
|
|
228
|
+
resolveReference(value) {
|
|
229
|
+
if (!value || !value.$ref) {
|
|
230
|
+
return value;
|
|
231
|
+
}
|
|
232
|
+
const refPath = value.$ref.replace(/^#\//, '').split('/');
|
|
233
|
+
let current = this.document;
|
|
234
|
+
for (const segment of refPath) {
|
|
235
|
+
current = current?.[segment];
|
|
236
|
+
if (!current) {
|
|
237
|
+
return value;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return current;
|
|
241
|
+
}
|
|
235
242
|
/**
|
|
236
243
|
* 按标签分组API
|
|
237
244
|
* @param apis API接口数组
|
|
@@ -262,16 +269,7 @@ class SwaggerParser {
|
|
|
262
269
|
}
|
|
263
270
|
// 从路径操作中获取
|
|
264
271
|
for (const pathItem of Object.values(this.document.paths)) {
|
|
265
|
-
const
|
|
266
|
-
'get',
|
|
267
|
-
'post',
|
|
268
|
-
'put',
|
|
269
|
-
'delete',
|
|
270
|
-
'patch',
|
|
271
|
-
'head',
|
|
272
|
-
'options'
|
|
273
|
-
];
|
|
274
|
-
for (const method of methods) {
|
|
272
|
+
for (const method of HTTP_METHODS) {
|
|
275
273
|
const operation = pathItem[method];
|
|
276
274
|
if (operation?.tags) {
|
|
277
275
|
operation.tags.forEach((tag) => tags.add(tag));
|
|
@@ -285,12 +283,23 @@ class SwaggerParser {
|
|
|
285
283
|
* @returns 基础URL字符串
|
|
286
284
|
*/
|
|
287
285
|
getBaseUrl() {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
286
|
+
const server = this.document.servers?.[0];
|
|
287
|
+
if (!server)
|
|
288
|
+
return '';
|
|
289
|
+
return this.resolveServerUrl(server);
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* 解析 OpenAPI server 地址
|
|
293
|
+
* @param server OpenAPI server 对象
|
|
294
|
+
* @returns 替换默认变量后的 server URL
|
|
295
|
+
*/
|
|
296
|
+
resolveServerUrl(server) {
|
|
297
|
+
if (!server.variables)
|
|
298
|
+
return server.url;
|
|
299
|
+
return server.url.replace(/\{([^}]+)\}/g, (match, name) => {
|
|
300
|
+
const variable = server.variables?.[name];
|
|
301
|
+
return variable?.default ?? match;
|
|
302
|
+
});
|
|
294
303
|
}
|
|
295
304
|
/**
|
|
296
305
|
* 获取API文档信息
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -44,6 +44,7 @@ const fs = __importStar(require("fs"));
|
|
|
44
44
|
const parser_1 = require("./core/parser");
|
|
45
45
|
const generator_1 = require("./core/generator");
|
|
46
46
|
const utils_1 = require("./utils");
|
|
47
|
+
const validator_1 = require("./config/validator");
|
|
47
48
|
/**
|
|
48
49
|
* Swagger2API 主类
|
|
49
50
|
*/
|
|
@@ -69,7 +70,7 @@ class Swagger2API {
|
|
|
69
70
|
// 2. 解析文档
|
|
70
71
|
console.log('🔍 解析API接口...');
|
|
71
72
|
const parser = new parser_1.SwaggerParser(document, this.config);
|
|
72
|
-
const apis = parser.parseApis();
|
|
73
|
+
const apis = this.filterApis(parser.parseApis());
|
|
73
74
|
const types = parser.parseTypes();
|
|
74
75
|
const groupedApis = parser.groupApisByTags(apis);
|
|
75
76
|
console.log(`✅ 解析完成: ${apis.length} 个接口, ${types.length} 个类型`);
|
|
@@ -94,18 +95,7 @@ class Swagger2API {
|
|
|
94
95
|
* 验证配置
|
|
95
96
|
*/
|
|
96
97
|
validateConfig() {
|
|
97
|
-
const errors =
|
|
98
|
-
if (!this.config.input) {
|
|
99
|
-
errors.push('input 配置项不能为空');
|
|
100
|
-
}
|
|
101
|
-
if (!this.config.output) {
|
|
102
|
-
errors.push('output 配置项不能为空');
|
|
103
|
-
}
|
|
104
|
-
// 支持 typescript 与 javascript 两种生成器
|
|
105
|
-
if (this.config.generator !== 'typescript' &&
|
|
106
|
-
this.config.generator !== 'javascript') {
|
|
107
|
-
errors.push('目前只支持 typescript 或 javascript 生成器');
|
|
108
|
-
}
|
|
98
|
+
const errors = (0, validator_1.validateSwaggerConfig)(this.config);
|
|
109
99
|
if (errors.length > 0) {
|
|
110
100
|
console.error('❌ 配置验证失败:');
|
|
111
101
|
errors.forEach((error) => console.error(` - ${error}`));
|
|
@@ -113,6 +103,24 @@ class Swagger2API {
|
|
|
113
103
|
}
|
|
114
104
|
return true;
|
|
115
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* 根据配置过滤 API
|
|
108
|
+
* @param apis API接口数组
|
|
109
|
+
* @returns 过滤后的 API接口数组
|
|
110
|
+
*/
|
|
111
|
+
filterApis(apis) {
|
|
112
|
+
const includeTags = this.config.filter?.include?.tags;
|
|
113
|
+
const excludeTags = this.config.filter?.exclude?.tags;
|
|
114
|
+
if (!includeTags?.length && !excludeTags?.length) {
|
|
115
|
+
return apis;
|
|
116
|
+
}
|
|
117
|
+
return apis.filter((api) => {
|
|
118
|
+
const tags = api.tags || [];
|
|
119
|
+
const included = !includeTags?.length || tags.some((tag) => includeTags.includes(tag));
|
|
120
|
+
const excluded = !!excludeTags?.length && tags.some((tag) => excludeTags.includes(tag));
|
|
121
|
+
return included && !excluded;
|
|
122
|
+
});
|
|
123
|
+
}
|
|
116
124
|
}
|
|
117
125
|
exports.Swagger2API = Swagger2API;
|
|
118
126
|
/**
|