openapi-ts-request 1.9.0 → 1.9.2
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 +2 -5
- package/dist/bin/openapi.js +1 -2
- package/dist/generator/serviceGenarator.js +31 -7
- package/dist/generator/util.d.ts +27 -0
- package/dist/generator/util.js +70 -1
- package/dist/index.d.ts +5 -0
- package/package.json +2 -2
- package/templates/serviceController.njk +3 -0
package/README.md
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
<!-- TODO:需要修改文档, 添加参数, 添加apifox的配置支持 -->
|
|
2
|
-
|
|
3
1
|
## 介绍
|
|
4
2
|
|
|
5
3
|
[](https://github.com/openapi-ui/openapi-ts-request) [](https://www.npmjs.com/package/openapi-ts-request) 
|
|
@@ -50,8 +48,6 @@ pnpm i openapi-ts-request -D
|
|
|
50
48
|
import type { GenerateServiceProps } from 'openapi-ts-request';
|
|
51
49
|
|
|
52
50
|
export default {
|
|
53
|
-
// schemaPath: './openapi.json', // 本地openapi文件
|
|
54
|
-
// serversPath: './src/apis', // 接口存放路径
|
|
55
51
|
schemaPath: 'http://petstore.swagger.io/v2/swagger.json',
|
|
56
52
|
} as GenerateServiceProps;
|
|
57
53
|
```
|
|
@@ -194,7 +190,7 @@ $ openapi --help
|
|
|
194
190
|
-f, --full <boolean> full replacement (default: true)
|
|
195
191
|
--enableLogging <boolean> open the log (default: false)
|
|
196
192
|
--priorityRule <string> priority rule, include/exclude/both (default: "include")
|
|
197
|
-
--filterCaseInsensitive <boolean> whether to perform a case-insensitive match with includeTags, includePaths, excludeTags, excludePaths filters
|
|
193
|
+
--filterCaseInsensitive <boolean> whether to perform a case-insensitive match with includeTags, includePaths, excludeTags, excludePaths filters (default: false)
|
|
198
194
|
--includeTags <(string|RegExp)[]> generate code from include tags
|
|
199
195
|
--includePaths <(string|RegExp)[]> generate code from include paths
|
|
200
196
|
--excludeTags <(string|RegExp)[]> generate code from exclude tags
|
|
@@ -254,6 +250,7 @@ openapi --i ./spec.json --o ./apis
|
|
|
254
250
|
| isOnlyGenTypeScriptType | 否 | boolean | false | 仅生成 typescript 类型 |
|
|
255
251
|
| isCamelCase | 否 | boolean | true | 小驼峰命名文件和请求函数 |
|
|
256
252
|
| isSupportParseEnumDesc | 否 | boolean | false | 解析枚举描述生成枚举标签,格式参考:`系统用户角色:User(普通用户)=0,Agent(经纪人)=1,Admin(管理员)=2` |
|
|
253
|
+
| binaryMediaTypes | 否 | string[] | - | 自定义二进制媒体类型列表,默认包含:['application/octet-stream', 'application/pdf', 'image/*', 'video/*', 'audio/*'] |
|
|
257
254
|
| hook | 否 | [Custom Hook](#Custom-Hook) | - | 自定义 hook |
|
|
258
255
|
|
|
259
256
|
## 自定义 Hook
|
package/dist/bin/openapi.js
CHANGED
|
@@ -21,8 +21,7 @@ const params = commander_1.program
|
|
|
21
21
|
.option('--requestLibPath <string>', 'custom request lib path, for example: "@/request", "node-fetch" (default: "axios")')
|
|
22
22
|
.option('-f, --full <boolean>', 'full replacement', true)
|
|
23
23
|
.option('--enableLogging <boolean>', 'open the log', false)
|
|
24
|
-
.option('--
|
|
25
|
-
.option('--includeTags <(string|RegExp)[]>', 'generate code from include tags')
|
|
24
|
+
.option('--priorityRule <string>', 'priority rule, include/exclude/both (default: "include")')
|
|
26
25
|
.option('--filterCaseInsensitive <boolean>', 'whether to perform a case-insensitive match with includeTags, includePaths, excludeTags, excludePaths filters', false)
|
|
27
26
|
.option('--includeTags <(string|RegExp)[]>', 'generate code from include tags')
|
|
28
27
|
.option('--includePaths <(string|RegExp)[]>', 'generate code from include paths')
|
|
@@ -391,7 +391,7 @@ class ServiceGenerator {
|
|
|
391
391
|
// 暂不支持变量, path 需要普通前缀请使用例如: apiPrefix: "`api`", path 需要变量前缀请使用例如: apiPrefix: "api"
|
|
392
392
|
!api.path.includes('${'))
|
|
393
393
|
.map((api) => {
|
|
394
|
-
var _a, _b, _c, _d, _e, _f;
|
|
394
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
395
395
|
const newApi = api;
|
|
396
396
|
try {
|
|
397
397
|
const params = this.getParamsTP(newApi.parameters, newApi.path) || {};
|
|
@@ -422,9 +422,13 @@ class ServiceGenerator {
|
|
|
422
422
|
}
|
|
423
423
|
if (response === null || response === void 0 ? void 0 : response.isAnonymous) {
|
|
424
424
|
const responseName = (0, lodash_1.upperFirst)(`${functionName}Response`);
|
|
425
|
+
// 使用正则表达式移除 response?.type 中包含 this.config.namespace 的部分,isAnonymous模式不需要 this.config.namespace 前缀
|
|
426
|
+
const cleanType = ((_b = response === null || response === void 0 ? void 0 : response.type) === null || _b === void 0 ? void 0 : _b.includes(`${this.config.namespace}.`))
|
|
427
|
+
? (_c = response === null || response === void 0 ? void 0 : response.type) === null || _c === void 0 ? void 0 : _c.replace(new RegExp(`${this.config.namespace}\\.`, 'g'), '')
|
|
428
|
+
: (response === null || response === void 0 ? void 0 : response.type) || '';
|
|
425
429
|
this.interfaceTPConfigs.push({
|
|
426
430
|
typeName: responseName,
|
|
427
|
-
type:
|
|
431
|
+
type: cleanType,
|
|
428
432
|
isEnum: false,
|
|
429
433
|
props: [],
|
|
430
434
|
});
|
|
@@ -494,13 +498,13 @@ class ServiceGenerator {
|
|
|
494
498
|
: [
|
|
495
499
|
newApi.summary,
|
|
496
500
|
newApi.description,
|
|
497
|
-
((
|
|
498
|
-
? `返回值: ${((
|
|
501
|
+
((_e = (_d = newApi.responses) === null || _d === void 0 ? void 0 : _d.default) === null || _e === void 0 ? void 0 : _e.description)
|
|
502
|
+
? `返回值: ${((_f = newApi.responses) === null || _f === void 0 ? void 0 : _f.default).description}`
|
|
499
503
|
: '',
|
|
500
504
|
]
|
|
501
505
|
.filter((s) => s)
|
|
502
506
|
.join(' ')
|
|
503
|
-
.replace(config_2.lineBreakReg, ''), hasHeader: !!(params === null || params === void 0 ? void 0 : params.header) || !!(body === null || body === void 0 ? void 0 : body.mediaType), params: finalParams, hasParams: Boolean((0, lodash_1.keys)(finalParams).length), options: ((
|
|
507
|
+
.replace(config_2.lineBreakReg, ''), hasHeader: !!(params === null || params === void 0 ? void 0 : params.header) || !!(body === null || body === void 0 ? void 0 : body.mediaType), params: finalParams, hasParams: Boolean((0, lodash_1.keys)(finalParams).length), options: ((_h = (_g = this.config.hook) === null || _g === void 0 ? void 0 : _g.customOptionsDefaultValue) === null || _h === void 0 ? void 0 : _h.call(_g, newApi)) || {}, body,
|
|
504
508
|
file, hasFormData: formData, response });
|
|
505
509
|
}
|
|
506
510
|
catch (error) {
|
|
@@ -734,15 +738,19 @@ class ServiceGenerator {
|
|
|
734
738
|
mediaType: '*/*',
|
|
735
739
|
type: 'unknown',
|
|
736
740
|
isAnonymous: false,
|
|
741
|
+
responseType: undefined,
|
|
737
742
|
};
|
|
738
743
|
if (!response) {
|
|
739
744
|
return defaultResponse;
|
|
740
745
|
}
|
|
741
746
|
const resContent = response.content;
|
|
742
747
|
const resContentMediaTypes = (0, lodash_1.keys)(resContent);
|
|
748
|
+
// 检测二进制流媒体类型
|
|
749
|
+
const binaryMediaTypes = (0, util_2.getBinaryMediaTypes)(this.config.binaryMediaTypes);
|
|
750
|
+
const binaryMediaType = resContentMediaTypes.find((mediaType) => (0, util_2.isBinaryMediaType)(mediaType, binaryMediaTypes));
|
|
743
751
|
const mediaType = resContentMediaTypes.includes('application/json')
|
|
744
752
|
? 'application/json'
|
|
745
|
-
: resContentMediaTypes[0]; // 优先使用 application/json
|
|
753
|
+
: binaryMediaType || resContentMediaTypes[0]; // 优先使用 application/json,然后是二进制类型
|
|
746
754
|
if (!(0, lodash_1.isObject)(resContent) || !mediaType) {
|
|
747
755
|
return defaultResponse;
|
|
748
756
|
}
|
|
@@ -752,7 +760,16 @@ class ServiceGenerator {
|
|
|
752
760
|
mediaType,
|
|
753
761
|
type: 'unknown',
|
|
754
762
|
isAnonymous: false,
|
|
763
|
+
responseType: undefined,
|
|
755
764
|
};
|
|
765
|
+
// 如果是二进制媒体类型,直接返回二进制类型
|
|
766
|
+
if ((0, util_2.isBinaryMediaType)(mediaType, binaryMediaTypes)) {
|
|
767
|
+
const binaryType = (0, util_2.getBinaryResponseType)();
|
|
768
|
+
responseSchema.type = binaryType;
|
|
769
|
+
// 自动为二进制响应添加 responseType 配置
|
|
770
|
+
responseSchema.responseType = (0, util_2.getAxiosResponseType)(binaryType);
|
|
771
|
+
return responseSchema;
|
|
772
|
+
}
|
|
756
773
|
if ((0, util_2.isReferenceObject)(schema)) {
|
|
757
774
|
const refName = (0, util_2.getLastRefName)(schema.$ref);
|
|
758
775
|
const childrenSchema = components.schemas[refName];
|
|
@@ -845,12 +862,19 @@ class ServiceGenerator {
|
|
|
845
862
|
}
|
|
846
863
|
const resContent = response.content;
|
|
847
864
|
const resContentMediaTypes = (0, lodash_1.keys)(resContent);
|
|
865
|
+
// 检测二进制流媒体类型
|
|
866
|
+
const binaryMediaTypes = (0, util_2.getBinaryMediaTypes)(this.config.binaryMediaTypes);
|
|
867
|
+
const binaryMediaType = resContentMediaTypes.find((mediaType) => (0, util_2.isBinaryMediaType)(mediaType, binaryMediaTypes));
|
|
848
868
|
const mediaType = resContentMediaTypes.includes('application/json')
|
|
849
869
|
? 'application/json'
|
|
850
|
-
: resContentMediaTypes[0];
|
|
870
|
+
: binaryMediaType || resContentMediaTypes[0];
|
|
851
871
|
if (!(0, lodash_1.isObject)(resContent) || !mediaType) {
|
|
852
872
|
return 'unknown';
|
|
853
873
|
}
|
|
874
|
+
// 如果是二进制媒体类型,直接返回二进制类型
|
|
875
|
+
if ((0, util_2.isBinaryMediaType)(mediaType, binaryMediaTypes)) {
|
|
876
|
+
return (0, util_2.getBinaryResponseType)();
|
|
877
|
+
}
|
|
854
878
|
let schema = (resContent[mediaType].schema ||
|
|
855
879
|
config_2.DEFAULT_SCHEMA);
|
|
856
880
|
if ((0, util_2.isReferenceObject)(schema)) {
|
package/dist/generator/util.d.ts
CHANGED
|
@@ -23,3 +23,30 @@ export declare function isAllNumeric(arr: any): boolean;
|
|
|
23
23
|
export declare function isAllNumber(arr: any): boolean;
|
|
24
24
|
export declare function capitalizeFirstLetter(str: string): string;
|
|
25
25
|
export declare const parseDescriptionEnum: (description: string) => Map<number, string>;
|
|
26
|
+
/**
|
|
27
|
+
* 获取默认的二进制媒体类型列表
|
|
28
|
+
*/
|
|
29
|
+
export declare const getDefaultBinaryMediaTypes: () => string[];
|
|
30
|
+
/**
|
|
31
|
+
* 获取二进制媒体类型列表
|
|
32
|
+
* 支持配置自定义二进制媒体类型
|
|
33
|
+
* @param customBinaryTypes 自定义二进制媒体类型列表
|
|
34
|
+
*/
|
|
35
|
+
export declare const getBinaryMediaTypes: (customBinaryTypes?: string[]) => string[];
|
|
36
|
+
/**
|
|
37
|
+
* 检测是否为二进制媒体类型
|
|
38
|
+
* @param mediaType 媒体类型
|
|
39
|
+
* @param binaryMediaTypes 二进制媒体类型列表
|
|
40
|
+
*/
|
|
41
|
+
export declare const isBinaryMediaType: (mediaType: string, binaryMediaTypes: string[]) => boolean;
|
|
42
|
+
/**
|
|
43
|
+
* 获取二进制响应类型
|
|
44
|
+
* 默认返回 Blob,这是浏览器环境中最常用的二进制类型
|
|
45
|
+
*/
|
|
46
|
+
export declare const getBinaryResponseType: () => string;
|
|
47
|
+
/**
|
|
48
|
+
* 获取 axios responseType 配置
|
|
49
|
+
* 根据二进制响应类型返回对应的 responseType
|
|
50
|
+
* @param binaryType 二进制类型
|
|
51
|
+
*/
|
|
52
|
+
export declare const getAxiosResponseType: (binaryType: string) => string;
|
package/dist/generator/util.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseDescriptionEnum = void 0;
|
|
3
|
+
exports.getAxiosResponseType = exports.getBinaryResponseType = exports.isBinaryMediaType = exports.getBinaryMediaTypes = exports.getDefaultBinaryMediaTypes = exports.parseDescriptionEnum = void 0;
|
|
4
4
|
exports.stripDot = stripDot;
|
|
5
5
|
exports.resolveTypeName = resolveTypeName;
|
|
6
6
|
exports.getRefName = getRefName;
|
|
@@ -408,3 +408,72 @@ const parseDescriptionEnum = (description) => {
|
|
|
408
408
|
return enumMap;
|
|
409
409
|
};
|
|
410
410
|
exports.parseDescriptionEnum = parseDescriptionEnum;
|
|
411
|
+
/**
|
|
412
|
+
* 获取默认的二进制媒体类型列表
|
|
413
|
+
*/
|
|
414
|
+
const getDefaultBinaryMediaTypes = () => {
|
|
415
|
+
return [
|
|
416
|
+
'application/octet-stream',
|
|
417
|
+
'application/pdf',
|
|
418
|
+
'application/zip',
|
|
419
|
+
'application/x-zip-compressed',
|
|
420
|
+
'image/*',
|
|
421
|
+
'video/*',
|
|
422
|
+
'audio/*',
|
|
423
|
+
];
|
|
424
|
+
};
|
|
425
|
+
exports.getDefaultBinaryMediaTypes = getDefaultBinaryMediaTypes;
|
|
426
|
+
/**
|
|
427
|
+
* 获取二进制媒体类型列表
|
|
428
|
+
* 支持配置自定义二进制媒体类型
|
|
429
|
+
* @param customBinaryTypes 自定义二进制媒体类型列表
|
|
430
|
+
*/
|
|
431
|
+
const getBinaryMediaTypes = (customBinaryTypes = []) => {
|
|
432
|
+
const defaultBinaryTypes = (0, exports.getDefaultBinaryMediaTypes)();
|
|
433
|
+
return [...defaultBinaryTypes, ...customBinaryTypes];
|
|
434
|
+
};
|
|
435
|
+
exports.getBinaryMediaTypes = getBinaryMediaTypes;
|
|
436
|
+
/**
|
|
437
|
+
* 检测是否为二进制媒体类型
|
|
438
|
+
* @param mediaType 媒体类型
|
|
439
|
+
* @param binaryMediaTypes 二进制媒体类型列表
|
|
440
|
+
*/
|
|
441
|
+
const isBinaryMediaType = (mediaType, binaryMediaTypes) => {
|
|
442
|
+
return binaryMediaTypes.some((type) => {
|
|
443
|
+
if (type.endsWith('/*')) {
|
|
444
|
+
// 处理通配符类型,如 image/*, video/*
|
|
445
|
+
const prefix = type.slice(0, -1);
|
|
446
|
+
return mediaType.startsWith(prefix);
|
|
447
|
+
}
|
|
448
|
+
return mediaType === type;
|
|
449
|
+
});
|
|
450
|
+
};
|
|
451
|
+
exports.isBinaryMediaType = isBinaryMediaType;
|
|
452
|
+
/**
|
|
453
|
+
* 获取二进制响应类型
|
|
454
|
+
* 默认返回 Blob,这是浏览器环境中最常用的二进制类型
|
|
455
|
+
*/
|
|
456
|
+
const getBinaryResponseType = () => {
|
|
457
|
+
return 'Blob';
|
|
458
|
+
};
|
|
459
|
+
exports.getBinaryResponseType = getBinaryResponseType;
|
|
460
|
+
/**
|
|
461
|
+
* 获取 axios responseType 配置
|
|
462
|
+
* 根据二进制响应类型返回对应的 responseType
|
|
463
|
+
* @param binaryType 二进制类型
|
|
464
|
+
*/
|
|
465
|
+
const getAxiosResponseType = (binaryType) => {
|
|
466
|
+
switch (binaryType.toLowerCase()) {
|
|
467
|
+
case 'blob':
|
|
468
|
+
return 'blob';
|
|
469
|
+
case 'arraybuffer':
|
|
470
|
+
return 'arraybuffer';
|
|
471
|
+
case 'uint8array':
|
|
472
|
+
return 'arraybuffer'; // Uint8Array 需要从 ArrayBuffer 转换
|
|
473
|
+
case 'buffer':
|
|
474
|
+
return 'arraybuffer'; // Node.js Buffer 需要从 ArrayBuffer 转换
|
|
475
|
+
default:
|
|
476
|
+
return 'blob';
|
|
477
|
+
}
|
|
478
|
+
};
|
|
479
|
+
exports.getAxiosResponseType = getAxiosResponseType;
|
package/dist/index.d.ts
CHANGED
|
@@ -143,6 +143,11 @@ export type GenerateServiceProps = {
|
|
|
143
143
|
* 多网关唯一标识
|
|
144
144
|
*/
|
|
145
145
|
uniqueKey?: string;
|
|
146
|
+
/**
|
|
147
|
+
* 自定义二进制媒体类型列表
|
|
148
|
+
* 默认包含: ['application/octet-stream', 'application/pdf', 'image/*', 'video/*', 'audio/*']
|
|
149
|
+
*/
|
|
150
|
+
binaryMediaTypes?: string[];
|
|
146
151
|
/**
|
|
147
152
|
* 自定义 hook
|
|
148
153
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openapi-ts-request",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.2",
|
|
4
4
|
"description": "Swagger2/OpenAPI3/Apifox to TypeScript/JavaScript, request client(support any client), request mock service, enum and enum translation, react-query/vue-query, type field label, JSON Schemas",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=18.0.0",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"openapi-types": "^12.1.3",
|
|
71
71
|
"sanitize-filename": "^1.6.3",
|
|
72
72
|
"ts-node": "^10.9.2",
|
|
73
|
-
"typescript": "5.9.
|
|
73
|
+
"typescript": "5.9.3",
|
|
74
74
|
"vitest": "^2.1.9"
|
|
75
75
|
},
|
|
76
76
|
"keywords": [
|
|
@@ -128,6 +128,9 @@
|
|
|
128
128
|
return request{{ ("<" + api.response.type + ">") | safe if genType === "ts" }}('{{ api.path }}', {
|
|
129
129
|
{% endif -%}
|
|
130
130
|
method: '{{ api.method | upper }}',
|
|
131
|
+
{%- if api.response.responseType %}
|
|
132
|
+
responseType: '{{ api.response.responseType }}',
|
|
133
|
+
{%- endif %}
|
|
131
134
|
{%- if api.hasHeader and api.body.mediaType %}
|
|
132
135
|
headers: {
|
|
133
136
|
{%- if api.body.mediaType %}
|