@gogenger/go-gen 1.0.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/CHANGELOG.md +38 -0
- package/LICENSE +21 -0
- package/README.en.md +151 -0
- package/README.md +151 -0
- package/bin/index.js +86 -0
- package/core/config.js +176 -0
- package/core/fetch-mode.js +400 -0
- package/core/openapi-mode.js +328 -0
- package/core/quicktype.js +31 -0
- package/core/writer.js +413 -0
- package/docs/BEST_PRACTICES.md +327 -0
- package/docs/CONFIGURATION.md +161 -0
- package/docs/FEATURES.md +136 -0
- package/docs/TROUBLESHOOTING.md +386 -0
- package/docs/USE_CASES.md +247 -0
- package/package.json +68 -0
- package/utils/load-openapi.js +23 -0
- package/utils/name.js +17 -0
- package/utils/sampler.js +28 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# 🎨 使用场景
|
|
2
|
+
|
|
3
|
+
## 场景 1:快速对接第三方 API
|
|
4
|
+
|
|
5
|
+
**需求:** 需要调用一个第三方支付接口
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
go-gen fetch
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
**交互过程:**
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
🌐 请输入 API URL: https://api.payment.com/v1/orders
|
|
15
|
+
🔧 请求方法: POST
|
|
16
|
+
🔐 是否需要认证? Bearer Token
|
|
17
|
+
🔑 请输入 Bearer Token: sk_test_xxxxx
|
|
18
|
+
📦 该接口是否需要请求体? Yes
|
|
19
|
+
📝 请输入请求体 JSON:
|
|
20
|
+
{
|
|
21
|
+
"amount": 100,
|
|
22
|
+
"currency": "USD",
|
|
23
|
+
"description": "Order #123"
|
|
24
|
+
}
|
|
25
|
+
📝 Response Type 名称: CreateOrderResponse
|
|
26
|
+
📦 API 方法名: createPaymentOrder
|
|
27
|
+
📂 输出目录: 📁 当前目录
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**生成结果:** 30 秒内完成接口对接
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 场景 2:从 Swagger 文档批量生成
|
|
35
|
+
|
|
36
|
+
**需求:** 后端提供了 Swagger 文档,需要生成所有用户相关接口
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
go-gen openapi https://api.example.com/swagger.json
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**选择批量模式:**
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
⚡ 批量生成中... (1/15): GET /users
|
|
46
|
+
⚡ 批量生成中... (2/15): POST /users
|
|
47
|
+
⚡ 批量生成中... (3/15): GET /users/{id}
|
|
48
|
+
...
|
|
49
|
+
✅ 批量生成完成!成功: 15,失败: 0
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**优势:** 一次性生成所有接口,节省大量时间
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 场景 3:团队协作规范化
|
|
57
|
+
|
|
58
|
+
**场景描述:** 团队有 5 个前端开发,需要统一 API 调用方式
|
|
59
|
+
|
|
60
|
+
**步骤 1:项目负责人设置规范**
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
cd your-project
|
|
64
|
+
go-gen init
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
编辑 `.apirc.json`:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"requestModule": "@/api/request",
|
|
72
|
+
"typePrefix": "I",
|
|
73
|
+
"apiPrefix": "api"
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
提交配置:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
git add .apirc.json
|
|
81
|
+
git commit -m "chore: add api generator config"
|
|
82
|
+
git push
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**步骤 2:团队成员使用**
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
git pull
|
|
89
|
+
go-gen fetch # 自动使用团队配置
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**效果:** 所有成员生成的代码风格统一,无需口头约定
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 场景 4:多项目维护
|
|
97
|
+
|
|
98
|
+
**场景描述:** 同时维护 3 个项目,每个项目使用不同的 HTTP 库
|
|
99
|
+
|
|
100
|
+
**项目 A(使用 axios)**
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
cd project-a
|
|
104
|
+
cat .apirc.json
|
|
105
|
+
# { "requestModule": "axios" }
|
|
106
|
+
go-gen fetch
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
生成的代码:
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import axios from 'axios';
|
|
113
|
+
|
|
114
|
+
export function getUsers() {
|
|
115
|
+
return axios.get<UserResponse>('/api/users');
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
**项目 B(使用自定义 request)**
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
cd project-b
|
|
123
|
+
cat .apirc.json
|
|
124
|
+
# { "requestModule": "@/utils/http" }
|
|
125
|
+
go-gen fetch
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
生成的代码:
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
import request from '@/utils/http';
|
|
132
|
+
|
|
133
|
+
export function getUsers() {
|
|
134
|
+
return request.get<UserResponse>('/api/users');
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**项目 C(使用 fetch)**
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
cd project-c
|
|
142
|
+
cat .apirc.json
|
|
143
|
+
# { "requestModule": "@/api/fetch" }
|
|
144
|
+
go-gen fetch
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
生成的代码:
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
import request from '@/api/fetch';
|
|
151
|
+
|
|
152
|
+
export function getUsers() {
|
|
153
|
+
return request.get<UserResponse>('/api/users');
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
**优势:** 自动适配各项目规范,无需手动调整
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 场景 5:迭代开发增量更新
|
|
162
|
+
|
|
163
|
+
**场景描述:** 项目已有 10 个接口,现在要新增 2 个
|
|
164
|
+
|
|
165
|
+
**第一次生成:**
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
go-gen fetch
|
|
169
|
+
# 输出到: src/api/user/
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
生成文件:
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
src/api/user/
|
|
176
|
+
├── api.ts # 10 个 API 方法
|
|
177
|
+
└── types.ts # 10 个类型定义
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
**新增接口:**
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
go-gen fetch
|
|
184
|
+
# 输出到: src/api/user/ (相同目录)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**结果:** 新接口自动追加,原有代码不受影响
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
// api.ts
|
|
191
|
+
export function getUsers() { ... } // 原有
|
|
192
|
+
export function createUser(data) { ... } // 原有
|
|
193
|
+
export function updateUser(id, data) { ... } // 新增
|
|
194
|
+
export function deleteUser(id) { ... } // 新增
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## 场景 6:处理复杂认证
|
|
200
|
+
|
|
201
|
+
**场景描述:** 接口需要多个 Header
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
go-gen fetch
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
🔐 是否需要认证? Bearer Token
|
|
209
|
+
🔑 请输入 Bearer Token: your_token_here
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
如果需要额外的 Header,可以在生成后手动添加:
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
export function getUsers() {
|
|
216
|
+
return request.get<UserResponse>('/api/users', {
|
|
217
|
+
headers: {
|
|
218
|
+
'X-Custom-Header': 'value',
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## 场景 7:调试和测试
|
|
227
|
+
|
|
228
|
+
**场景描述:** 开发环境测试接口
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
go-gen fetch
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
🌐 请输入 API URL: http://localhost:3000/api/test
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
生成代码后立即测试:
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
import { getTest } from './api';
|
|
242
|
+
|
|
243
|
+
// 立即调用测试
|
|
244
|
+
getTest().then(data => {
|
|
245
|
+
console.log('API 响应:', data);
|
|
246
|
+
});
|
|
247
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gogenger/go-gen",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "一款 TypeScript API 代码生成器,支持从 API 响应或 OpenAPI 文档一键生成 TypeScript 接口代码和类型定义",
|
|
5
|
+
"bin": {
|
|
6
|
+
"go-gen": "./bin/index.js"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"test": "jest --coverage",
|
|
10
|
+
"test:watch": "jest --watch",
|
|
11
|
+
"lint": "eslint core/**/*.js",
|
|
12
|
+
"prepare": "husky install",
|
|
13
|
+
"format": "prettier --write .",
|
|
14
|
+
"format:check": "prettier --check ."
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"quicktype",
|
|
18
|
+
"api",
|
|
19
|
+
"typescript",
|
|
20
|
+
"code-generator",
|
|
21
|
+
"openapi",
|
|
22
|
+
"cli"
|
|
23
|
+
],
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"author": "goGenger",
|
|
26
|
+
"email": "bg2582266166@gmail.com",
|
|
27
|
+
"lint-staged": {
|
|
28
|
+
"**/*.{js}": [
|
|
29
|
+
"prettier --write",
|
|
30
|
+
"eslint --fix"
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"core",
|
|
35
|
+
"utils",
|
|
36
|
+
"bin",
|
|
37
|
+
"docs",
|
|
38
|
+
"README.md",
|
|
39
|
+
"LICENSE",
|
|
40
|
+
"CHANGELOG.md"
|
|
41
|
+
],
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"eslint": "^8.47.0",
|
|
44
|
+
"jest": "^29.6.0",
|
|
45
|
+
"nock": "^13.3.3",
|
|
46
|
+
"prettier": "^3.7.4",
|
|
47
|
+
"lint-staged": "^16.2.7",
|
|
48
|
+
"husky": "^9.1.7",
|
|
49
|
+
"eslint-config-prettier": "^10.1.8",
|
|
50
|
+
"eslint-plugin-prettier": "^5.5.4"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@darkobits/lolcatjs": "3.1.3",
|
|
54
|
+
"chalk": "^4.1.2",
|
|
55
|
+
"commander": "^9.5.0",
|
|
56
|
+
"figlet": "^1.9.4",
|
|
57
|
+
"inquirer": "^8.2.6",
|
|
58
|
+
"node-fetch": "^2.7.0",
|
|
59
|
+
"openapi-sampler": "^1.6.2",
|
|
60
|
+
"ora": "^5.4.1",
|
|
61
|
+
"quicktype-core": "^23.2.6",
|
|
62
|
+
"shelljs": "^0.10.0",
|
|
63
|
+
"prompts": "^2.4.2"
|
|
64
|
+
},
|
|
65
|
+
"engines": {
|
|
66
|
+
"node": ">=20.0.0"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const fetch = require('node-fetch');
|
|
3
|
+
|
|
4
|
+
async function loadOpenAPI(source) {
|
|
5
|
+
// 如果是 URL
|
|
6
|
+
if (source.startsWith('http://') || source.startsWith('https://')) {
|
|
7
|
+
const response = await fetch(source);
|
|
8
|
+
if (!response.ok) {
|
|
9
|
+
throw new Error(`Failed to fetch OpenAPI: ${response.statusText}`);
|
|
10
|
+
}
|
|
11
|
+
return await response.json();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// 如果是本地文件
|
|
15
|
+
if (fs.existsSync(source)) {
|
|
16
|
+
const content = fs.readFileSync(source, 'utf-8');
|
|
17
|
+
return JSON.parse(content);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
throw new Error('Invalid OpenAPI source: must be URL or file path');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = loadOpenAPI;
|
package/utils/name.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
function isValidIdentifier(name) {
|
|
2
|
+
return /^[A-Za-z][A-Za-z0-9]*$/.test(name);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function pascalCase(name) {
|
|
6
|
+
// 如果用户已经输入了合法 TS 名称,直接返回
|
|
7
|
+
if (isValidIdentifier(name)) {
|
|
8
|
+
return name;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// 否则才进行 pascalCase
|
|
12
|
+
return name
|
|
13
|
+
.replace(/[-_/](.)/g, (_, c) => c.toUpperCase())
|
|
14
|
+
.replace(/^(.)/, (_, c) => c.toUpperCase());
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = { pascalCase };
|
package/utils/sampler.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
function schemaToSample(schema) {
|
|
2
|
+
if (!schema) return {};
|
|
3
|
+
|
|
4
|
+
if (schema.type === 'object' && schema.properties) {
|
|
5
|
+
const sample = {};
|
|
6
|
+
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
7
|
+
sample[key] = schemaToSample(prop);
|
|
8
|
+
}
|
|
9
|
+
return sample;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (schema.type === 'array' && schema.items) {
|
|
13
|
+
return [schemaToSample(schema.items)];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const typeDefaults = {
|
|
17
|
+
string: 'example',
|
|
18
|
+
number: 0,
|
|
19
|
+
integer: 0,
|
|
20
|
+
boolean: false,
|
|
21
|
+
object: {},
|
|
22
|
+
array: [],
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return typeDefaults[schema.type] || null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = { schemaToSample };
|