@karry.sun/yapi-gen 0.1.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 +73 -0
- package/bin/yapi-gen.js +14 -0
- package/dist/adapters/axios.d.ts +14 -0
- package/dist/adapters/axios.d.ts.map +1 -0
- package/dist/adapters/axios.js +48 -0
- package/dist/adapters/nuxt-bbm.d.ts +14 -0
- package/dist/adapters/nuxt-bbm.d.ts.map +1 -0
- package/dist/adapters/nuxt-bbm.js +23 -0
- package/dist/config/index.d.ts +14 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +21 -0
- package/dist/config/schema.d.ts +98 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +15 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/resolve-config.d.ts +7 -0
- package/dist/resolve-config.d.ts.map +1 -0
- package/dist/resolve-config.js +115 -0
- package/dist/run.d.ts +6 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +117 -0
- package/package.json +59 -0
- package/templates/request-axios.ts +33 -0
- package/templates/request-defhttp.ts +53 -0
- package/templates/request-nuxt.ts +25 -0
package/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# yapi-gen
|
|
2
|
+
|
|
3
|
+
基于 [yapi-to-typescript](https://github.com/fjc0k/yapi-to-typescript) 的 YApi 前端代码生成 CLI,支持可配置的请求适配器与多项目复用。适用于 Vite、Nuxt、Vue 等不同请求封装(axios、defHttp、Nuxt request 等)。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add -D yapi-gen yapi-to-typescript
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 快速开始
|
|
12
|
+
|
|
13
|
+
### 1. 初始化配置
|
|
14
|
+
|
|
15
|
+
在项目根目录执行:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm yapi-gen init
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
会生成 `yapi-gen.config.ts`,按需修改 `serverUrl`、`token`、`requestAdapter`、`outputFilePath` 等。
|
|
22
|
+
|
|
23
|
+
### 2. 选择请求适配方式
|
|
24
|
+
|
|
25
|
+
- **内置预设(推荐)**:在配置中设置 `requestAdapter: 'axios'` 或 `requestAdapter: 'nuxt-bbm'`,无需在各仓库维护 `request.ts`,运行 `yapi-gen` 时会自动生成并写入 `src/yapi/request.ts`(路径可配)。
|
|
26
|
+
- **axios**:适用于封装了 axios 的项目(如 defHttp)。可选 `requestAdapter: { type: 'axios', axiosInstancePath: '/@/utils/http/axios' }` 指定实例路径,默认 `'/@/utils/http/axios'`(defHttp 常见路径)。
|
|
27
|
+
- **nuxt-bbm**:适用于 Nuxt 项目,使用 Layer 的 `#imports` 或 `@bitunix/bbm` 的 request。可选 `requestAdapter: { type: 'nuxt-bbm', requestImportPath: '#imports' }`,默认 `'#imports'`。
|
|
28
|
+
- **自定义**:设置 `requestAdapter: 'custom'` 并配置 `requestFunctionFilePath`,在对应文件中自行实现适配逻辑;或参考包内 `templates/request-*.ts` 复制后修改。
|
|
29
|
+
|
|
30
|
+
### 3. 生成接口代码
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pnpm yapi-gen
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
会在当前目录查找 `yapi-gen.config.ts`(或 `.yapi-genrc.ts` 等),生成临时 ytt 配置并执行 `ytt`,输出到你在 `outputFilePath` 中配置的目录。
|
|
37
|
+
|
|
38
|
+
## 配置说明
|
|
39
|
+
|
|
40
|
+
`yapi-gen.config.ts` 使用 `defineYapiGenConfig` 导出单条配置(或数组,多条会合并为 `defineConfig([...])`)。主要字段与 [yapi-to-typescript 配置](https://fjc0k.github.io/yapi-to-typescript/handbook/config.html) 对齐:
|
|
41
|
+
|
|
42
|
+
| 字段 | 说明 | 必填 |
|
|
43
|
+
|------|------|------|
|
|
44
|
+
| `serverUrl` | YApi 服务器地址 | 是 |
|
|
45
|
+
| `serverType` | `'yapi'` \| `'swagger'` | 否,默认 `'yapi'` |
|
|
46
|
+
| `requestAdapter` | 请求适配方式:`'axios'` / `'nuxt-bbm'` / `'custom'`,或对象形式带可选参数 | 否,与 `requestFunctionFilePath` 二选一 |
|
|
47
|
+
| `requestFunctionFilePath` | 请求适配器文件路径;使用预设时可选(默认 `src/yapi/request.ts`),custom 时必填 | custom 时必填 |
|
|
48
|
+
| `outputFilePath` | 生成文件路径或函数 `(interfaceInfo, changeCase) => string` | 是 |
|
|
49
|
+
| `projects` | 项目列表,每项含 `token`、`categories` | 是 |
|
|
50
|
+
| `dataKey` | 业务数据字段,如 `'result'`,适配器需据此解包 | 否 |
|
|
51
|
+
| `prodEnvName` / `devEnvName` | 生产/测试环境名称(用于域名) | 否 |
|
|
52
|
+
| `typesOnly` | 是否只生成类型 | 否,默认 `false` |
|
|
53
|
+
| `target` | `'typescript'` \| `'javascript'` | 否,默认 `'typescript'` |
|
|
54
|
+
| `reactHooks` | React Hooks 生成配置 | 否 |
|
|
55
|
+
| `preproccessInterface` | 预处理/过滤接口 | 否 |
|
|
56
|
+
| `getRequestFunctionName` | 请求函数命名 | 否 |
|
|
57
|
+
|
|
58
|
+
YApi 的 **token** 建议通过环境变量注入,例如在 `projects[].token` 中写 `process.env.YAPI_TOKEN || 'fallback'`。
|
|
59
|
+
|
|
60
|
+
## 在现有项目中使用
|
|
61
|
+
|
|
62
|
+
- **web-finance-admin(defHttp)**:在 `yapi-gen.config.ts` 中设置 `requestAdapter: 'axios'`(或 `{ type: 'axios', axiosInstancePath: '/@/utils/http/axios' }`),无需再维护 `request.ts`;或继续使用 `requestAdapter: 'custom'` 并保留现有 `requestFunctionFilePath`。
|
|
63
|
+
- **pc(Nuxt / @bitunix/bbm)**:设置 `requestAdapter: 'nuxt-bbm'`(或 `{ type: 'nuxt-bbm', requestImportPath: '#imports' }`),无需再维护 `request.ts`;或使用 `custom` 并指向现有文件。
|
|
64
|
+
|
|
65
|
+
## 配置文件查找顺序
|
|
66
|
+
|
|
67
|
+
CLI 会按以下顺序查找配置(找到即用):
|
|
68
|
+
|
|
69
|
+
`yapi-gen.config.ts`、`yapi-gen.config.mts`、`yapi-gen.config.cts`、`yapi-gen.config.js`、`yapi-gen.config.mjs`、`yapi-gen.config.cjs`、`.yapi-genrc.ts`、`.yapi-genrc.mts`、`.yapi-genrc.js`、`.yapi-genrc.mjs`。
|
|
70
|
+
|
|
71
|
+
## License
|
|
72
|
+
|
|
73
|
+
MIT
|
package/bin/yapi-gen.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { dirname, join } from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { pathToFileURL } from 'url';
|
|
6
|
+
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const runPath = join(__dirname, '..', 'dist', 'run.js');
|
|
9
|
+
const runUrl = pathToFileURL(runPath).href;
|
|
10
|
+
|
|
11
|
+
const { run } = await import(runUrl);
|
|
12
|
+
const init = process.argv.includes('init');
|
|
13
|
+
const code = run({ cwd: process.cwd(), init });
|
|
14
|
+
process.exit(code);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 内置适配器:封装 axios / defHttp 的工厂
|
|
3
|
+
* 生成的 request 文件会 import 项目的 axios 实例并传入此工厂
|
|
4
|
+
*/
|
|
5
|
+
import type { RequestFunctionParams } from 'yapi-to-typescript';
|
|
6
|
+
export type AxiosLikeInstance = {
|
|
7
|
+
get: (config: any) => Promise<any>;
|
|
8
|
+
post: (config: any) => Promise<any>;
|
|
9
|
+
put: (config: any) => Promise<any>;
|
|
10
|
+
delete: (config: any) => Promise<any>;
|
|
11
|
+
request?: (config: any) => Promise<any>;
|
|
12
|
+
};
|
|
13
|
+
export declare function createAxiosAdapter(instance: AxiosLikeInstance): <TResponseData>(payload: RequestFunctionParams) => Promise<TResponseData>;
|
|
14
|
+
//# sourceMappingURL=axios.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"axios.d.ts","sourceRoot":"","sources":["../../src/adapters/axios.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAEhE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,GAAG,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,MAAM,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;IACtC,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;CACzC,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,iBAAiB,IAC9B,aAAa,EACzC,SAAS,qBAAqB,KAC7B,OAAO,CAAC,aAAa,CAAC,CA+C1B"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export function createAxiosAdapter(instance) {
|
|
2
|
+
return async function request(payload) {
|
|
3
|
+
const { method, path, data, hasFileData, getFormData } = payload;
|
|
4
|
+
const url = path;
|
|
5
|
+
const isGet = method === 'GET' || method === 'HEAD' || method === 'OPTIONS';
|
|
6
|
+
let config;
|
|
7
|
+
if (isGet) {
|
|
8
|
+
config = { url, params: {} };
|
|
9
|
+
}
|
|
10
|
+
else if (hasFileData && getFormData) {
|
|
11
|
+
config = { url, params: getFormData() };
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
config = { url, params: data || {} };
|
|
15
|
+
}
|
|
16
|
+
let res;
|
|
17
|
+
switch (method) {
|
|
18
|
+
case 'GET':
|
|
19
|
+
case 'HEAD':
|
|
20
|
+
case 'OPTIONS':
|
|
21
|
+
res = await instance.get(config);
|
|
22
|
+
break;
|
|
23
|
+
case 'POST':
|
|
24
|
+
res = await instance.post(config);
|
|
25
|
+
break;
|
|
26
|
+
case 'PUT':
|
|
27
|
+
res = await instance.put(config);
|
|
28
|
+
break;
|
|
29
|
+
case 'DELETE':
|
|
30
|
+
res = await instance.delete(config);
|
|
31
|
+
break;
|
|
32
|
+
case 'PATCH':
|
|
33
|
+
res = await (instance.request ?? instance.post)({ ...config, method: 'PATCH' });
|
|
34
|
+
break;
|
|
35
|
+
default:
|
|
36
|
+
res = await instance.post(config);
|
|
37
|
+
}
|
|
38
|
+
const key = payload.dataKey;
|
|
39
|
+
if (res != null && typeof res === 'object' && key != null) {
|
|
40
|
+
const val = Array.isArray(key)
|
|
41
|
+
? key.reduce((o, k) => o?.[k], res)
|
|
42
|
+
: res[key];
|
|
43
|
+
if (val !== undefined && val !== null)
|
|
44
|
+
return val;
|
|
45
|
+
}
|
|
46
|
+
return res;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 内置适配器:Nuxt Layer @bitunix/bbm 或 #imports 的 request 工厂
|
|
3
|
+
* 生成的 request 文件会 import 项目的 request 并传入此工厂
|
|
4
|
+
*/
|
|
5
|
+
import type { RequestFunctionParams } from 'yapi-to-typescript';
|
|
6
|
+
export type NuxtRequestLike = <T = any>(path: string, options?: {
|
|
7
|
+
baseURL?: string;
|
|
8
|
+
method?: string;
|
|
9
|
+
body?: any;
|
|
10
|
+
query?: any;
|
|
11
|
+
tips?: boolean;
|
|
12
|
+
}) => Promise<T>;
|
|
13
|
+
export declare function createNuxtAdapter(requestFn: NuxtRequestLike): <TResponseData>(payload: RequestFunctionParams) => Promise<TResponseData>;
|
|
14
|
+
//# sourceMappingURL=nuxt-bbm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nuxt-bbm.d.ts","sourceRoot":"","sources":["../../src/adapters/nuxt-bbm.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAEhE,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,GAAG,GAAG,EACpC,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,GAAG,CAAC;IAAC,KAAK,CAAC,EAAE,GAAG,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,KACrF,OAAO,CAAC,CAAC,CAAC,CAAC;AAEhB,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,eAAe,IACrB,aAAa,EAChD,SAAS,qBAAqB,KAC7B,OAAO,CAAC,aAAa,CAAC,CAsB1B"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function createNuxtAdapter(requestFn) {
|
|
2
|
+
return async function requestAdapter(payload) {
|
|
3
|
+
const baseUrl = typeof import.meta !== 'undefined' && import.meta.dev
|
|
4
|
+
? payload.devUrl
|
|
5
|
+
: payload.prodUrl;
|
|
6
|
+
const res = await requestFn(payload.path, {
|
|
7
|
+
baseURL: baseUrl || '',
|
|
8
|
+
method: payload.method.toLowerCase(),
|
|
9
|
+
...(payload.requestBodyType === 'json' && payload.data ? { body: payload.data } : {}),
|
|
10
|
+
...(payload.requestBodyType === 'query' && payload.data ? { query: payload.data } : {}),
|
|
11
|
+
tips: false,
|
|
12
|
+
});
|
|
13
|
+
const key = payload.dataKey;
|
|
14
|
+
if (res != null && typeof res === 'object' && key != null) {
|
|
15
|
+
const val = Array.isArray(key)
|
|
16
|
+
? key.reduce((o, k) => o?.[k], res)
|
|
17
|
+
: res[key];
|
|
18
|
+
if (val !== undefined && val !== null)
|
|
19
|
+
return val;
|
|
20
|
+
}
|
|
21
|
+
return res;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { YapiGenUserConfig } from './schema';
|
|
2
|
+
/**
|
|
3
|
+
* 合并用户配置与默认配置,返回可直接用于 defineConfig([...]) 的配置对象
|
|
4
|
+
*/
|
|
5
|
+
export declare function mergeConfig(user: YapiGenUserConfig): YapiGenUserConfig;
|
|
6
|
+
/**
|
|
7
|
+
* 定义 yapi-gen 配置的辅助函数,带类型提示与默认值
|
|
8
|
+
* 在项目根目录的 yapi-gen.config.ts 中使用:
|
|
9
|
+
* import { defineYapiGenConfig } from 'yapi-gen';
|
|
10
|
+
* export default defineYapiGenConfig({ serverUrl: '...', ... });
|
|
11
|
+
*/
|
|
12
|
+
export declare function defineYapiGenConfig(config: YapiGenUserConfig): YapiGenUserConfig;
|
|
13
|
+
export type { YapiGenUserConfig, YapiGenProjectConfig, YapiGenCategoryConfig, YapiGenReactHooksConfig, YapiGenRequestAdapter, } from './schema';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAGlD;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,iBAAiB,GAAG,iBAAiB,CAOtE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,CAEhF;AAED,YAAY,EACV,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,UAAU,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { getDefaultConfig } from './schema';
|
|
2
|
+
/**
|
|
3
|
+
* 合并用户配置与默认配置,返回可直接用于 defineConfig([...]) 的配置对象
|
|
4
|
+
*/
|
|
5
|
+
export function mergeConfig(user) {
|
|
6
|
+
const defaults = getDefaultConfig();
|
|
7
|
+
return {
|
|
8
|
+
...defaults,
|
|
9
|
+
...user,
|
|
10
|
+
reactHooks: user.reactHooks ?? defaults.reactHooks,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 定义 yapi-gen 配置的辅助函数,带类型提示与默认值
|
|
15
|
+
* 在项目根目录的 yapi-gen.config.ts 中使用:
|
|
16
|
+
* import { defineYapiGenConfig } from 'yapi-gen';
|
|
17
|
+
* export default defineYapiGenConfig({ serverUrl: '...', ... });
|
|
18
|
+
*/
|
|
19
|
+
export function defineYapiGenConfig(config) {
|
|
20
|
+
return mergeConfig(config);
|
|
21
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 用户配置类型定义
|
|
3
|
+
* 与 yapi-to-typescript 的 ServerConfig 对齐,便于透传
|
|
4
|
+
*/
|
|
5
|
+
export interface YapiGenCategoryConfig {
|
|
6
|
+
id: number | number[];
|
|
7
|
+
getRequestFunctionName?: (interfaceInfo: any, changeCase: {
|
|
8
|
+
camelCase: (s: string) => string;
|
|
9
|
+
paramCase: (s: string) => string;
|
|
10
|
+
pascalCase: (s: string) => string;
|
|
11
|
+
}) => string;
|
|
12
|
+
}
|
|
13
|
+
export interface YapiGenProjectConfig {
|
|
14
|
+
token: string | string[];
|
|
15
|
+
categories: YapiGenCategoryConfig[];
|
|
16
|
+
}
|
|
17
|
+
export interface YapiGenReactHooksConfig {
|
|
18
|
+
enabled: boolean;
|
|
19
|
+
requestHookMakerFilePath?: string;
|
|
20
|
+
getRequestHookName?: (interfaceInfo: any, changeCase: any) => string;
|
|
21
|
+
}
|
|
22
|
+
/** 请求适配方式:内置预设(关键字)或自定义 */
|
|
23
|
+
export type YapiGenRequestAdapter = 'axios' | 'nuxt-bbm' | 'custom' | {
|
|
24
|
+
type: 'axios';
|
|
25
|
+
axiosInstancePath?: string;
|
|
26
|
+
axiosExportName?: 'defHttp' | 'default';
|
|
27
|
+
} | {
|
|
28
|
+
type: 'nuxt-bbm';
|
|
29
|
+
requestImportPath?: string;
|
|
30
|
+
} | {
|
|
31
|
+
type: 'custom';
|
|
32
|
+
requestFunctionFilePath: string;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* 用户可在 yapi-gen.config.ts 中使用的配置项
|
|
36
|
+
* 未填的项将使用下方默认值
|
|
37
|
+
*/
|
|
38
|
+
export interface YapiGenUserConfig {
|
|
39
|
+
/** YApi 服务器地址(必填) */
|
|
40
|
+
serverUrl: string;
|
|
41
|
+
/** 服务器类型 */
|
|
42
|
+
serverType?: 'yapi' | 'swagger';
|
|
43
|
+
/** 是否只生成类型 */
|
|
44
|
+
typesOnly?: boolean;
|
|
45
|
+
/** 生成目标语言 */
|
|
46
|
+
target?: 'typescript' | 'javascript';
|
|
47
|
+
/** 生产环境名称(用于获取生产环境域名) */
|
|
48
|
+
prodEnvName?: string;
|
|
49
|
+
/** 测试环境名称 */
|
|
50
|
+
devEnvName?: string;
|
|
51
|
+
/** 业务数据字段,如 'result' / 'data',请求函数需据此解包 */
|
|
52
|
+
dataKey?: string | string[];
|
|
53
|
+
/**
|
|
54
|
+
* 请求适配方式(与 requestFunctionFilePath 二选一):
|
|
55
|
+
* - 'axios':封装 axios/defHttp,可选 axiosInstancePath
|
|
56
|
+
* - 'nuxt-bbm':Nuxt Layer @bitunix/bbm 或 #imports,可选 requestImportPath
|
|
57
|
+
* - 'custom':使用 requestFunctionFilePath 指向的自定义 request.ts
|
|
58
|
+
* 使用预设时可不填 requestFunctionFilePath,默认生成到 src/yapi/request.ts
|
|
59
|
+
*/
|
|
60
|
+
requestAdapter?: YapiGenRequestAdapter;
|
|
61
|
+
/** 项目内请求适配器文件路径(custom 时必填;使用预设时可选,默认 src/yapi/request.ts) */
|
|
62
|
+
requestFunctionFilePath?: string;
|
|
63
|
+
/** 输出文件路径或函数(必填) */
|
|
64
|
+
outputFilePath: string | ((interfaceInfo: any, changeCase: {
|
|
65
|
+
paramCase: (s: string) => string;
|
|
66
|
+
camelCase: (s: string) => string;
|
|
67
|
+
pascalCase: (s: string) => string;
|
|
68
|
+
}) => string);
|
|
69
|
+
/** 预处理接口,可过滤或改写 */
|
|
70
|
+
preproccessInterface?: (interfaceInfo: any, changeCase?: any, syntheticalConfig?: any) => any | false;
|
|
71
|
+
/** 请求函数命名 */
|
|
72
|
+
getRequestFunctionName?: (interfaceInfo: any, changeCase: any) => string;
|
|
73
|
+
/** 请求数据类型命名 */
|
|
74
|
+
getRequestDataTypeName?: (interfaceInfo: any, changeCase: any) => string;
|
|
75
|
+
/** 响应数据类型命名 */
|
|
76
|
+
getResponseDataTypeName?: (interfaceInfo: any, changeCase: any) => string;
|
|
77
|
+
/** React Hooks 相关 */
|
|
78
|
+
reactHooks?: YapiGenReactHooksConfig;
|
|
79
|
+
/** 项目列表(必填) */
|
|
80
|
+
projects: YapiGenProjectConfig[];
|
|
81
|
+
/** 不生成更新时间注释 */
|
|
82
|
+
noUpdateTimeComment?: boolean;
|
|
83
|
+
/** 注释配置 */
|
|
84
|
+
comment?: Record<string, boolean | unknown>;
|
|
85
|
+
/** JSON Schema 配置 */
|
|
86
|
+
jsonSchema?: Record<string, boolean | unknown>;
|
|
87
|
+
/** 查询字符串数组格式 */
|
|
88
|
+
queryStringArrayFormat?: 'brackets' | 'indices' | 'repeat' | 'comma' | 'json';
|
|
89
|
+
/** 自定义类型映射 */
|
|
90
|
+
customTypeMapping?: Record<string, string>;
|
|
91
|
+
/** 请求函数 extraInfo */
|
|
92
|
+
setRequestFunctionExtraInfo?: (interfaceInfo: any, changeCase: any) => Record<string, unknown>;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* 默认配置(与 ytt 常用默认一致)
|
|
96
|
+
*/
|
|
97
|
+
export declare function getDefaultConfig(): Partial<YapiGenUserConfig>;
|
|
98
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const DEFAULT_REACT_HOOKS = {
|
|
2
|
+
enabled: false,
|
|
3
|
+
};
|
|
4
|
+
/**
|
|
5
|
+
* 默认配置(与 ytt 常用默认一致)
|
|
6
|
+
*/
|
|
7
|
+
export function getDefaultConfig() {
|
|
8
|
+
return {
|
|
9
|
+
serverType: 'yapi',
|
|
10
|
+
typesOnly: false,
|
|
11
|
+
target: 'typescript',
|
|
12
|
+
reactHooks: DEFAULT_REACT_HOOKS,
|
|
13
|
+
prodEnvName: 'production',
|
|
14
|
+
};
|
|
15
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* yapi-gen
|
|
3
|
+
* 基于 yapi-to-typescript 的 YApi 前端代码生成 CLI,支持可配置的请求适配器与多项目复用
|
|
4
|
+
*/
|
|
5
|
+
export { defineYapiGenConfig, mergeConfig } from './config';
|
|
6
|
+
export { resolveConfig } from './resolve-config';
|
|
7
|
+
export type { YapiGenUserConfig, YapiGenProjectConfig, YapiGenCategoryConfig, YapiGenReactHooksConfig, YapiGenRequestAdapter, } from './config/schema';
|
|
8
|
+
export type { RequestFunctionParams } from 'yapi-to-typescript';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,YAAY,EACV,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,iBAAiB,CAAC;AAGzB,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { YapiGenUserConfig } from './config/schema';
|
|
2
|
+
/**
|
|
3
|
+
* 解析配置:若为预设(axios / nuxt-bbm),则生成并写入 request 文件,并补全 requestFunctionFilePath;
|
|
4
|
+
* 返回去掉 requestAdapter 等字段、可供 ytt defineConfig 使用的配置。
|
|
5
|
+
*/
|
|
6
|
+
export declare function resolveConfig(config: YapiGenUserConfig, cwd: string): YapiGenUserConfig;
|
|
7
|
+
//# sourceMappingURL=resolve-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-config.d.ts","sourceRoot":"","sources":["../src/resolve-config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAyB,MAAM,iBAAiB,CAAC;AAiFhF;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,iBAAiB,EAAE,GAAG,EAAE,MAAM,GAAG,iBAAiB,CA0CvF"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 在运行 ytt 前解析配置:处理 requestAdapter 预设,生成并写入 request 文件,得到 ytt 可用的配置
|
|
3
|
+
*/
|
|
4
|
+
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
5
|
+
import { resolve, dirname } from 'path';
|
|
6
|
+
const DEFAULT_REQUEST_FILE_PATH = 'src/yapi/request.ts';
|
|
7
|
+
const DEFAULT_AXIOS_INSTANCE_PATH = "/@/utils/http/axios";
|
|
8
|
+
const DEFAULT_NUXT_REQUEST_IMPORT_PATH = '#imports';
|
|
9
|
+
function normalizeRequestAdapter(adapter) {
|
|
10
|
+
if (adapter == null) {
|
|
11
|
+
return { type: 'custom' };
|
|
12
|
+
}
|
|
13
|
+
if (adapter === 'axios') {
|
|
14
|
+
return {
|
|
15
|
+
type: 'axios',
|
|
16
|
+
axiosInstancePath: DEFAULT_AXIOS_INSTANCE_PATH,
|
|
17
|
+
axiosExportName: 'defHttp',
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
if (adapter === 'nuxt-bbm') {
|
|
21
|
+
return { type: 'nuxt-bbm', requestImportPath: DEFAULT_NUXT_REQUEST_IMPORT_PATH };
|
|
22
|
+
}
|
|
23
|
+
if (adapter === 'custom') {
|
|
24
|
+
return { type: 'custom' };
|
|
25
|
+
}
|
|
26
|
+
if (typeof adapter === 'object') {
|
|
27
|
+
if (adapter.type === 'axios') {
|
|
28
|
+
return {
|
|
29
|
+
type: 'axios',
|
|
30
|
+
axiosInstancePath: adapter.axiosInstancePath ?? DEFAULT_AXIOS_INSTANCE_PATH,
|
|
31
|
+
axiosExportName: adapter.axiosExportName ?? 'defHttp',
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
if (adapter.type === 'nuxt-bbm') {
|
|
35
|
+
return {
|
|
36
|
+
type: 'nuxt-bbm',
|
|
37
|
+
requestImportPath: adapter.requestImportPath ?? DEFAULT_NUXT_REQUEST_IMPORT_PATH,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
if (adapter.type === 'custom') {
|
|
41
|
+
return {
|
|
42
|
+
type: 'custom',
|
|
43
|
+
requestFunctionFilePath: adapter.requestFunctionFilePath,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return { type: 'custom' };
|
|
48
|
+
}
|
|
49
|
+
function getAxiosAdapterFileContent(axiosInstancePath, exportName) {
|
|
50
|
+
const importLine = exportName === 'default'
|
|
51
|
+
? `import defHttp from '${axiosInstancePath}';`
|
|
52
|
+
: `import { defHttp } from '${axiosInstancePath}';`;
|
|
53
|
+
return `/**
|
|
54
|
+
* 由 yapi-gen 预设 "axios" 自动生成,请勿直接修改。
|
|
55
|
+
* 如需自定义请求逻辑,请将配置改为 requestAdapter: 'custom' 并维护 requestFunctionFilePath 指向的文件。
|
|
56
|
+
*/
|
|
57
|
+
import { createAxiosAdapter } from 'yapi-gen/adapters/axios';
|
|
58
|
+
${importLine}
|
|
59
|
+
|
|
60
|
+
export default createAxiosAdapter(defHttp);
|
|
61
|
+
`;
|
|
62
|
+
}
|
|
63
|
+
function getNuxtBbmAdapterFileContent(requestImportPath) {
|
|
64
|
+
return `/**
|
|
65
|
+
* 由 yapi-gen 预设 "nuxt-bbm" 自动生成,请勿直接修改。
|
|
66
|
+
* 如需自定义请求逻辑,请将配置改为 requestAdapter: 'custom' 并维护 requestFunctionFilePath 指向的文件。
|
|
67
|
+
*/
|
|
68
|
+
import { createNuxtAdapter } from 'yapi-gen/adapters/nuxt-bbm';
|
|
69
|
+
import { request } from '${requestImportPath}';
|
|
70
|
+
|
|
71
|
+
export default createNuxtAdapter(request);
|
|
72
|
+
`;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* 解析配置:若为预设(axios / nuxt-bbm),则生成并写入 request 文件,并补全 requestFunctionFilePath;
|
|
76
|
+
* 返回去掉 requestAdapter 等字段、可供 ytt defineConfig 使用的配置。
|
|
77
|
+
*/
|
|
78
|
+
export function resolveConfig(config, cwd) {
|
|
79
|
+
const resolved = { ...config };
|
|
80
|
+
const adapter = normalizeRequestAdapter(resolved.requestAdapter);
|
|
81
|
+
const requestFilePath = resolved.requestFunctionFilePath ?? adapter.requestFunctionFilePath ?? DEFAULT_REQUEST_FILE_PATH;
|
|
82
|
+
if (adapter.type === 'axios') {
|
|
83
|
+
const content = getAxiosAdapterFileContent(adapter.axiosInstancePath, adapter.axiosExportName ?? 'defHttp');
|
|
84
|
+
const absolutePath = resolve(cwd, requestFilePath);
|
|
85
|
+
const dir = dirname(absolutePath);
|
|
86
|
+
if (!existsSync(dir)) {
|
|
87
|
+
mkdirSync(dir, { recursive: true });
|
|
88
|
+
}
|
|
89
|
+
writeFileSync(absolutePath, content, 'utf-8');
|
|
90
|
+
resolved.requestFunctionFilePath = requestFilePath;
|
|
91
|
+
delete resolved.requestAdapter;
|
|
92
|
+
return resolved;
|
|
93
|
+
}
|
|
94
|
+
if (adapter.type === 'nuxt-bbm') {
|
|
95
|
+
const content = getNuxtBbmAdapterFileContent(adapter.requestImportPath);
|
|
96
|
+
const absolutePath = resolve(cwd, requestFilePath);
|
|
97
|
+
const dir = dirname(absolutePath);
|
|
98
|
+
if (!existsSync(dir)) {
|
|
99
|
+
mkdirSync(dir, { recursive: true });
|
|
100
|
+
}
|
|
101
|
+
writeFileSync(absolutePath, content, 'utf-8');
|
|
102
|
+
resolved.requestFunctionFilePath = requestFilePath;
|
|
103
|
+
delete resolved.requestAdapter;
|
|
104
|
+
return resolved;
|
|
105
|
+
}
|
|
106
|
+
// custom 或未指定:必须已有 requestFunctionFilePath
|
|
107
|
+
if (!resolved.requestFunctionFilePath && !adapter.requestFunctionFilePath) {
|
|
108
|
+
throw new Error('[yapi-gen] requestAdapter 为 custom 或未指定时,必须配置 requestFunctionFilePath');
|
|
109
|
+
}
|
|
110
|
+
if (adapter.requestFunctionFilePath) {
|
|
111
|
+
resolved.requestFunctionFilePath = adapter.requestFunctionFilePath;
|
|
112
|
+
}
|
|
113
|
+
delete resolved.requestAdapter;
|
|
114
|
+
return resolved;
|
|
115
|
+
}
|
package/dist/run.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAiGA,wBAAgB,GAAG,CAAC,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,MAAM,CAkC/F"}
|
package/dist/run.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI 执行逻辑:解析用户配置、生成 ytt 包装配置并执行 ytt
|
|
3
|
+
*/
|
|
4
|
+
import { spawnSync } from 'child_process';
|
|
5
|
+
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
6
|
+
import { resolve, dirname, basename, relative } from 'path';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const CONFIG_NAMES = [
|
|
10
|
+
'yapi-gen.config.ts',
|
|
11
|
+
'yapi-gen.config.mts',
|
|
12
|
+
'yapi-gen.config.cts',
|
|
13
|
+
'yapi-gen.config.js',
|
|
14
|
+
'yapi-gen.config.mjs',
|
|
15
|
+
'yapi-gen.config.cjs',
|
|
16
|
+
'.yapi-genrc.ts',
|
|
17
|
+
'.yapi-genrc.mts',
|
|
18
|
+
'.yapi-genrc.js',
|
|
19
|
+
'.yapi-genrc.mjs',
|
|
20
|
+
];
|
|
21
|
+
const WRAPPER_DIR = '.yapi-gen';
|
|
22
|
+
const WRAPPER_FILENAME = 'ytt.config.ts';
|
|
23
|
+
function findConfig(cwd) {
|
|
24
|
+
for (const name of CONFIG_NAMES) {
|
|
25
|
+
const p = resolve(cwd, name);
|
|
26
|
+
if (existsSync(p))
|
|
27
|
+
return p;
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 生成包装用的 ytt.config.ts 内容
|
|
33
|
+
* 该文件会 import 用户配置并传入 defineConfig
|
|
34
|
+
*/
|
|
35
|
+
function getWrapperContent(cwd, configPath) {
|
|
36
|
+
const absoluteConfig = resolve(cwd, configPath);
|
|
37
|
+
const configDir = dirname(absoluteConfig);
|
|
38
|
+
const configBase = basename(absoluteConfig).replace(/\.[^.]+$/, '') || 'yapi-gen.config';
|
|
39
|
+
const wrapperDir = resolve(cwd, WRAPPER_DIR);
|
|
40
|
+
const rel = relative(wrapperDir, configDir).replace(/\\/g, '/');
|
|
41
|
+
const relativeImport = (rel ? rel + '/' : '') + configBase;
|
|
42
|
+
return `/* 由 yapi-gen 自动生成,请勿修改 */
|
|
43
|
+
import { defineConfig } from 'yapi-to-typescript';
|
|
44
|
+
import { resolveConfig } from 'yapi-gen';
|
|
45
|
+
|
|
46
|
+
const userConfig = await import('${relativeImport}');
|
|
47
|
+
const raw = userConfig.default ?? userConfig;
|
|
48
|
+
const configList = Array.isArray(raw) ? raw : [raw];
|
|
49
|
+
const resolvedList = configList.map((c) => resolveConfig(c, process.cwd()));
|
|
50
|
+
|
|
51
|
+
export default defineConfig(resolvedList);
|
|
52
|
+
`;
|
|
53
|
+
}
|
|
54
|
+
function runInit(cwd) {
|
|
55
|
+
const configPath = resolve(cwd, 'yapi-gen.config.ts');
|
|
56
|
+
if (existsSync(configPath)) {
|
|
57
|
+
console.log('[yapi-gen] 已存在 yapi-gen.config.ts,跳过创建');
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
const tpl = `import { defineYapiGenConfig } from 'yapi-gen';
|
|
61
|
+
|
|
62
|
+
export default defineYapiGenConfig({
|
|
63
|
+
serverUrl: 'https://yapi.example.com',
|
|
64
|
+
serverType: 'yapi',
|
|
65
|
+
// 请求适配:'axios' | 'nuxt-bbm' | 'custom',使用预设时可不填 requestFunctionFilePath
|
|
66
|
+
requestAdapter: 'axios',
|
|
67
|
+
// requestFunctionFilePath: 'src/yapi/request.ts', // custom 时必填;预设时可选,默认 src/yapi/request.ts
|
|
68
|
+
outputFilePath: (interfaceInfo, changeCase) => {
|
|
69
|
+
const catId = interfaceInfo.catid ?? 0;
|
|
70
|
+
return \`src/yapi/cat_\${catId}/index.ts\`;
|
|
71
|
+
},
|
|
72
|
+
dataKey: 'result',
|
|
73
|
+
projects: [
|
|
74
|
+
{
|
|
75
|
+
token: process.env.YAPI_TOKEN || 'your-project-token',
|
|
76
|
+
categories: [
|
|
77
|
+
{
|
|
78
|
+
id: 0,
|
|
79
|
+
getRequestFunctionName(interfaceInfo, changeCase) {
|
|
80
|
+
return changeCase.camelCase(interfaceInfo.path);
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
],
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
});
|
|
87
|
+
`;
|
|
88
|
+
writeFileSync(configPath, tpl, 'utf-8');
|
|
89
|
+
console.log('[yapi-gen] 已创建 yapi-gen.config.ts,请按需修改 serverUrl、token 等');
|
|
90
|
+
}
|
|
91
|
+
return 0;
|
|
92
|
+
}
|
|
93
|
+
export function run(options = {}) {
|
|
94
|
+
const cwd = options.cwd ?? process.cwd();
|
|
95
|
+
if (options.init) {
|
|
96
|
+
return runInit(cwd);
|
|
97
|
+
}
|
|
98
|
+
const configPath = options.configPath ?? findConfig(cwd);
|
|
99
|
+
if (!configPath) {
|
|
100
|
+
console.error('[yapi-gen] 未找到配置文件。请在项目根目录创建以下之一:', CONFIG_NAMES.join(', '));
|
|
101
|
+
console.error('[yapi-gen] 或使用 init 子命令:pnpm yapi-gen init');
|
|
102
|
+
return 1;
|
|
103
|
+
}
|
|
104
|
+
const wrapperDir = resolve(cwd, WRAPPER_DIR);
|
|
105
|
+
if (!existsSync(wrapperDir)) {
|
|
106
|
+
mkdirSync(wrapperDir, { recursive: true });
|
|
107
|
+
}
|
|
108
|
+
const wrapperPath = resolve(wrapperDir, WRAPPER_FILENAME);
|
|
109
|
+
const content = getWrapperContent(cwd, configPath);
|
|
110
|
+
writeFileSync(wrapperPath, content, 'utf-8');
|
|
111
|
+
const result = spawnSync('npx', ['ytt', '-c', wrapperPath], {
|
|
112
|
+
cwd,
|
|
113
|
+
stdio: 'inherit',
|
|
114
|
+
shell: true,
|
|
115
|
+
});
|
|
116
|
+
return result.status ?? 1;
|
|
117
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@karry.sun/yapi-gen",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "基于 yapi-to-typescript 的 YApi 前端代码生成 CLI,支持可配置的请求适配器与多项目复用",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./adapters/axios": {
|
|
15
|
+
"types": "./dist/adapters/axios.d.ts",
|
|
16
|
+
"import": "./dist/adapters/axios.js",
|
|
17
|
+
"default": "./dist/adapters/axios.js"
|
|
18
|
+
},
|
|
19
|
+
"./adapters/nuxt-bbm": {
|
|
20
|
+
"types": "./dist/adapters/nuxt-bbm.d.ts",
|
|
21
|
+
"import": "./dist/adapters/nuxt-bbm.js",
|
|
22
|
+
"default": "./dist/adapters/nuxt-bbm.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"bin": {
|
|
26
|
+
"yapi-gen": "./bin/yapi-gen.js"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"bin",
|
|
31
|
+
"templates",
|
|
32
|
+
"README.md"
|
|
33
|
+
],
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"yapi-to-typescript": "^3.38.0"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"yapi-to-typescript": ">=3.0.0"
|
|
39
|
+
},
|
|
40
|
+
"peerDependenciesMeta": {
|
|
41
|
+
"yapi-to-typescript": {
|
|
42
|
+
"optional": true
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"typescript": "^5.0.0"
|
|
47
|
+
},
|
|
48
|
+
"keywords": [
|
|
49
|
+
"yapi",
|
|
50
|
+
"yapi-to-typescript",
|
|
51
|
+
"codegen",
|
|
52
|
+
"api",
|
|
53
|
+
"typescript"
|
|
54
|
+
],
|
|
55
|
+
"license": "MIT",
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "tsc"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 请求适配器模板:适配原生 axios 或封装后的 axios 实例
|
|
3
|
+
* 使用方式:复制到项目内 requestFunctionFilePath 指定路径,并修改 axios 的引用
|
|
4
|
+
*/
|
|
5
|
+
import type { RequestFunctionParams } from 'yapi-to-typescript';
|
|
6
|
+
import axios from 'axios'; // 或项目内封装的实例,如 @/utils/request
|
|
7
|
+
|
|
8
|
+
export default async function request<TResponseData>(
|
|
9
|
+
payload: RequestFunctionParams,
|
|
10
|
+
): Promise<TResponseData> {
|
|
11
|
+
const baseURL = import.meta?.dev ? payload.devUrl : payload.prodUrl;
|
|
12
|
+
const isGet = payload.method === 'GET' || payload.method === 'HEAD' || payload.method === 'OPTIONS';
|
|
13
|
+
|
|
14
|
+
const config: any = {
|
|
15
|
+
baseURL: baseURL || '',
|
|
16
|
+
url: payload.path,
|
|
17
|
+
method: payload.method.toLowerCase(),
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
if (isGet && payload.data) {
|
|
21
|
+
config.params = payload.data;
|
|
22
|
+
} else if (!isGet && payload.data) {
|
|
23
|
+
config.data = payload.data;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const res = await axios.request(config);
|
|
27
|
+
const data = res?.data;
|
|
28
|
+
|
|
29
|
+
if (data != null && typeof data === 'object' && payload.dataKey != null && data[payload.dataKey] != null) {
|
|
30
|
+
return data[payload.dataKey] as TResponseData;
|
|
31
|
+
}
|
|
32
|
+
return data as TResponseData;
|
|
33
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 请求适配器模板:适配基于 axios 的 defHttp(如 Vite + Vue 项目)
|
|
3
|
+
* 使用方式:复制到项目内 requestFunctionFilePath 指定路径,并修改 defHttp 的引用路径
|
|
4
|
+
*/
|
|
5
|
+
import type { RequestFunctionParams } from 'yapi-to-typescript';
|
|
6
|
+
// 请根据项目实际路径修改
|
|
7
|
+
import { defHttp } from '/@/utils/http/axios';
|
|
8
|
+
|
|
9
|
+
export default async function request<TResponseData>(
|
|
10
|
+
payload: RequestFunctionParams,
|
|
11
|
+
): Promise<TResponseData> {
|
|
12
|
+
const { method, path, data, hasFileData, getFormData } = payload;
|
|
13
|
+
const url = path;
|
|
14
|
+
const isGet = method === 'GET' || method === 'HEAD' || method === 'OPTIONS';
|
|
15
|
+
|
|
16
|
+
let config: { url: string; params?: any; data?: any; headers?: Record<string, string> };
|
|
17
|
+
|
|
18
|
+
if (isGet) {
|
|
19
|
+
config = { url, params: {} };
|
|
20
|
+
} else if (hasFileData && getFormData) {
|
|
21
|
+
config = { url, params: getFormData() };
|
|
22
|
+
} else {
|
|
23
|
+
config = { url, params: data || {} };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let res: any;
|
|
27
|
+
switch (method) {
|
|
28
|
+
case 'GET':
|
|
29
|
+
case 'HEAD':
|
|
30
|
+
case 'OPTIONS':
|
|
31
|
+
res = await defHttp.get(config);
|
|
32
|
+
break;
|
|
33
|
+
case 'POST':
|
|
34
|
+
res = await defHttp.post(config);
|
|
35
|
+
break;
|
|
36
|
+
case 'PUT':
|
|
37
|
+
res = await defHttp.put(config);
|
|
38
|
+
break;
|
|
39
|
+
case 'DELETE':
|
|
40
|
+
res = await defHttp.delete(config);
|
|
41
|
+
break;
|
|
42
|
+
case 'PATCH':
|
|
43
|
+
res = await (defHttp as any).request({ ...config, method: 'PATCH' });
|
|
44
|
+
break;
|
|
45
|
+
default:
|
|
46
|
+
res = await defHttp.post(config);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (res != null && typeof res === 'object' && payload.dataKey != null && (res as any)[payload.dataKey] != null) {
|
|
50
|
+
return (res as any)[payload.dataKey] as TResponseData;
|
|
51
|
+
}
|
|
52
|
+
return res as TResponseData;
|
|
53
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 请求适配器模板:适配 Nuxt 项目的 request(如 #imports 的 request / $fetch)
|
|
3
|
+
* 使用方式:复制到项目内 requestFunctionFilePath 指定路径,并修改 request 的引用(如 #imports)
|
|
4
|
+
*/
|
|
5
|
+
import type { RequestFunctionParams } from 'yapi-to-typescript';
|
|
6
|
+
// Nuxt 项目通常从 #imports 或 useRequest 等引入,请根据项目修改
|
|
7
|
+
import { request } from '#imports';
|
|
8
|
+
|
|
9
|
+
export default async function requestAdapter<TResponseData>(
|
|
10
|
+
payload: RequestFunctionParams,
|
|
11
|
+
): Promise<TResponseData> {
|
|
12
|
+
const baseUrl = import.meta.dev ? payload.devUrl : payload.prodUrl;
|
|
13
|
+
const res = await request<TResponseData>(payload.path, {
|
|
14
|
+
baseURL: baseUrl || '',
|
|
15
|
+
method: payload.method.toLowerCase() as 'get' | 'post' | 'put' | 'delete',
|
|
16
|
+
...(payload.requestBodyType === 'json' && payload.data ? { body: payload.data } : {}),
|
|
17
|
+
...(payload.requestBodyType === 'query' && payload.data ? { query: payload.data } : {}),
|
|
18
|
+
tips: false,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
if (res != null && typeof res === 'object' && payload.dataKey != null && (res as any)[payload.dataKey] != null) {
|
|
22
|
+
return (res as any)[payload.dataKey] as TResponseData;
|
|
23
|
+
}
|
|
24
|
+
return res as TResponseData;
|
|
25
|
+
}
|