openapi-ts-request 0.12.0 → 0.13.0
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 +17 -7
- package/dist/bin/openapi.js +13 -3
- package/dist/generator/serviceGenarator.d.ts +14 -0
- package/dist/generator/serviceGenarator.js +176 -53
- package/dist/generator/util.d.ts +2 -1
- package/dist/generator/util.js +10 -4
- package/dist/index.d.ts +24 -3
- package/dist/index.js +9 -4
- package/dist/type.d.ts +11 -0
- package/dist/type.js +7 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
<a href="https://github.com/openapi-ui/openapi-ts-request/blob/master/README-en_US.md">English</a> | 简体中文
|
|
6
6
|
|
|
7
|
-
根据 [Swagger2/OpenAPI3](https://swagger.io/blog/news/whats-new-in-openapi-3-0/) 文档生成 TS 类型, 客户端请求函数, 模拟请求响应服务, 枚举, 类型字段翻译, JSON Schemas
|
|
7
|
+
根据 [Swagger2/OpenAPI3/Apifox](https://swagger.io/blog/news/whats-new-in-openapi-3-0/) 文档生成 TS 类型, 客户端请求函数, 模拟请求响应服务, 枚举, 类型字段翻译, JSON Schemas
|
|
8
8
|
|
|
9
9
|
文档:[使用手册](https://github.com/openapi-ui/openapi-ts-request/issues/100)
|
|
10
10
|
|
|
11
11
|
## 功能
|
|
12
12
|
|
|
13
|
-
- 支持 Swagger2.0/OpenAPI 3.0,3.1 定义
|
|
13
|
+
- 支持 Swagger2.0/OpenAPI/Apifox 3.0,3.1 定义
|
|
14
14
|
- 生成 TS 类型, 请求客户端, 请求模拟服务, 枚举, 类型字段翻译, JSON Schemas
|
|
15
15
|
- 支持通过 npx、CLI、Nodejs 的方式使用
|
|
16
16
|
- 支持自定义请求工具函数, 支持 Fetch、Axios、[UniApp-Request](https://github.com/openapi-ui/openapi-ts-request/issues/46)、Node.js、XHR 客户端
|
|
@@ -136,8 +136,13 @@ $ openapi --help
|
|
|
136
136
|
-V, --version output the version number
|
|
137
137
|
-i, --input <string> OpenAPI specification, can be a path, url (required)
|
|
138
138
|
-o, --output <string> output directory (required)
|
|
139
|
-
--requestLibPath <string> custom request lib path, for example: "@/request", "node-fetch"
|
|
140
|
-
--
|
|
139
|
+
--requestLibPath <string> custom request lib path, for example: "@/request", "node-fetch" (default: "axios")
|
|
140
|
+
--enableLogging <boolean> open the log (default: false)
|
|
141
|
+
--priorityRule <string> priority rule, include/exclude/both (default: "include")
|
|
142
|
+
--includeTags <(string|RegExp)[]> generate code from include tags
|
|
143
|
+
--includePaths <(string|RegExp)[]> generate code from include paths
|
|
144
|
+
--excludeTags <(string|RegExp)[]> generate code from exclude tags
|
|
145
|
+
--excludePaths <(string|RegExp)[]> generate code from exclude paths
|
|
141
146
|
--requestOptionsType <string> custom request method options parameter type (default: "{ [key:
|
|
142
147
|
string]: unknown }")
|
|
143
148
|
--requestImportStatement <string> custom request import statement, for example: "const request =
|
|
@@ -146,7 +151,7 @@ $ openapi --help
|
|
|
146
151
|
"'api'"(string)
|
|
147
152
|
--isDisplayTypeLabel <boolean> generate label matching type field (default: false)
|
|
148
153
|
--isGenJsonSchemas <boolean> generate JSON Schemas (default: false)
|
|
149
|
-
--mockFolder <string> mock file path
|
|
154
|
+
--mockFolder <string> mock file path, for example: './mocks'
|
|
150
155
|
--authorization <string> docs authorization
|
|
151
156
|
--nullable <boolean> null instead of optional (default: false)
|
|
152
157
|
--isTranslateToEnglishTag <boolean>translate chinese tag name to english tag name (default: false)
|
|
@@ -168,13 +173,18 @@ openapi --i ./spec.json --o ./apis
|
|
|
168
173
|
| schemaPath | 是 | string | - | Swagger2/OpenAPI3 地址 |
|
|
169
174
|
| serversPath | 否 | string | './src/apis' | 生成结果的文件夹路径 |
|
|
170
175
|
| requestLibPath | 否 | string | 'axios' | 自定义请求方法路径,例如:'@/request'、'node-fetch' |
|
|
171
|
-
|
|
|
176
|
+
| enableLogging | 否 | boolean | false | 是否开启日志 |
|
|
177
|
+
| priorityRule | 否 | string | 'include' | 模式规则,可选include/exclude/both |
|
|
178
|
+
| includeTags | 否 | (string\|RegExp)[] | - | 根据指定的 tags 生成代码, priorityRule=include则必填 |
|
|
179
|
+
| includePaths | 否 | (string\|RegExp)[] | - | 根据指定的 paths 生成代码 |
|
|
180
|
+
| excludeTags | 否 | (string\|RegExp)[] | - | 根据指定的 tags 不生成代码 |
|
|
181
|
+
| excludePaths | 否 | (string\|RegExp)[] | - | 根据指定的 paths 不生成代码 |
|
|
172
182
|
| requestOptionsType | 否 | string | '{ [key: string]: unknown }' | 自定义请求方法 options 参数类型 |
|
|
173
183
|
| requestImportStatement | 否 | string | - | 自定义请求方法表达式,例如:"const request = require('@/request')" |
|
|
174
184
|
| apiPrefix | 否 | string | - | api path的前缀,例如:'api'(动态变量), "'api'"(字符串) |
|
|
175
185
|
| isDisplayTypeLabel | 否 | boolean | false | 是否生成 type 对应的label |
|
|
176
186
|
| isGenJsonSchemas | 否 | boolean | false | 是否生成 JSON Schemas |
|
|
177
|
-
| mockFolder | 否 | string | './mocks' |
|
|
187
|
+
| mockFolder | 否 | string | - | mock文件路径,例如:'./mocks' |
|
|
178
188
|
| authorization | 否 | string | - | 文档权限凭证 |
|
|
179
189
|
| nullable | 否 | boolean | false | 使用 null 代替可选 |
|
|
180
190
|
| isTranslateToEnglishTag | 否 | boolean | false | 将中文 tag 名称翻译成英文 tag 名称 |
|
package/dist/bin/openapi.js
CHANGED
|
@@ -12,8 +12,13 @@ const params = commander_1.program
|
|
|
12
12
|
.version(pkg.version)
|
|
13
13
|
.requiredOption('-i, --input <string>', 'OpenAPI specification, can be a path, url (required)')
|
|
14
14
|
.requiredOption('-o, --output <string>', 'output directory (required)')
|
|
15
|
-
.option('--requestLibPath <string>', 'custom request lib path, for example: "@/request", "node-fetch"
|
|
16
|
-
.option('--
|
|
15
|
+
.option('--requestLibPath <string>', 'custom request lib path, for example: "@/request", "node-fetch" (default: "axios")')
|
|
16
|
+
.option('--enableLogging <boolean>', 'open the log', false)
|
|
17
|
+
.option('--priorityRule <string>', 'priority rule, include/exclude/both (default: "include")')
|
|
18
|
+
.option('--includeTags <(string|RegExp)[]>', 'generate code from include tags')
|
|
19
|
+
.option('--includePaths <(string|RegExp)[]>', 'generate code from include paths')
|
|
20
|
+
.option('--excludeTags <(string|RegExp)[]>', 'generate code from exclude tags')
|
|
21
|
+
.option('--excludePaths <(string|RegExp)[]>', 'generate code from exclude paths')
|
|
17
22
|
.option('--requestOptionsType <string>', 'custom request method options parameter type (default: "{ [key: string]: unknown }")')
|
|
18
23
|
.option('--requestImportStatement <string>', `custom request import statement, for example: "const request = require('@/request')"`)
|
|
19
24
|
.option('--apiPrefix <string>', `custom the prefix of the api path, for example: "api"(variable), "'api'"(string)`)
|
|
@@ -43,7 +48,12 @@ function run() {
|
|
|
43
48
|
schemaPath: input,
|
|
44
49
|
serversPath: output,
|
|
45
50
|
requestLibPath: params.requestLibPath,
|
|
46
|
-
|
|
51
|
+
enableLogging: JSON.parse(params.enableLogging) === true,
|
|
52
|
+
priorityRule: params.priorityRule,
|
|
53
|
+
includeTags: params.includeTags,
|
|
54
|
+
includePaths: params.includePaths,
|
|
55
|
+
excludeTags: params.excludeTags,
|
|
56
|
+
excludePaths: params.excludePaths,
|
|
47
57
|
requestOptionsType: params.requestOptionsType,
|
|
48
58
|
apiPrefix: params.apiPrefix,
|
|
49
59
|
isDisplayTypeLabel: JSON.parse(params.isDisplayTypeLabel) === true,
|
|
@@ -29,4 +29,18 @@ export default class ServiceGenerator {
|
|
|
29
29
|
private resolveAllOfObject;
|
|
30
30
|
private getProps;
|
|
31
31
|
private resolveRefObject;
|
|
32
|
+
log(message: string): void;
|
|
33
|
+
private generateInfoLog;
|
|
34
|
+
/**
|
|
35
|
+
* 校验规则
|
|
36
|
+
* @param regexp 正则数组
|
|
37
|
+
* @param data 数据
|
|
38
|
+
*/
|
|
39
|
+
private validateRegexp;
|
|
40
|
+
/**
|
|
41
|
+
*
|
|
42
|
+
* @param item 数组数据
|
|
43
|
+
* @param reg 规则
|
|
44
|
+
*/
|
|
45
|
+
private matches;
|
|
32
46
|
}
|
|
@@ -4,6 +4,7 @@ const tslib_1 = require("tslib");
|
|
|
4
4
|
const fs_1 = require("fs");
|
|
5
5
|
const glob_1 = require("glob");
|
|
6
6
|
const lodash_1 = require("lodash");
|
|
7
|
+
const minimatch_1 = require("minimatch");
|
|
7
8
|
const nunjucks_1 = tslib_1.__importDefault(require("nunjucks"));
|
|
8
9
|
const path_1 = require("path");
|
|
9
10
|
const rimraf_1 = require("rimraf");
|
|
@@ -15,14 +16,19 @@ const patchSchema_1 = require("./patchSchema");
|
|
|
15
16
|
const util_1 = require("./util");
|
|
16
17
|
class ServiceGenerator {
|
|
17
18
|
constructor(config, openAPIData) {
|
|
18
|
-
var _a, _b;
|
|
19
|
+
var _a, _b, _c, _d, _e;
|
|
19
20
|
this.apiData = {};
|
|
20
21
|
this.classNameList = [];
|
|
21
22
|
this.schemaList = [];
|
|
22
23
|
this.finalPath = '';
|
|
23
24
|
this.config = Object.assign({ templatesFolder: (0, path_1.join)(__dirname, '../../', 'templates') }, config);
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
this.generateInfoLog();
|
|
26
|
+
const includeTags = ((_a = this.config) === null || _a === void 0 ? void 0 : _a.includeTags) || [];
|
|
27
|
+
const includePaths = ((_b = this.config) === null || _b === void 0 ? void 0 : _b.includePaths) || [];
|
|
28
|
+
const excludeTags = ((_c = this.config) === null || _c === void 0 ? void 0 : _c.excludeTags) || [];
|
|
29
|
+
const excludePaths = ((_d = this.config) === null || _d === void 0 ? void 0 : _d.excludePaths) || [];
|
|
30
|
+
const priorityRule = type_1.PriorityRule[config.priorityRule];
|
|
31
|
+
if ((_e = this.config.hook) === null || _e === void 0 ? void 0 : _e.afterOpenApiDataInited) {
|
|
26
32
|
this.openAPIData =
|
|
27
33
|
this.config.hook.afterOpenApiDataInited(openAPIData) || openAPIData;
|
|
28
34
|
}
|
|
@@ -30,23 +36,85 @@ class ServiceGenerator {
|
|
|
30
36
|
this.openAPIData = openAPIData;
|
|
31
37
|
}
|
|
32
38
|
// 用 tag 分组 paths, { [tag]: [pathMap, pathMap] }
|
|
33
|
-
(
|
|
39
|
+
outerLoop: for (const pathKey in this.openAPIData.paths) {
|
|
40
|
+
// 这里判断paths
|
|
41
|
+
switch (priorityRule) {
|
|
42
|
+
case type_1.PriorityRule.include: {
|
|
43
|
+
// includePaths and includeTags is empty, 直接跳过
|
|
44
|
+
if ((0, lodash_1.isEmpty)(includeTags) && (0, lodash_1.isEmpty)(includePaths)) {
|
|
45
|
+
this.log('priorityRule include need includeTags or includePaths');
|
|
46
|
+
break outerLoop;
|
|
47
|
+
}
|
|
48
|
+
if (!(0, lodash_1.isEmpty)(includePaths) &&
|
|
49
|
+
!this.validateRegexp(pathKey, includePaths)) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
case type_1.PriorityRule.exclude: {
|
|
55
|
+
if (this.validateRegexp(pathKey, excludePaths)) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
case type_1.PriorityRule.both: {
|
|
61
|
+
// includePaths and includeTags is empty,直接跳过
|
|
62
|
+
if ((0, lodash_1.isEmpty)(includeTags) && (0, lodash_1.isEmpty)(includePaths)) {
|
|
63
|
+
this.log('priorityRule both need includeTags or includePaths');
|
|
64
|
+
break outerLoop;
|
|
65
|
+
}
|
|
66
|
+
const outIncludePaths = !(0, lodash_1.isEmpty)(includePaths) &&
|
|
67
|
+
!this.validateRegexp(pathKey, includePaths);
|
|
68
|
+
const inExcludePaths = !(0, lodash_1.isEmpty)(excludePaths) &&
|
|
69
|
+
this.validateRegexp(pathKey, excludePaths);
|
|
70
|
+
if (outIncludePaths || inExcludePaths) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
default:
|
|
76
|
+
throw new Error('priorityRule must be "include" or "exclude" or "include"');
|
|
77
|
+
}
|
|
34
78
|
const pathItem = this.openAPIData.paths[pathKey];
|
|
35
79
|
(0, lodash_1.forEach)(config_1.methods, (method) => {
|
|
80
|
+
var _a;
|
|
36
81
|
const operationObject = pathItem[method];
|
|
37
82
|
if (!operationObject) {
|
|
38
83
|
return;
|
|
39
84
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
85
|
+
const hookCustomFileNames = ((_a = this.config.hook) === null || _a === void 0 ? void 0 : _a.customFileNames) || util_1.getDefaultFileTag;
|
|
86
|
+
const tags = hookCustomFileNames(operationObject, pathKey, method);
|
|
87
|
+
// 这里判断tags
|
|
44
88
|
tags.forEach((tag) => {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
89
|
+
const tagLowerCase = tag.toLowerCase();
|
|
90
|
+
if (priorityRule === type_1.PriorityRule.include) {
|
|
91
|
+
// includeTags 为空,不会匹配任何path,故跳过
|
|
92
|
+
if ((0, lodash_1.isEmpty)(includeTags)) {
|
|
93
|
+
this.log('priorityRule include need includeTags or includePaths');
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (!this.validateRegexp(tagLowerCase, includeTags)) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (priorityRule === type_1.PriorityRule.exclude) {
|
|
101
|
+
if (this.validateRegexp(tagLowerCase, excludeTags)) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (priorityRule === type_1.PriorityRule.both) {
|
|
106
|
+
// includeTags is empty 没有配置, 直接跳过
|
|
107
|
+
if ((0, lodash_1.isEmpty)(includeTags)) {
|
|
108
|
+
this.log('priorityRule both need includeTags or includePaths');
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const outIncludeTags = !(0, lodash_1.isEmpty)(includeTags) &&
|
|
112
|
+
!this.validateRegexp(tagLowerCase, includeTags);
|
|
113
|
+
const inExcludeTags = !(0, lodash_1.isEmpty)(excludeTags) &&
|
|
114
|
+
this.validateRegexp(tagLowerCase, excludeTags);
|
|
115
|
+
if (outIncludeTags || inExcludeTags) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
50
118
|
}
|
|
51
119
|
const tagKey = this.config.isCamelCase
|
|
52
120
|
? (0, lodash_1.camelCase)((0, util_1.resolveTypeName)(tag))
|
|
@@ -57,7 +125,7 @@ class ServiceGenerator {
|
|
|
57
125
|
this.apiData[tagKey].push(Object.assign({ path: pathKey, method }, operationObject));
|
|
58
126
|
});
|
|
59
127
|
});
|
|
60
|
-
}
|
|
128
|
+
}
|
|
61
129
|
}
|
|
62
130
|
genFile() {
|
|
63
131
|
try {
|
|
@@ -139,28 +207,30 @@ class ServiceGenerator {
|
|
|
139
207
|
(0, log_1.default)('✅ 成功生成 api 文件');
|
|
140
208
|
}
|
|
141
209
|
getInterfaceTPConfigs() {
|
|
142
|
-
var _a;
|
|
210
|
+
var _a, _b;
|
|
143
211
|
const schemas = (_a = this.openAPIData.components) === null || _a === void 0 ? void 0 : _a.schemas;
|
|
144
212
|
const lastTypes = [];
|
|
213
|
+
const includeTags = ((_b = this.config) === null || _b === void 0 ? void 0 : _b.includeTags) || [];
|
|
145
214
|
// 强行替换掉请求参数params的类型,生成方法对应的 xxxxParams 类型
|
|
146
215
|
(0, lodash_1.keys)(this.openAPIData.paths).forEach((pathKey) => {
|
|
147
216
|
const pathItem = this.openAPIData.paths[pathKey];
|
|
148
217
|
(0, lodash_1.forEach)(config_1.methods, (method) => {
|
|
149
218
|
var _a, _b, _c, _d;
|
|
150
219
|
const operationObject = pathItem[method];
|
|
220
|
+
const hookCustomFileNames = ((_a = this.config.hook) === null || _a === void 0 ? void 0 : _a.customFileNames) || util_1.getDefaultFileTag;
|
|
151
221
|
if (!operationObject) {
|
|
152
222
|
return;
|
|
153
223
|
}
|
|
154
|
-
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
if (!(0, lodash_1.isEmpty)((0, lodash_1.intersection)(this.config.allowedTags, (0, lodash_1.map)(operationObject.tags, (tag) => tag.toLowerCase())))) {
|
|
158
|
-
(0, util_1.markAllowedSchema)(JSON.stringify(pathItem), schemas);
|
|
159
|
-
}
|
|
160
|
-
else {
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
224
|
+
const tags = hookCustomFileNames(operationObject, pathKey, method);
|
|
225
|
+
if ((0, lodash_1.isEmpty)(includeTags) || (!(0, lodash_1.isEmpty)(includeTags) && (0, lodash_1.isEmpty)(tags))) {
|
|
226
|
+
return;
|
|
163
227
|
}
|
|
228
|
+
const flag = this.validateRegexp((0, lodash_1.map)(tags, (tag) => tag.toLowerCase()), includeTags);
|
|
229
|
+
if (!flag) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
// 筛选出 pathItem 包含的 $ref 对应的schema
|
|
233
|
+
(0, util_1.markAllowedSchema)(JSON.stringify(pathItem), this.openAPIData);
|
|
164
234
|
operationObject.parameters = (_b = operationObject.parameters) === null || _b === void 0 ? void 0 : _b.filter((item) => (item === null || item === void 0 ? void 0 : item.in) !== `${config_1.parametersInsEnum.header}`);
|
|
165
235
|
const props = [];
|
|
166
236
|
(_c = operationObject.parameters) === null || _c === void 0 ? void 0 : _c.forEach((parameter) => {
|
|
@@ -196,6 +266,10 @@ class ServiceGenerator {
|
|
|
196
266
|
(0, lodash_1.keys)(schemas).forEach((schemaKey) => {
|
|
197
267
|
var _a;
|
|
198
268
|
const schema = schemas[schemaKey];
|
|
269
|
+
// 判断哪些 schema 需要添加进 type, schemas 渲染数组
|
|
270
|
+
if (!(schema === null || schema === void 0 ? void 0 : schema.isAllowed)) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
199
273
|
const result = this.resolveObject(schema);
|
|
200
274
|
const getDefinesType = () => {
|
|
201
275
|
if (result === null || result === void 0 ? void 0 : result.type) {
|
|
@@ -223,29 +297,25 @@ class ServiceGenerator {
|
|
|
223
297
|
}
|
|
224
298
|
});
|
|
225
299
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
typeName: `$${(0, util_1.resolveTypeName)(schemaKey)}`,
|
|
246
|
-
type: JSON.stringify((0, patchSchema_1.patchSchema)(schema, (_a = this.openAPIData.components) === null || _a === void 0 ? void 0 : _a.schemas)),
|
|
247
|
-
});
|
|
248
|
-
}
|
|
300
|
+
const isEnum = result.isEnum;
|
|
301
|
+
const typeName = (0, util_1.resolveTypeName)(schemaKey);
|
|
302
|
+
if (typeName) {
|
|
303
|
+
lastTypes.push({
|
|
304
|
+
typeName,
|
|
305
|
+
type: getDefinesType(),
|
|
306
|
+
props: (result.props || []),
|
|
307
|
+
isEnum,
|
|
308
|
+
displayLabelFuncName: isEnum
|
|
309
|
+
? (0, lodash_1.camelCase)(`display-${typeName}-Enum`)
|
|
310
|
+
: '',
|
|
311
|
+
enumLabelType: isEnum ? result.enumLabelType : '',
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
if (this.config.isGenJsonSchemas) {
|
|
315
|
+
this.schemaList.push({
|
|
316
|
+
typeName: `$${(0, util_1.resolveTypeName)(schemaKey)}`,
|
|
317
|
+
type: JSON.stringify((0, patchSchema_1.patchSchema)(schema, (_a = this.openAPIData.components) === null || _a === void 0 ? void 0 : _a.schemas)),
|
|
318
|
+
});
|
|
249
319
|
}
|
|
250
320
|
});
|
|
251
321
|
return lastTypes === null || lastTypes === void 0 ? void 0 : lastTypes.sort((a, b) => a.typeName.localeCompare(b.typeName)); // typeName排序
|
|
@@ -627,11 +697,11 @@ class ServiceGenerator {
|
|
|
627
697
|
const enumArray = schemaObject.enum;
|
|
628
698
|
let enumStr = '';
|
|
629
699
|
let enumLabelTypeStr = '';
|
|
630
|
-
if (
|
|
631
|
-
enumStr = `{${(0, lodash_1.map)(enumArray, (value) =>
|
|
700
|
+
if (config_1.numberEnum.includes(schemaObject.type) || (0, util_1.isAllNumeric)(enumArray)) {
|
|
701
|
+
enumStr = `{${(0, lodash_1.map)(enumArray, (value) => `NUMBER_${value}=${Number(value)}`).join(',')}}`;
|
|
632
702
|
}
|
|
633
703
|
else {
|
|
634
|
-
enumStr = `{${(0, lodash_1.map)(enumArray, (value) =>
|
|
704
|
+
enumStr = `{${(0, lodash_1.map)(enumArray, (value) => `${value}="${value}"`).join(',')}}`;
|
|
635
705
|
}
|
|
636
706
|
// 翻译枚举
|
|
637
707
|
if (schemaObject['x-enum-varnames'] && schemaObject['x-enum-comments']) {
|
|
@@ -647,11 +717,11 @@ class ServiceGenerator {
|
|
|
647
717
|
}).join(',')}}`;
|
|
648
718
|
}
|
|
649
719
|
else {
|
|
650
|
-
if (
|
|
651
|
-
enumLabelTypeStr = `{${(0, lodash_1.map)(enumArray, (value) =>
|
|
720
|
+
if (config_1.numberEnum.includes(schemaObject.type) || (0, util_1.isAllNumeric)(enumArray)) {
|
|
721
|
+
enumLabelTypeStr = `{${(0, lodash_1.map)(enumArray, (value) => `NUMBER_${value}:${Number(value)}`).join(',')}}`;
|
|
652
722
|
}
|
|
653
723
|
else {
|
|
654
|
-
enumLabelTypeStr = `{${(0, lodash_1.map)(enumArray, (value) =>
|
|
724
|
+
enumLabelTypeStr = `{${(0, lodash_1.map)(enumArray, (value) => `${value}:"${value}"`).join(',')}}`;
|
|
655
725
|
}
|
|
656
726
|
}
|
|
657
727
|
return {
|
|
@@ -709,5 +779,58 @@ class ServiceGenerator {
|
|
|
709
779
|
}
|
|
710
780
|
return refObject;
|
|
711
781
|
}
|
|
782
|
+
log(message) {
|
|
783
|
+
if (this.config.enableLogging) {
|
|
784
|
+
(0, log_1.default)(message);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
generateInfoLog() {
|
|
788
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
789
|
+
this.log(`priorityRule: ${(_a = this.config) === null || _a === void 0 ? void 0 : _a.priorityRule}`);
|
|
790
|
+
if ((_b = this.config) === null || _b === void 0 ? void 0 : _b.includeTags) {
|
|
791
|
+
this.log(`includeTags: ${(_c = this.config) === null || _c === void 0 ? void 0 : _c.includeTags.join(', ')}`);
|
|
792
|
+
}
|
|
793
|
+
if ((_d = this.config) === null || _d === void 0 ? void 0 : _d.excludeTags) {
|
|
794
|
+
this.log(`excludeTags: ${(_e = this.config) === null || _e === void 0 ? void 0 : _e.excludeTags.join(', ')}`);
|
|
795
|
+
}
|
|
796
|
+
if ((_f = this.config) === null || _f === void 0 ? void 0 : _f.includePaths) {
|
|
797
|
+
this.log(`includePaths: ${(_g = this.config) === null || _g === void 0 ? void 0 : _g.includePaths.join(', ')}`);
|
|
798
|
+
}
|
|
799
|
+
if ((_h = this.config) === null || _h === void 0 ? void 0 : _h.excludePaths) {
|
|
800
|
+
this.log(`excludePaths: ${(_j = this.config) === null || _j === void 0 ? void 0 : _j.excludePaths.join(', ')}`);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* 校验规则
|
|
805
|
+
* @param regexp 正则数组
|
|
806
|
+
* @param data 数据
|
|
807
|
+
*/
|
|
808
|
+
validateRegexp(data, regexp) {
|
|
809
|
+
// 确保 data 是数组
|
|
810
|
+
const dataArray = Array.isArray(data) ? data : [data];
|
|
811
|
+
this.log(`"Data Array:", ${dataArray.join(',')}`);
|
|
812
|
+
this.log(`"Regexp Array:", ${regexp.join(',')}`);
|
|
813
|
+
return dataArray.some((item) => {
|
|
814
|
+
const result = regexp.some((reg) => this.matches(item, reg));
|
|
815
|
+
this.log(`"Item:", ${item}, "Matches:", ${result}`);
|
|
816
|
+
return result;
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
/**
|
|
820
|
+
*
|
|
821
|
+
* @param item 数组数据
|
|
822
|
+
* @param reg 规则
|
|
823
|
+
*/
|
|
824
|
+
// 提取匹配逻辑到单独的函数
|
|
825
|
+
matches(item, reg) {
|
|
826
|
+
if (typeof reg === 'string') {
|
|
827
|
+
return (0, minimatch_1.minimatch)(item, reg);
|
|
828
|
+
}
|
|
829
|
+
else if (reg instanceof RegExp) {
|
|
830
|
+
reg.lastIndex = 0; // 重置正则表达式的 lastIndex 属性
|
|
831
|
+
return reg.test(item);
|
|
832
|
+
}
|
|
833
|
+
return false; // 对于其他类型,返回 false
|
|
834
|
+
}
|
|
712
835
|
}
|
|
713
836
|
exports.default = ServiceGenerator;
|
package/dist/generator/util.d.ts
CHANGED
|
@@ -12,10 +12,11 @@ export declare function genDefaultFunctionName(path: string, pathBasePrefix: str
|
|
|
12
12
|
export declare function getFinalFileName(s: string): string;
|
|
13
13
|
export declare function replaceDot(s: string): string;
|
|
14
14
|
export declare function resolveFunctionName(functionName: string, methodName: string): string;
|
|
15
|
-
export declare function markAllowedSchema(schemaStr: string,
|
|
15
|
+
export declare function markAllowedSchema(schemaStr: string, openAPIData: OpenAPIObject): void;
|
|
16
16
|
export declare function isReferenceObject(schema: unknown): schema is ReferenceObject;
|
|
17
17
|
export declare function isSchemaObject(schema: unknown): schema is SchemaObject;
|
|
18
18
|
export declare function isNonArraySchemaObject(schema: unknown): schema is NonArraySchemaObject;
|
|
19
19
|
export declare function isArraySchemaObject(schema: unknown): schema is ArraySchemaObject;
|
|
20
20
|
export declare function isBinaryArraySchemaObject(schema: unknown): schema is BinaryArraySchemaObject;
|
|
21
21
|
export declare function resolveRefs(obj: OpenAPIObject, fields: string[]): unknown;
|
|
22
|
+
export declare function isAllNumeric(arr: any): boolean;
|
package/dist/generator/util.js
CHANGED
|
@@ -19,6 +19,7 @@ exports.isNonArraySchemaObject = isNonArraySchemaObject;
|
|
|
19
19
|
exports.isArraySchemaObject = isArraySchemaObject;
|
|
20
20
|
exports.isBinaryArraySchemaObject = isBinaryArraySchemaObject;
|
|
21
21
|
exports.resolveRefs = resolveRefs;
|
|
22
|
+
exports.isAllNumeric = isAllNumeric;
|
|
22
23
|
const tslib_1 = require("tslib");
|
|
23
24
|
const lodash_1 = require("lodash");
|
|
24
25
|
const reserved_words_1 = tslib_1.__importDefault(require("reserved-words"));
|
|
@@ -286,13 +287,15 @@ function resolveFunctionName(functionName, methodName) {
|
|
|
286
287
|
return functionName;
|
|
287
288
|
}
|
|
288
289
|
// 标记引用的 $ref 对应的schema
|
|
289
|
-
function markAllowedSchema(schemaStr,
|
|
290
|
-
const refs = schemaStr === null || schemaStr === void 0 ? void 0 : schemaStr.match(
|
|
290
|
+
function markAllowedSchema(schemaStr, openAPIData) {
|
|
291
|
+
const refs = (0, lodash_1.map)(schemaStr === null || schemaStr === void 0 ? void 0 : schemaStr.match(/"#\/components\/[^"]+"/g), (item) => item.slice(1, -1));
|
|
291
292
|
(0, lodash_1.forEach)(refs, (ref) => {
|
|
292
|
-
const schema = schemas
|
|
293
|
+
// const schema = schemas?.[getLastRefName(ref)] as ICustomSchemaObject;
|
|
294
|
+
const refPaths = ref.split('/');
|
|
295
|
+
const schema = resolveRefs(openAPIData, refPaths.slice(1));
|
|
293
296
|
if (schema && !schema.isAllowed) {
|
|
294
297
|
schema.isAllowed = true;
|
|
295
|
-
markAllowedSchema(JSON.stringify(schema),
|
|
298
|
+
markAllowedSchema(JSON.stringify(schema), openAPIData);
|
|
296
299
|
}
|
|
297
300
|
});
|
|
298
301
|
}
|
|
@@ -327,3 +330,6 @@ function resolveRefs(obj, fields) {
|
|
|
327
330
|
return s;
|
|
328
331
|
}, obj);
|
|
329
332
|
}
|
|
333
|
+
function isAllNumeric(arr) {
|
|
334
|
+
return (0, lodash_1.every)(arr, (item) => (0, lodash_1.isString)(item) && /^[0-9]+$/.test(item));
|
|
335
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -18,9 +18,30 @@ export type GenerateServiceProps = {
|
|
|
18
18
|
*/
|
|
19
19
|
requestLibPath?: string;
|
|
20
20
|
/**
|
|
21
|
-
*
|
|
21
|
+
* 开启日志
|
|
22
22
|
*/
|
|
23
|
-
|
|
23
|
+
enableLogging?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
/**
|
|
26
|
+
* 优先规则, include(只允许include列表) | exclude(只排除exclude列表) | both(允许include列表,排除exclude列表)
|
|
27
|
+
*/
|
|
28
|
+
priorityRule?: string;
|
|
29
|
+
/**
|
|
30
|
+
* 只解析归属于 tags 集合的 api 和 schema
|
|
31
|
+
*/
|
|
32
|
+
includeTags?: (string | RegExp)[];
|
|
33
|
+
/**
|
|
34
|
+
* 只解析归属于 paths 集合的 api
|
|
35
|
+
*/
|
|
36
|
+
includePaths?: (string | RegExp)[];
|
|
37
|
+
/**
|
|
38
|
+
* 不解析归属于 tags 集合的 api 和 schema
|
|
39
|
+
*/
|
|
40
|
+
excludeTags?: (string | RegExp)[];
|
|
41
|
+
/**
|
|
42
|
+
* 不解析归属于 paths 集合的 api
|
|
43
|
+
*/
|
|
44
|
+
excludePaths?: (string | RegExp)[];
|
|
24
45
|
/**
|
|
25
46
|
* 自定义请求方法 options 参数类型
|
|
26
47
|
*/
|
|
@@ -143,4 +164,4 @@ export type GenerateServiceProps = {
|
|
|
143
164
|
customFileNames?: (operationObject: OperationObject, apiPath: string, apiMethod: string) => string[] | null;
|
|
144
165
|
};
|
|
145
166
|
};
|
|
146
|
-
export declare function generateService({ requestLibPath, schemaPath, mockFolder,
|
|
167
|
+
export declare function generateService({ requestLibPath, schemaPath, mockFolder, includeTags, excludeTags, authorization, isTranslateToEnglishTag, priorityRule, ...rest }: GenerateServiceProps): Promise<void>;
|
package/dist/index.js
CHANGED
|
@@ -5,11 +5,12 @@ const tslib_1 = require("tslib");
|
|
|
5
5
|
const lodash_1 = require("lodash");
|
|
6
6
|
const mockGenarator_1 = require("./generator/mockGenarator");
|
|
7
7
|
const serviceGenarator_1 = tslib_1.__importDefault(require("./generator/serviceGenarator"));
|
|
8
|
+
const type_1 = require("./type");
|
|
8
9
|
const util_1 = require("./util");
|
|
9
10
|
tslib_1.__exportStar(require("./generator/patchSchema"), exports);
|
|
10
11
|
function generateService(_a) {
|
|
11
12
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
12
|
-
var { requestLibPath, schemaPath, mockFolder,
|
|
13
|
+
var { requestLibPath, schemaPath, mockFolder, includeTags, excludeTags, authorization, isTranslateToEnglishTag, priorityRule = type_1.PriorityRule.include } = _a, rest = tslib_1.__rest(_a, ["requestLibPath", "schemaPath", "mockFolder", "includeTags", "excludeTags", "authorization", "isTranslateToEnglishTag", "priorityRule"]);
|
|
13
14
|
if (!schemaPath) {
|
|
14
15
|
return;
|
|
15
16
|
}
|
|
@@ -21,9 +22,13 @@ function generateService(_a) {
|
|
|
21
22
|
yield (0, util_1.translateChineseModuleNodeToEnglish)(openAPI);
|
|
22
23
|
}
|
|
23
24
|
const requestImportStatement = (0, util_1.getImportStatement)(requestLibPath);
|
|
24
|
-
const serviceGenerator = new serviceGenarator_1.default(Object.assign({ schemaPath, serversPath: './src/apis', requestImportStatement,
|
|
25
|
-
? (0, lodash_1.map)(
|
|
26
|
-
:
|
|
25
|
+
const serviceGenerator = new serviceGenarator_1.default(Object.assign({ schemaPath, serversPath: './src/apis', requestImportStatement, enableLogging: false, priorityRule, includeTags: includeTags
|
|
26
|
+
? (0, lodash_1.map)(includeTags, (item) => typeof item === 'string' ? item.toLowerCase() : item)
|
|
27
|
+
: priorityRule === type_1.PriorityRule.include
|
|
28
|
+
? [/.*/g]
|
|
29
|
+
: null, excludeTags: excludeTags
|
|
30
|
+
? (0, lodash_1.map)(excludeTags, (item) => typeof item === 'string' ? item.toLowerCase() : item)
|
|
31
|
+
: null, requestOptionsType: '{[key: string]: unknown}', namespace: 'API', nullable: false, isCamelCase: true, isDisplayTypeLabel: false, isGenJsonSchemas: false, isOnlyGenTypeScriptType: false }, rest), openAPI);
|
|
27
32
|
serviceGenerator.genFile();
|
|
28
33
|
if (mockFolder) {
|
|
29
34
|
(0, mockGenarator_1.mockGenerator)({
|
package/dist/type.d.ts
CHANGED
|
@@ -73,5 +73,16 @@ export declare enum SchemaObjectType {
|
|
|
73
73
|
union = "union",
|
|
74
74
|
file = "file"
|
|
75
75
|
}
|
|
76
|
+
export declare enum PriorityRule {
|
|
77
|
+
include = "include",
|
|
78
|
+
exclude = "exclude",
|
|
79
|
+
both = "both"
|
|
80
|
+
}
|
|
81
|
+
export type GenerateRegExp = {
|
|
82
|
+
includeTags: (string | RegExp)[];
|
|
83
|
+
excludeTags: (string | RegExp)[];
|
|
84
|
+
includePaths: (string | RegExp)[];
|
|
85
|
+
excludePaths: (string | RegExp)[];
|
|
86
|
+
};
|
|
76
87
|
export type ISchemaObjectType = keyof typeof SchemaObjectType;
|
|
77
88
|
export {};
|
package/dist/type.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SchemaObjectType = exports.SchemaObjectFormat = void 0;
|
|
3
|
+
exports.PriorityRule = exports.SchemaObjectType = exports.SchemaObjectFormat = void 0;
|
|
4
4
|
var SchemaObjectFormat;
|
|
5
5
|
(function (SchemaObjectFormat) {
|
|
6
6
|
SchemaObjectFormat["int32"] = "int32";
|
|
@@ -28,3 +28,9 @@ var SchemaObjectType;
|
|
|
28
28
|
SchemaObjectType["union"] = "union";
|
|
29
29
|
SchemaObjectType["file"] = "file";
|
|
30
30
|
})(SchemaObjectType || (exports.SchemaObjectType = SchemaObjectType = {}));
|
|
31
|
+
var PriorityRule;
|
|
32
|
+
(function (PriorityRule) {
|
|
33
|
+
PriorityRule["include"] = "include";
|
|
34
|
+
PriorityRule["exclude"] = "exclude";
|
|
35
|
+
PriorityRule["both"] = "both";
|
|
36
|
+
})(PriorityRule || (exports.PriorityRule = PriorityRule = {}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openapi-ts-request",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Swagger2/OpenAPI3 to TypeScript, request client, request mock service, enum, type field label, JSON Schemas",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=18.0.0",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"js-yaml": "^4.1.0",
|
|
37
37
|
"lodash": "^4.17.21",
|
|
38
38
|
"memoizee": "^0.4.17",
|
|
39
|
+
"minimatch": "^10.0.1",
|
|
39
40
|
"mockjs": "^1.1.0",
|
|
40
41
|
"nunjucks": "^3.2.4",
|
|
41
42
|
"prettier": "^3.3.2",
|
|
@@ -64,7 +65,8 @@
|
|
|
64
65
|
"husky": "^9.0.11",
|
|
65
66
|
"lint-staged": "^15.2.5",
|
|
66
67
|
"openapi-types": "^12.1.3",
|
|
67
|
-
"
|
|
68
|
+
"ts-node": "^10.9.2",
|
|
69
|
+
"typescript": "5.7.2"
|
|
68
70
|
},
|
|
69
71
|
"keywords": [
|
|
70
72
|
"openapi",
|