swagger2api-v3 1.1.10 → 1.1.11
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 +4 -4
- package/dist/.swagger2api.schema.json +2 -2
- package/dist/cli/index.js +2 -2
- package/dist/config/validator.js +92 -9
- package/dist/core/generator.d.ts +71 -17
- package/dist/core/generator.js +261 -106
- package/dist/core/parser.d.ts +14 -16
- package/dist/core/parser.js +32 -90
- package/dist/core/query-parameter-generator.d.ts +26 -0
- package/dist/core/query-parameter-generator.js +114 -0
- package/dist/core/type-generator.d.ts +73 -0
- package/dist/core/type-generator.js +215 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -3
- package/dist/types/index.d.ts +27 -6
- package/dist/utils/comment.d.ts +4 -1
- package/dist/utils/comment.js +6 -2
- package/dist/utils/file.d.ts +10 -3
- package/dist/utils/file.js +48 -19
- package/dist/utils/naming.js +3 -2
- package/dist/utils/schema.d.ts +79 -0
- package/dist/utils/schema.js +536 -0
- package/dist/utils/type.d.ts +7 -37
- package/dist/utils/type.js +29 -260
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
English | [中文](./README_CN.md)
|
|
4
4
|
|
|
5
|
-
A powerful command-line tool for automatically generating TypeScript or JavaScript interface code from OpenAPI 3.
|
|
5
|
+
A powerful command-line tool for automatically generating TypeScript or JavaScript interface code from OpenAPI 3.0 documentation.
|
|
6
6
|
|
|
7
7
|
## ✨ Features
|
|
8
8
|
|
|
9
|
-
- 🚀 **Fast Generation** - Quickly generate TypeScript interface code from OpenAPI
|
|
9
|
+
- 🚀 **Fast Generation** - Quickly generate TypeScript interface code from OpenAPI 3.0 JSON or YAML
|
|
10
10
|
- 📁 **Smart Grouping** - Support automatic file grouping by document tags
|
|
11
11
|
- 📝 **Detailed Comments** - Automatically generate detailed comments including descriptions, parameters, and return values
|
|
12
12
|
- 🎨 **Code Formatting** - Support custom formatting commands
|
|
@@ -76,11 +76,11 @@ npx swagger2api-v3 generate
|
|
|
76
76
|
| Option | Type | Default | Description |
|
|
77
77
|
| ------------------------ | --------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
78
78
|
| `$schema` | string | - | Local JSON Schema path for editor completion. The default points to `node_modules/swagger2api-v3/dist/.swagger2api.schema.json` |
|
|
79
|
-
| `input` | string | - | OpenAPI
|
|
79
|
+
| `input` | string | - | OpenAPI 3.0 JSON/YAML file path or URL; local and remote external `$ref` references are bundled automatically |
|
|
80
80
|
| `output` | string | `'./src/api'` | Output directory for generated code |
|
|
81
81
|
| `generator` | string | `'typescript'` | Code generator type. Supports `'typescript'` and `'javascript'`. `'javascript'` outputs `.js` files and skips type file generation |
|
|
82
82
|
| `groupByTags` | boolean | `true` | Whether to group files by tags |
|
|
83
|
-
| `multiTagStrategy` | 'first' \| 'all' | `'first'` | Grouping strategy for operations with multiple tags. `first` uses only the first tag, `all` combines all tags into one group name
|
|
83
|
+
| `multiTagStrategy` | 'first' \| 'all' | `'first'` | Grouping strategy for operations with multiple tags. `first` uses only the first tag, `all` combines all tags into one group name |
|
|
84
84
|
| `overwrite` | boolean | `true` | Whether to overwrite existing files |
|
|
85
85
|
| `prefix` | string | `''` | Common prefix for API paths |
|
|
86
86
|
| `importTemplate` | string | - | Import statement template for request function |
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
},
|
|
11
11
|
"input": {
|
|
12
12
|
"type": "string",
|
|
13
|
-
"description": "OpenAPI JSON 文件路径或 URL"
|
|
13
|
+
"description": "OpenAPI 3.0 JSON/YAML 文件路径或 URL"
|
|
14
14
|
},
|
|
15
15
|
"output": {
|
|
16
16
|
"type": "string",
|
|
17
|
-
"description": "
|
|
17
|
+
"description": "生成代码输出目录,不能是当前工作目录或其父目录"
|
|
18
18
|
},
|
|
19
19
|
"generator": {
|
|
20
20
|
"enum": ["typescript", "javascript"],
|
package/dist/cli/index.js
CHANGED
|
@@ -44,7 +44,7 @@ const program = new commander_1.Command();
|
|
|
44
44
|
const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../package.json'), 'utf-8'));
|
|
45
45
|
program
|
|
46
46
|
.name('swagger2api-v3')
|
|
47
|
-
.description('从
|
|
47
|
+
.description('从 OpenAPI 3.0 文档生成 TypeScript API 接口')
|
|
48
48
|
.version(packageJson.version);
|
|
49
49
|
// generate 命令
|
|
50
50
|
program
|
|
@@ -52,7 +52,7 @@ program
|
|
|
52
52
|
.alias('gen')
|
|
53
53
|
.description('根据配置文件生成 API 接口')
|
|
54
54
|
.option('-c, --config <path>', '配置文件路径', '.swagger.config.json')
|
|
55
|
-
.option('-i, --input <path>', '
|
|
55
|
+
.option('-i, --input <path>', 'OpenAPI JSON/YAML 文件路径或 URL')
|
|
56
56
|
.option('-o, --output <path>', '输出目录')
|
|
57
57
|
.option('--no-types', '不生成类型文件')
|
|
58
58
|
.option('--no-group', '不按标签分组')
|
package/dist/config/validator.js
CHANGED
|
@@ -1,6 +1,41 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.validateSwaggerConfig = validateSwaggerConfig;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const file_1 = require("../utils/file");
|
|
4
39
|
const CONFIG_KEYS = [
|
|
5
40
|
'$schema',
|
|
6
41
|
'input',
|
|
@@ -43,8 +78,12 @@ const COMMENT_KEYS = [
|
|
|
43
78
|
*/
|
|
44
79
|
function validateSwaggerConfig(config) {
|
|
45
80
|
const errors = [];
|
|
81
|
+
if (!isPlainObject(config)) {
|
|
82
|
+
return ['config 必须是对象'];
|
|
83
|
+
}
|
|
46
84
|
validateRequiredString(config.input, 'input', errors);
|
|
47
85
|
validateRequiredString(config.output, 'output', errors);
|
|
86
|
+
validateOutputPath(config.output, errors);
|
|
48
87
|
validateEnum(config.generator, 'generator', ['typescript', 'javascript'], errors);
|
|
49
88
|
validateBoolean(config.groupByTags, 'groupByTags', errors);
|
|
50
89
|
validateOptionalEnum(config.multiTagStrategy, 'multiTagStrategy', ['first', 'all'], errors);
|
|
@@ -71,10 +110,25 @@ function validateSwaggerConfig(config) {
|
|
|
71
110
|
* @param errors 错误信息数组
|
|
72
111
|
*/
|
|
73
112
|
function validateRequiredString(value, field, errors) {
|
|
74
|
-
if (typeof value !== 'string' || !value) {
|
|
113
|
+
if (typeof value !== 'string' || !value.trim()) {
|
|
75
114
|
errors.push(`${field} 配置项不能为空,且必须是字符串`);
|
|
76
115
|
}
|
|
77
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* 验证输出路径不会覆盖当前工作目录或其父目录
|
|
119
|
+
* @param value 输出路径
|
|
120
|
+
* @param errors 错误信息数组
|
|
121
|
+
*/
|
|
122
|
+
function validateOutputPath(value, errors) {
|
|
123
|
+
if (typeof value !== 'string' || !value.trim())
|
|
124
|
+
return;
|
|
125
|
+
const currentDirectory = path.resolve(process.cwd());
|
|
126
|
+
const outputDirectory = path.resolve(currentDirectory, value);
|
|
127
|
+
if (outputDirectory === currentDirectory ||
|
|
128
|
+
(0, file_1.isPathInside)(outputDirectory, currentDirectory)) {
|
|
129
|
+
errors.push('output 不能是当前工作目录或其父目录');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
78
132
|
/**
|
|
79
133
|
* 验证可选字符串
|
|
80
134
|
* @param value 字段值
|
|
@@ -151,13 +205,17 @@ function validateStringArray(value, field, errors) {
|
|
|
151
205
|
* @param errors 错误信息数组
|
|
152
206
|
*/
|
|
153
207
|
function validateFilter(config, errors) {
|
|
154
|
-
if (!config.filter)
|
|
208
|
+
if (!validateOptionalPlainObject(config.filter, 'filter', errors))
|
|
155
209
|
return;
|
|
156
210
|
validateKnownKeys(config.filter, ['include', 'exclude'], 'filter', errors);
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
211
|
+
if (validateOptionalPlainObject(config.filter.include, 'filter.include', errors)) {
|
|
212
|
+
validateKnownKeys(config.filter.include, ['tags'], 'filter.include', errors);
|
|
213
|
+
validateStringArray(config.filter.include.tags, 'filter.include.tags', errors);
|
|
214
|
+
}
|
|
215
|
+
if (validateOptionalPlainObject(config.filter.exclude, 'filter.exclude', errors)) {
|
|
216
|
+
validateKnownKeys(config.filter.exclude, ['tags'], 'filter.exclude', errors);
|
|
217
|
+
validateStringArray(config.filter.exclude.tags, 'filter.exclude.tags', errors);
|
|
218
|
+
}
|
|
161
219
|
}
|
|
162
220
|
/**
|
|
163
221
|
* 验证生成选项配置
|
|
@@ -165,7 +223,7 @@ function validateFilter(config, errors) {
|
|
|
165
223
|
* @param errors 错误信息数组
|
|
166
224
|
*/
|
|
167
225
|
function validateOptions(config, errors) {
|
|
168
|
-
if (!config.options)
|
|
226
|
+
if (!validateOptionalPlainObject(config.options, 'options', errors))
|
|
169
227
|
return;
|
|
170
228
|
validateKnownKeys(config.options, OPTIONS_KEYS, 'options', errors);
|
|
171
229
|
validateOptionalBoolean(config.options.generateModels, 'options.generateModels', errors);
|
|
@@ -181,8 +239,9 @@ function validateOptions(config, errors) {
|
|
|
181
239
|
* @param errors 错误信息数组
|
|
182
240
|
*/
|
|
183
241
|
function validateTagGrouping(config, errors) {
|
|
184
|
-
if (!config.tagGrouping)
|
|
242
|
+
if (!validateOptionalPlainObject(config.tagGrouping, 'tagGrouping', errors)) {
|
|
185
243
|
return;
|
|
244
|
+
}
|
|
186
245
|
validateKnownKeys(config.tagGrouping, TAG_GROUPING_KEYS, 'tagGrouping', errors);
|
|
187
246
|
validateOptionalBoolean(config.tagGrouping.enabled, 'tagGrouping.enabled', errors);
|
|
188
247
|
validateOptionalBoolean(config.tagGrouping.createSubDirectories, 'tagGrouping.createSubDirectories', errors);
|
|
@@ -194,7 +253,7 @@ function validateTagGrouping(config, errors) {
|
|
|
194
253
|
* @param errors 错误信息数组
|
|
195
254
|
*/
|
|
196
255
|
function validateComments(config, errors) {
|
|
197
|
-
if (!config.comments)
|
|
256
|
+
if (!validateOptionalPlainObject(config.comments, 'comments', errors))
|
|
198
257
|
return;
|
|
199
258
|
validateKnownKeys(config.comments, COMMENT_KEYS, 'comments', errors);
|
|
200
259
|
validateOptionalBoolean(config.comments.includeDescription, 'comments.includeDescription', errors);
|
|
@@ -218,3 +277,27 @@ function validateKnownKeys(value, knownKeys, path, errors) {
|
|
|
218
277
|
}
|
|
219
278
|
}
|
|
220
279
|
}
|
|
280
|
+
/**
|
|
281
|
+
* 验证可选配置值是否为普通对象
|
|
282
|
+
* @param value 配置值
|
|
283
|
+
* @param field 字段路径
|
|
284
|
+
* @param errors 错误信息数组
|
|
285
|
+
* @returns 配置值是否为普通对象
|
|
286
|
+
*/
|
|
287
|
+
function validateOptionalPlainObject(value, field, errors) {
|
|
288
|
+
if (value === undefined)
|
|
289
|
+
return false;
|
|
290
|
+
if (!isPlainObject(value)) {
|
|
291
|
+
errors.push(`${field} 必须是对象`);
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* 判断值是否为普通对象
|
|
298
|
+
* @param value 待判断的值
|
|
299
|
+
* @returns 是否为普通对象
|
|
300
|
+
*/
|
|
301
|
+
function isPlainObject(value) {
|
|
302
|
+
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
303
|
+
}
|
package/dist/core/generator.d.ts
CHANGED
|
@@ -4,6 +4,11 @@ import { SwaggerConfig, ApiInfo, TypeInfo } from '../types';
|
|
|
4
4
|
*/
|
|
5
5
|
export declare class CodeGenerator {
|
|
6
6
|
private config;
|
|
7
|
+
private readonly outputRoot;
|
|
8
|
+
/**
|
|
9
|
+
* 创建代码生成器
|
|
10
|
+
* @param config 生成配置
|
|
11
|
+
*/
|
|
7
12
|
constructor(config: SwaggerConfig);
|
|
8
13
|
/**
|
|
9
14
|
* 生成所有文件
|
|
@@ -23,6 +28,31 @@ export declare class CodeGenerator {
|
|
|
23
28
|
* @returns 类型文件内容
|
|
24
29
|
*/
|
|
25
30
|
private generateTypesContent;
|
|
31
|
+
/**
|
|
32
|
+
* 渲染类型定义列表
|
|
33
|
+
* @param types 类型定义数组
|
|
34
|
+
* @returns 类型定义内容
|
|
35
|
+
*/
|
|
36
|
+
private renderTypeDefinitions;
|
|
37
|
+
/**
|
|
38
|
+
* 合并类型定义
|
|
39
|
+
* @param modelTypes 组件模型类型
|
|
40
|
+
* @param parameterTypes 查询参数类型
|
|
41
|
+
* @returns 合并后的类型定义
|
|
42
|
+
*/
|
|
43
|
+
private mergeTypeDefinitions;
|
|
44
|
+
/**
|
|
45
|
+
* 判断是否应提取查询参数类型
|
|
46
|
+
* @returns 是否提取查询参数类型
|
|
47
|
+
*/
|
|
48
|
+
private shouldExtractQueryParameterTypes;
|
|
49
|
+
/**
|
|
50
|
+
* 生成 tag 内的查询参数类型文件
|
|
51
|
+
* @param folderName tag 目录名
|
|
52
|
+
* @param apis 当前 tag 的 API 接口
|
|
53
|
+
* @param modelTypes 组件模型类型
|
|
54
|
+
*/
|
|
55
|
+
private generateTagParameterTypesFile;
|
|
26
56
|
/**
|
|
27
57
|
* 按标签生成API文件
|
|
28
58
|
* @param groupedApis 按标签分组的API
|
|
@@ -46,31 +76,35 @@ export declare class CodeGenerator {
|
|
|
46
76
|
/**
|
|
47
77
|
* 生成单个API函数
|
|
48
78
|
* @param api API接口信息
|
|
79
|
+
* @param queryParameterTypeName 查询参数类型名
|
|
49
80
|
* @returns API函数代码
|
|
50
81
|
*/
|
|
51
82
|
private generateApiFunction;
|
|
52
83
|
/**
|
|
53
84
|
* 生成直接参数形式
|
|
54
85
|
* @param parameters OpenAPI 参数数组
|
|
86
|
+
* @param isJavaScript 是否生成 JavaScript 参数
|
|
87
|
+
* @param queryParameterTypeName 查询参数类型名
|
|
55
88
|
* @returns 函数参数字符串
|
|
56
89
|
*/
|
|
57
90
|
private generateDirectParameters;
|
|
58
|
-
/**
|
|
59
|
-
* 从schema获取类型
|
|
60
|
-
* @param schema Swagger schema
|
|
61
|
-
* @returns 类型字符串
|
|
62
|
-
*/
|
|
63
|
-
private getTypeFromSchema;
|
|
64
91
|
/**
|
|
65
92
|
* 获取当前配置下可安全输出的类型
|
|
66
93
|
* @param type 类型字符串
|
|
67
94
|
* @returns 安全类型字符串
|
|
68
95
|
*/
|
|
69
96
|
private getSafeGeneratedType;
|
|
97
|
+
/**
|
|
98
|
+
* 渲染内联查询参数类型成员
|
|
99
|
+
* @param parameters 查询参数数组
|
|
100
|
+
* @returns 内联类型成员
|
|
101
|
+
*/
|
|
102
|
+
private renderInlineQueryParameterMembers;
|
|
70
103
|
/**
|
|
71
104
|
* 收集API数组中实际使用的类型
|
|
72
105
|
* @param apis API接口数组
|
|
73
106
|
* @param definedTypes 已定义的类型数组
|
|
107
|
+
* @param excludeQueryParameters 是否排除查询参数
|
|
74
108
|
* @returns 使用的类型名称数组
|
|
75
109
|
*/
|
|
76
110
|
private collectUsedTypes;
|
|
@@ -86,13 +120,6 @@ export declare class CodeGenerator {
|
|
|
86
120
|
* @returns 是否为基础类型
|
|
87
121
|
*/
|
|
88
122
|
private isPrimitiveType;
|
|
89
|
-
/**
|
|
90
|
-
* 检测是否为通用响应容器类型
|
|
91
|
-
* @param type 类型信息
|
|
92
|
-
* @param definition 类型定义
|
|
93
|
-
* @returns 是否为通用响应容器类型
|
|
94
|
-
*/
|
|
95
|
-
private isGenericResponseContainer;
|
|
96
123
|
/**
|
|
97
124
|
* 生成请求配置
|
|
98
125
|
* @param api API接口信息
|
|
@@ -100,16 +127,26 @@ export declare class CodeGenerator {
|
|
|
100
127
|
*/
|
|
101
128
|
private generateRequestConfig;
|
|
102
129
|
/**
|
|
103
|
-
*
|
|
104
|
-
* @param
|
|
105
|
-
* @returns
|
|
130
|
+
* 创建不重复的路径参数变量名
|
|
131
|
+
* @param parameters OpenAPI 路径参数
|
|
132
|
+
* @returns 路径参数变量名
|
|
106
133
|
*/
|
|
107
|
-
private
|
|
134
|
+
private createPathParameterNames;
|
|
108
135
|
/**
|
|
109
136
|
* 生成入口文件
|
|
110
137
|
* @param groupedApis 按标签分组的API
|
|
111
138
|
*/
|
|
112
139
|
private generateIndexFile;
|
|
140
|
+
/**
|
|
141
|
+
* 校验输出目录不会覆盖当前工作目录或其父目录
|
|
142
|
+
*/
|
|
143
|
+
private assertSafeOutputDirectory;
|
|
144
|
+
/**
|
|
145
|
+
* 解析并校验输出目录内的文件路径
|
|
146
|
+
* @param segments 输出目录下的路径片段
|
|
147
|
+
* @returns 安全的绝对路径
|
|
148
|
+
*/
|
|
149
|
+
private resolveOutputPath;
|
|
113
150
|
/**
|
|
114
151
|
* 写入生成文件,overwrite=false 时保留已存在文件
|
|
115
152
|
* @param filePath 文件路径
|
|
@@ -122,6 +159,23 @@ export declare class CodeGenerator {
|
|
|
122
159
|
* @returns 文件名
|
|
123
160
|
*/
|
|
124
161
|
private getTagFileName;
|
|
162
|
+
/**
|
|
163
|
+
* 校验所有标签生成的目录名称安全且不重复
|
|
164
|
+
* @param groupedApis 按标签分组的 API
|
|
165
|
+
*/
|
|
166
|
+
private validateTagFolders;
|
|
167
|
+
/**
|
|
168
|
+
* 转义模板字符串中的特殊字符
|
|
169
|
+
* @param value 原始字符串
|
|
170
|
+
* @returns 可安全写入模板字符串的内容
|
|
171
|
+
*/
|
|
172
|
+
private escapeTemplateLiteral;
|
|
173
|
+
/**
|
|
174
|
+
* 将字符串转换为安全的单引号字面量
|
|
175
|
+
* @param value 原始字符串
|
|
176
|
+
* @returns 单引号字符串字面量
|
|
177
|
+
*/
|
|
178
|
+
private toSingleQuotedString;
|
|
125
179
|
/**
|
|
126
180
|
* 生成文件头部注释
|
|
127
181
|
* @param defaultHeader 默认头部注释
|