openapi-ts-request 1.9.1 → 1.10.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 CHANGED
@@ -45,19 +45,20 @@ pnpm i openapi-ts-request -D
45
45
  > 配置文件还支持 **_.openapi-ts-request.ts_**, **_openapi-ts-request.config.cjs_** 等格式,参考 [cosmiconfig](https://github.com/cosmiconfig/cosmiconfig?tab=readme-ov-file#cosmiconfig)
46
46
 
47
47
  ```ts
48
- import type { GenerateServiceProps } from 'openapi-ts-request';
48
+ import { defineConfig } from 'openapi-ts-request';
49
49
 
50
- export default {
50
+ export default defineConfig({
51
51
  schemaPath: 'http://petstore.swagger.io/v2/swagger.json',
52
- } as GenerateServiceProps;
52
+ serversPath: './src/apis',
53
+ });
53
54
  ```
54
55
 
55
56
  支持传入数组配置进行生成
56
57
 
57
58
  ```ts
58
- import type { GenerateServiceProps } from 'openapi-ts-request';
59
+ import { defineConfig } from 'openapi-ts-request';
59
60
 
60
- export default [
61
+ export default defineConfig([
61
62
  {
62
63
  schemaPath: 'http://app.swagger.io/v2/swagger.json',
63
64
  serversPath: './src/apis/app',
@@ -66,7 +67,7 @@ export default [
66
67
  schemaPath: 'http://auth.swagger.io/v2/swagger.json',
67
68
  serversPath: './src/apis/auth',
68
69
  },
69
- ] as GenerateServiceProps[];
70
+ ]);
70
71
  ```
71
72
 
72
73
  在 `package.json` 的 `script` 中添加命令: `"openapi": "openapi-ts",`
@@ -190,7 +191,7 @@ $ openapi --help
190
191
  -f, --full <boolean> full replacement (default: true)
191
192
  --enableLogging <boolean> open the log (default: false)
192
193
  --priorityRule <string> priority rule, include/exclude/both (default: "include")
193
- --filterCaseInsensitive <boolean> whether to perform a case-insensitive match with includeTags, includePaths, excludeTags, excludePaths filters
194
+ --filterCaseInsensitive <boolean> whether to perform a case-insensitive match with includeTags, includePaths, excludeTags, excludePaths filters (default: false)
194
195
  --includeTags <(string|RegExp)[]> generate code from include tags
195
196
  --includePaths <(string|RegExp)[]> generate code from include paths
196
197
  --excludeTags <(string|RegExp)[]> generate code from exclude tags
@@ -227,6 +228,7 @@ openapi --i ./spec.json --o ./apis
227
228
  | serversPath | 否 | string | './src/apis' | 运行结果文件夹路径 |
228
229
  | requestLibPath | 否 | string | 'axios' | 自定义请求方法路径,例如:'@/request'、'node-fetch' |
229
230
  | full | 否 | boolean | true | 是否全量替换 |
231
+ | describe | 否 | string | - | 描述信息,在用 cli 可交互运行方式时会用到 |
230
232
  | enableLogging | 否 | boolean | false | 是否开启日志 |
231
233
  | priorityRule | 否 | string | 'include' | 模式规则,可选include/exclude/both |
232
234
  | filterCaseInsensitive | 否 | boolean | false | 执行 includeTags、includePaths、excludeTags、excludePaths 过滤时是否忽略大小写 |
@@ -266,6 +268,8 @@ openapi --i ./spec.json --o ./apis
266
268
  | customTemplates | {<br>[TypescriptFileType.serviceController]?: <T, U>(item: T, context: U) => string;<br>} | 自定义模板,详情请看源码 |
267
269
  | customRenderTemplateData | {<br>[TypescriptFileType]?: (list: any[], context: {fileName: string, params: Record<string, unknown>}) => any[]<br>} | 自定义文件生成时的 list 参数处理,支持对不同文件类型进行精细化控制 |
268
270
 
271
+ [hooks 示例](https://github.com/openapi-ui/openapi-ts-request/blob/main/agents.md#-advanced-customization-hooks)
272
+
269
273
  ## Apifox-Config
270
274
 
271
275
  | 属性 | 类型 | 说明 | 必填 |
@@ -343,7 +347,8 @@ export default {
343
347
  4. 确保你的代码可以通过所有测试用例(新增功能需要添加新的功能测试用例):`pnpm test:unit`
344
348
  5. 创建 changeset 文件通过命令:`pnpm changeset`
345
349
  6. 使用 commit 提交你的修改(需遵循 commitlint 规范)
346
- 7. 发起 Pull Request
350
+ 7. 如果涉及文档,请同步更新 README.md、READMD-en_US.md、agents.md
351
+ 8. 发起 Pull Request
347
352
 
348
353
  ## 感谢
349
354
 
package/dist/bin/cli.js CHANGED
@@ -2,9 +2,10 @@
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const tslib_1 = require("tslib");
5
- const chalk_1 = tslib_1.__importDefault(require("chalk"));
5
+ const prompts_1 = require("@clack/prompts");
6
6
  const commander_1 = require("commander");
7
7
  const index_1 = require("../index");
8
+ const log_1 = require("../log");
8
9
  const readConfig_1 = require("../readConfig");
9
10
  commander_1.program
10
11
  .option('-cfn, --configFileName <string>', 'config file name')
@@ -12,6 +13,11 @@ commander_1.program
12
13
  .option('-u, --uniqueKey <string>', 'unique key');
13
14
  commander_1.program.parse();
14
15
  const options = commander_1.program.opts();
16
+ /**
17
+ * 1. 执行 cli 命令读取配置文件,已经使用 openapi.ts 替代了 cli.ts,后期会废弃 cli.ts
18
+ * 2. 如果配置文件中有 uniqueKey,则根据 uniqueKey 生成 service
19
+ * 3. 如果配置文件中没有 uniqueKey,且有多个 service,则交互式选择要生成的 service
20
+ */
15
21
  function run() {
16
22
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
17
23
  const config = yield (0, readConfig_1.readConfig)({
@@ -25,30 +31,55 @@ function run() {
25
31
  let configs = Array.isArray(config)
26
32
  ? config
27
33
  : [config];
34
+ /** 是否交互式 */
35
+ let isInteractive = false;
28
36
  if (options.uniqueKey) {
29
37
  configs = configs.filter((config) => config.uniqueKey === options.uniqueKey);
30
38
  }
39
+ else if (configs.length > 1) {
40
+ // 如果没有指定 uniqueKey,并且有多个配置,则交互式选择
41
+ isInteractive = true;
42
+ console.log(''); // 添加一个空行
43
+ (0, prompts_1.intro)('🎉 欢迎使用 openapi-ts-request 生成器');
44
+ const selected = yield (0, prompts_1.multiselect)({
45
+ message: '请选择要生成的 service',
46
+ options: configs.map((config) => ({
47
+ value: config,
48
+ label: config.describe || config.schemaPath,
49
+ })),
50
+ });
51
+ if ((0, prompts_1.isCancel)(selected)) {
52
+ (0, prompts_1.cancel)('👋 Has cancelled');
53
+ process.exit(0);
54
+ }
55
+ configs = selected;
56
+ }
31
57
  for (const config of configs) {
32
58
  tasks.push((0, index_1.generateService)(config));
33
59
  }
34
60
  const results = yield Promise.allSettled(tasks);
35
- const errors = results.filter((result) => result.status === 'rejected');
36
61
  let errorMsg = '';
37
- for (let i = 0; i < errors.length; i++) {
38
- const error = errors[i];
39
- const cnf = configs[i];
40
- errorMsg += `${cnf.uniqueKey}${cnf.uniqueKey && ':'}${error.reason}\n`;
62
+ for (let i = 0; i < results.length; i++) {
63
+ const result = results[i];
64
+ if (result.status === 'rejected') {
65
+ const cnf = configs[i];
66
+ errorMsg += `${cnf.uniqueKey}${cnf.uniqueKey && ':'}${result.reason}\n`;
67
+ }
41
68
  }
42
69
  if (errorMsg) {
43
70
  throw new Error(errorMsg);
44
71
  }
72
+ if (isInteractive && !errorMsg) {
73
+ (0, prompts_1.outro)('🎉 All done!');
74
+ }
45
75
  }
46
76
  else {
47
77
  throw new Error('config is not found');
48
78
  }
49
79
  }
50
80
  catch (error) {
51
- console.log(chalk_1.default.red(error));
81
+ (0, log_1.logError)(error);
82
+ process.exit(1);
52
83
  }
53
84
  });
54
85
  }
@@ -2,6 +2,7 @@
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const tslib_1 = require("tslib");
5
+ const prompts_1 = require("@clack/prompts");
5
6
  const commander_1 = require("commander");
6
7
  const lodash_1 = require("lodash");
7
8
  const path_1 = require("path");
@@ -21,8 +22,7 @@ const params = commander_1.program
21
22
  .option('--requestLibPath <string>', 'custom request lib path, for example: "@/request", "node-fetch" (default: "axios")')
22
23
  .option('-f, --full <boolean>', 'full replacement', true)
23
24
  .option('--enableLogging <boolean>', 'open the log', false)
24
- .option('--filterCaseInsensitive <boolean>', 'whether to perform a case-insensitive match with includeTags, includePaths, excludeTags, excludePaths filters', false)
25
- .option('--includeTags <(string|RegExp)[]>', 'generate code from include tags')
25
+ .option('--priorityRule <string>', 'priority rule, include/exclude/both (default: "include")')
26
26
  .option('--filterCaseInsensitive <boolean>', 'whether to perform a case-insensitive match with includeTags, includePaths, excludeTags, excludePaths filters', false)
27
27
  .option('--includeTags <(string|RegExp)[]>', 'generate code from include tags')
28
28
  .option('--includePaths <(string|RegExp)[]>', 'generate code from include paths')
@@ -100,33 +100,50 @@ function run() {
100
100
  if (cnf) {
101
101
  const tasks = [];
102
102
  let configs = Array.isArray(cnf) ? cnf : [cnf];
103
+ /** 是否交互式 */
104
+ let isInteractive = false;
103
105
  if (params.uniqueKey) {
104
106
  configs = configs.filter((config) => config.uniqueKey === params.uniqueKey);
105
107
  }
108
+ else if (configs.length > 1) {
109
+ // 如果没有指定 uniqueKey,并且有多个配置,则交互式选择
110
+ isInteractive = true;
111
+ console.log(''); // 添加一个空行
112
+ (0, prompts_1.intro)('🎉 欢迎使用 openapi-ts-request 生成器');
113
+ const selected = yield (0, prompts_1.multiselect)({
114
+ message: '请选择要生成的 service',
115
+ options: configs.map((config) => ({
116
+ value: config,
117
+ label: config.describe || config.schemaPath,
118
+ })),
119
+ });
120
+ if ((0, prompts_1.isCancel)(selected)) {
121
+ (0, prompts_1.cancel)('👋 Has cancelled');
122
+ process.exit(0);
123
+ }
124
+ configs = selected;
125
+ }
106
126
  for (const config of configs) {
107
127
  tasks.push((0, index_1.generateService)(config));
108
128
  }
109
129
  const results = yield Promise.allSettled(tasks);
110
- const errors = results.filter((result) => result.status === 'rejected');
111
130
  let errorMsg = '';
112
- for (let i = 0; i < errors.length; i++) {
113
- const error = errors[i];
114
- const cnf = configs[i];
115
- errorMsg += `${cnf.uniqueKey}${cnf.uniqueKey && ':'}${error.reason}\n`;
131
+ for (let i = 0; i < results.length; i++) {
132
+ const result = results[i];
133
+ if (result.status === 'rejected') {
134
+ const cnf = configs[i];
135
+ errorMsg += `${cnf.uniqueKey}${cnf.uniqueKey && ':'}${result.reason}\n`;
136
+ }
116
137
  }
117
138
  if (errorMsg) {
118
- (0, log_1.logError)(errorMsg);
119
- process.exit(1);
139
+ throw new Error(errorMsg);
140
+ }
141
+ if (isInteractive && !errorMsg) {
142
+ (0, prompts_1.outro)('🎉 All done!');
120
143
  }
121
144
  }
122
145
  else {
123
- if (!params.input || !params.output) {
124
- (0, log_1.logError)('Please provide either input/output options or a configuration file path and name.');
125
- process.exit(1);
126
- }
127
- const options = baseGenerate(params);
128
- yield (0, index_1.generateService)((0, lodash_1.pickBy)(options, (value) => value !== null && value !== undefined && value !== ''));
129
- process.exit(0);
146
+ throw new Error('Please provide either input/output options or a configuration file path and name.');
130
147
  }
131
148
  }
132
149
  catch (error) {
@@ -249,7 +249,7 @@ class ServiceGenerator {
249
249
  displayTypeLabelFileName: config_2.displayTypeLabelFileName,
250
250
  });
251
251
  // 打印日志
252
- (0, log_1.default)('✅ 成功生成 api 文件目录-> ', this.config.serversPath);
252
+ (0, log_1.default)('✅ 成功生成 api 文件目录-> ', ` ${this.config.serversPath}`);
253
253
  }
254
254
  getInterfaceTPConfigs() {
255
255
  var _a, _b, _c;
@@ -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: response === null || response === void 0 ? void 0 : response.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
- ((_c = (_b = newApi.responses) === null || _b === void 0 ? void 0 : _b.default) === null || _c === void 0 ? void 0 : _c.description)
498
- ? `返回值: ${((_d = newApi.responses) === null || _d === void 0 ? void 0 : _d.default).description}`
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: ((_f = (_e = this.config.hook) === null || _e === void 0 ? void 0 : _e.customOptionsDefaultValue) === null || _f === void 0 ? void 0 : _f.call(_e, newApi)) || {}, body,
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) {
package/dist/index.d.ts CHANGED
@@ -23,6 +23,10 @@ export type GenerateServiceProps = {
23
23
  * 是否全量替换, 默认: true, 如果为false, 则进行增量替换
24
24
  */
25
25
  full?: boolean;
26
+ /**
27
+ * 描述信息,在用 cli 可交互运行方式时会用到
28
+ */
29
+ describe?: string;
26
30
  /**
27
31
  * 开启日志
28
32
  */
@@ -280,3 +284,7 @@ export type GenerateServiceProps = {
280
284
  };
281
285
  };
282
286
  export declare function generateService({ requestLibPath, schemaPath, mockFolder, includeTags, excludeTags, includePaths, excludePaths, authorization, isTranslateToEnglishTag, priorityRule, timeout, reactQueryMode, apifoxConfig, ...rest }: GenerateServiceProps): Promise<void>;
287
+ /**
288
+ * Defines the configuration for openapi-ts-request.
289
+ */
290
+ export declare function defineConfig(config: GenerateServiceProps | GenerateServiceProps[]): GenerateServiceProps | GenerateServiceProps[];
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateService = generateService;
4
+ exports.defineConfig = defineConfig;
4
5
  const tslib_1 = require("tslib");
5
6
  const lodash_1 = require("lodash");
6
7
  const config_1 = require("./config");
@@ -53,3 +54,9 @@ function generateService(_a) {
53
54
  }
54
55
  });
55
56
  }
57
+ /**
58
+ * Defines the configuration for openapi-ts-request.
59
+ */
60
+ function defineConfig(config) {
61
+ return config;
62
+ }
package/dist/log.js CHANGED
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.logError = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
6
- const log = (...rest) => console.log(`${chalk_1.default.blue('[openAPI]')}: ${rest.join('\n')}`);
7
- const logError = (...rest) => console.error(`${chalk_1.default.red('❌ [openAPI]')}: ${rest.join('\n')}`);
6
+ const log = (...rest) => console.log(` ${chalk_1.default.blue('[openAPI]')}: ${rest.join('\n')}`);
7
+ const logError = (...rest) => console.error(` ${chalk_1.default.red('❌ [openAPI]')}: ${rest.join('\n')}`);
8
8
  exports.logError = logError;
9
9
  exports.default = log;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openapi-ts-request",
3
- "version": "1.9.1",
3
+ "version": "1.10.0",
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",
@@ -24,6 +24,7 @@
24
24
  "prettier.config.cjs"
25
25
  ],
26
26
  "dependencies": {
27
+ "@clack/prompts": "^0.11.0",
27
28
  "@prettier/sync": "^0.6.1",
28
29
  "@trivago/prettier-plugin-sort-imports": "^5.2.1",
29
30
  "axios": "^1.7.2",