@fecommunity/reactpress-toolkit 1.0.0-beta.1 → 1.0.0-beta.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 +190 -0
- package/dist/Article.d.ts +121 -0
- package/dist/Article.js +189 -0
- package/dist/Auth.d.ts +30 -0
- package/dist/Auth.js +59 -0
- package/dist/Category.d.ts +49 -0
- package/dist/Category.js +85 -0
- package/dist/Comment.d.ts +58 -0
- package/dist/Comment.js +98 -0
- package/dist/File.d.ts +40 -0
- package/dist/File.js +72 -0
- package/dist/HttpClient.d.ts +41 -0
- package/dist/HttpClient.js +94 -0
- package/dist/Knowledge.d.ts +76 -0
- package/dist/Knowledge.js +124 -0
- package/dist/Page.d.ts +58 -0
- package/dist/Page.js +98 -0
- package/dist/Search.d.ts +30 -0
- package/dist/Search.js +59 -0
- package/dist/Setting.d.ts +22 -0
- package/dist/Setting.js +46 -0
- package/dist/Smtp.d.ts +31 -0
- package/dist/Smtp.js +59 -0
- package/dist/Tag.d.ts +58 -0
- package/dist/Tag.js +98 -0
- package/dist/User.d.ts +41 -0
- package/dist/User.js +73 -0
- package/dist/View.d.ts +49 -0
- package/dist/View.js +85 -0
- package/dist/api/ApiInstance.d.ts +39 -0
- package/dist/api/ApiInstance.js +46 -0
- package/dist/api/Article.d.ts +11 -11
- package/dist/api/Article.js +12 -12
- package/dist/api/ArticleRoute.d.ts +201 -0
- package/dist/api/ArticleRoute.js +12 -0
- package/dist/api/Auth.d.ts +5 -5
- package/dist/api/Auth.js +6 -6
- package/dist/api/AuthRoute.d.ts +44 -0
- package/dist/api/AuthRoute.js +12 -0
- package/dist/api/Category.d.ts +1 -1
- package/dist/api/Category.js +2 -2
- package/dist/api/CategoryRoute.d.ts +79 -0
- package/dist/api/CategoryRoute.js +12 -0
- package/dist/api/Comment.d.ts +3 -3
- package/dist/api/Comment.js +4 -4
- package/dist/api/CommentRoute.d.ts +95 -0
- package/dist/api/CommentRoute.js +12 -0
- package/dist/api/File.d.ts +3 -3
- package/dist/api/File.js +4 -4
- package/dist/api/FileRoute.d.ts +63 -0
- package/dist/api/FileRoute.js +12 -0
- package/dist/api/Knowledge.d.ts +5 -5
- package/dist/api/Knowledge.js +6 -6
- package/dist/api/KnowledgeRoute.d.ts +125 -0
- package/dist/api/KnowledgeRoute.js +12 -0
- package/dist/api/Page.d.ts +3 -3
- package/dist/api/Page.js +4 -4
- package/dist/api/PageRoute.d.ts +95 -0
- package/dist/api/PageRoute.js +12 -0
- package/dist/api/Search.d.ts +3 -3
- package/dist/api/Search.js +4 -4
- package/dist/api/SearchRoute.d.ts +46 -0
- package/dist/api/SearchRoute.js +12 -0
- package/dist/api/Setting.d.ts +3 -3
- package/dist/api/Setting.js +4 -4
- package/dist/api/SettingRoute.d.ts +31 -0
- package/dist/api/SettingRoute.js +12 -0
- package/dist/api/Smtp.d.ts +1 -1
- package/dist/api/Smtp.js +2 -2
- package/dist/api/SmtpRoute.d.ts +47 -0
- package/dist/api/SmtpRoute.js +12 -0
- package/dist/api/Tag.d.ts +3 -3
- package/dist/api/Tag.js +4 -4
- package/dist/api/TagRoute.d.ts +95 -0
- package/dist/api/TagRoute.js +12 -0
- package/dist/api/User.d.ts +7 -7
- package/dist/api/User.js +8 -8
- package/dist/api/UserRoute.d.ts +60 -0
- package/dist/api/UserRoute.js +12 -0
- package/dist/api/View.d.ts +3 -3
- package/dist/api/View.js +4 -4
- package/dist/api/ViewRoute.d.ts +77 -0
- package/dist/api/ViewRoute.js +12 -0
- package/dist/api/httpClient.d.ts +1 -0
- package/dist/api/httpClient.js +1 -0
- package/dist/api/index.d.ts +5 -5
- package/dist/api/index.js +6 -7
- package/dist/data-contracts.d.ts +245 -0
- package/dist/data-contracts.js +12 -0
- package/dist/index.d.ts +5 -9
- package/dist/index.js +14 -15
- package/dist/utils/common.d.ts +1 -3
- package/dist/utils/common.js +5 -31
- package/dist/utils/http.js +4 -6
- package/package.json +5 -3
- package/demos/simple.ts +0 -65
- package/scripts/generate-api-types.js +0 -571
- package/scripts/generate-swagger.js +0 -47
- package/scripts/organize-api.js +0 -136
- package/src/api/Article.ts +0 -186
- package/src/api/Auth.ts +0 -54
- package/src/api/Category.ts +0 -82
- package/src/api/Comment.ts +0 -95
- package/src/api/File.ts +0 -69
- package/src/api/Knowledge.ts +0 -122
- package/src/api/Page.ts +0 -95
- package/src/api/Search.ts +0 -54
- package/src/api/Setting.ts +0 -43
- package/src/api/Smtp.ts +0 -56
- package/src/api/Tag.ts +0 -95
- package/src/api/User.ts +0 -72
- package/src/api/View.ts +0 -82
- package/src/api/api-instance.ts +0 -69
- package/src/api/httpClient.ts +0 -140
- package/src/api/index.ts +0 -25
- package/src/index.ts +0 -18
- package/src/types/data-contracts.ts +0 -198
- package/src/types/index.ts +0 -4
- package/src/utils/common.ts +0 -108
- package/src/utils/http.ts +0 -52
- package/src/utils/index.ts +0 -5
- package/test-final.js +0 -56
- package/test-import.js +0 -34
- package/tsconfig.json +0 -20
|
@@ -1,571 +0,0 @@
|
|
|
1
|
-
// scripts/generate-api.js
|
|
2
|
-
const { generateApi } = require('swagger-typescript-api');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const fs = require('fs-extra');
|
|
5
|
-
|
|
6
|
-
// 配置常量
|
|
7
|
-
const CONFIG = {
|
|
8
|
-
input: path.resolve(__dirname, '../../server/public/swagger.json'),
|
|
9
|
-
output: path.resolve(__dirname, '../src'),
|
|
10
|
-
templates: path.resolve(__dirname, '../node_modules/swagger-typescript-api/templates/base'),
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
// 生成 API 类型定义和客户端
|
|
14
|
-
async function generateApiTypes() {
|
|
15
|
-
console.log('🚀 开始生成 TypeScript API 定义...');
|
|
16
|
-
console.log(`📁 输入: ${CONFIG.input}`);
|
|
17
|
-
console.log(`📁 输出: ${CONFIG.output}`);
|
|
18
|
-
|
|
19
|
-
// 检查输入文件是否存在
|
|
20
|
-
if (!fs.existsSync(CONFIG.input)) {
|
|
21
|
-
console.error(`❌ Swagger JSON 文件不存在: ${CONFIG.input}`);
|
|
22
|
-
process.exit(1);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
// 确保输出目录存在
|
|
27
|
-
fs.ensureDirSync(CONFIG.output);
|
|
28
|
-
|
|
29
|
-
const result = await generateApi({
|
|
30
|
-
input: CONFIG.input,
|
|
31
|
-
output: CONFIG.output,
|
|
32
|
-
templates: CONFIG.templates,
|
|
33
|
-
cleanOutput: true,
|
|
34
|
-
modular: true,
|
|
35
|
-
httpClientType: 'axios',
|
|
36
|
-
typePrefix: 'I',
|
|
37
|
-
generateClient: true,
|
|
38
|
-
hooks: {
|
|
39
|
-
onPrepareConfig: (currentConfiguration) => {
|
|
40
|
-
const config = currentConfiguration.config;
|
|
41
|
-
config.fileNames.httpClient = 'httpClient'; // http客户端文件名
|
|
42
|
-
return { ...currentConfiguration, config };
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
console.log('✅ TypeScript API 定义生成成功!');
|
|
48
|
-
|
|
49
|
-
// 检查生成的文件
|
|
50
|
-
const files = fs.readdirSync(CONFIG.output);
|
|
51
|
-
console.log('📄 生成的文件:', files);
|
|
52
|
-
|
|
53
|
-
// 后处理:组织文件和创建索引
|
|
54
|
-
await organizeGeneratedFiles();
|
|
55
|
-
|
|
56
|
-
return result;
|
|
57
|
-
} catch (error) {
|
|
58
|
-
console.error('❌ 生成 API 类型定义时出错:', error.message);
|
|
59
|
-
process.exit(1);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// 组织生成的文件到正确的文件夹结构
|
|
64
|
-
async function organizeGeneratedFiles() {
|
|
65
|
-
const srcDir = CONFIG.output;
|
|
66
|
-
|
|
67
|
-
// 检查生成的文件
|
|
68
|
-
const files = fs.readdirSync(srcDir);
|
|
69
|
-
|
|
70
|
-
// 创建必要的目录
|
|
71
|
-
const apiDir = path.join(srcDir, 'api');
|
|
72
|
-
const typesDir = path.join(srcDir, 'types');
|
|
73
|
-
const utilsDir = path.join(srcDir, 'utils');
|
|
74
|
-
|
|
75
|
-
fs.ensureDirSync(apiDir);
|
|
76
|
-
fs.ensureDirSync(typesDir);
|
|
77
|
-
fs.ensureDirSync(utilsDir);
|
|
78
|
-
|
|
79
|
-
// 移动文件到正确的目录
|
|
80
|
-
files.forEach((file) => {
|
|
81
|
-
const filePath = path.join(srcDir, file);
|
|
82
|
-
|
|
83
|
-
if (file.endsWith('.ts')) {
|
|
84
|
-
// 根据文件名判断文件类型
|
|
85
|
-
if (file === 'httpClient.ts' || file === 'api-client.ts' || /[A-Z]/.test(file[0])) {
|
|
86
|
-
// API 文件:首字母大写的文件或特定的客户端文件
|
|
87
|
-
fs.moveSync(filePath, path.join(apiDir, file), { overwrite: true });
|
|
88
|
-
console.log(`📄 移动 API 文件: ${file} -> api/`);
|
|
89
|
-
} else if (file.includes('contract') || file === 'types.ts') {
|
|
90
|
-
// 类型定义文件
|
|
91
|
-
fs.moveSync(filePath, path.join(typesDir, file === 'types.ts' ? 'index.ts' : file), { overwrite: true });
|
|
92
|
-
console.log(`📄 移动类型文件: ${file} -> types/`);
|
|
93
|
-
} else {
|
|
94
|
-
// 其他文件留在根目录
|
|
95
|
-
console.log(`📄 保留文件: ${file}`);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
// 修复 HttpClient 类的 securityWorker 属性
|
|
101
|
-
await fixHttpClient();
|
|
102
|
-
|
|
103
|
-
// 修复 API 文件中的导入路径
|
|
104
|
-
await fixApiImports();
|
|
105
|
-
|
|
106
|
-
// 重命名 API 方法,使其更专业
|
|
107
|
-
await renameApiMethods();
|
|
108
|
-
|
|
109
|
-
// 创建统一的类型索引
|
|
110
|
-
await createTypeIndex();
|
|
111
|
-
|
|
112
|
-
// 创建统一的 API 索引
|
|
113
|
-
await createApiIndex();
|
|
114
|
-
|
|
115
|
-
// 创建主入口文件
|
|
116
|
-
await createMainIndex();
|
|
117
|
-
|
|
118
|
-
// 创建 API 实例化文件
|
|
119
|
-
await createApiInstance();
|
|
120
|
-
|
|
121
|
-
// 生成工具函数
|
|
122
|
-
await generateUtils();
|
|
123
|
-
|
|
124
|
-
console.log('✅ 文件组织完成');
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// 修复 HttpClient 类的 securityWorker 属性
|
|
128
|
-
async function fixHttpClient() {
|
|
129
|
-
console.log('🔧 修复 HttpClient 类...');
|
|
130
|
-
|
|
131
|
-
const httpClientPath = path.join(CONFIG.output, 'api', 'httpClient.ts');
|
|
132
|
-
|
|
133
|
-
if (fs.existsSync(httpClientPath)) {
|
|
134
|
-
let content = fs.readFileSync(httpClientPath, 'utf8');
|
|
135
|
-
|
|
136
|
-
// 将 private securityWorker 改为 public
|
|
137
|
-
content = content.replace(/private securityWorker/, 'public securityWorker');
|
|
138
|
-
|
|
139
|
-
// 重命名 ApiConfig 接口,避免冲突
|
|
140
|
-
content = content.replace(/interface ApiConfig/, 'interface HttpClientConfig');
|
|
141
|
-
content = content.replace(/ApiConfig<SecurityDataType>/g, 'HttpClientConfig<SecurityDataType>');
|
|
142
|
-
|
|
143
|
-
fs.writeFileSync(httpClientPath, content);
|
|
144
|
-
console.log('✅ HttpClient 修复完成');
|
|
145
|
-
} else {
|
|
146
|
-
console.log('⚠️ httpClient.ts 文件不存在,跳过修复');
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// 修复 API 文件中的导入路径
|
|
151
|
-
async function fixApiImports() {
|
|
152
|
-
console.log('🔧 修复 API 文件中的导入路径...');
|
|
153
|
-
|
|
154
|
-
const apiDir = path.join(CONFIG.output, 'api');
|
|
155
|
-
|
|
156
|
-
// 获取所有 API 文件
|
|
157
|
-
const apiFiles = fs.readdirSync(apiDir).filter(file => file.endsWith('.ts') && file !== 'index.ts');
|
|
158
|
-
|
|
159
|
-
for (const file of apiFiles) {
|
|
160
|
-
const filePath = path.join(apiDir, file);
|
|
161
|
-
let content = fs.readFileSync(filePath, 'utf8');
|
|
162
|
-
|
|
163
|
-
// 修复导入路径
|
|
164
|
-
content = content.replace(
|
|
165
|
-
/from '\.\/data-contracts'/g,
|
|
166
|
-
"from '../types/data-contracts'"
|
|
167
|
-
);
|
|
168
|
-
|
|
169
|
-
// 修复其他可能的类型导入
|
|
170
|
-
content = content.replace(
|
|
171
|
-
/from '\.\/([^']+)'/g,
|
|
172
|
-
(match, importPath) => {
|
|
173
|
-
// 如果导入路径是类型文件,则重定向到 types 目录
|
|
174
|
-
if (importPath.includes('contract') || importPath === 'types') {
|
|
175
|
-
return `from '../types/${importPath}'`;
|
|
176
|
-
}
|
|
177
|
-
return match;
|
|
178
|
-
}
|
|
179
|
-
);
|
|
180
|
-
|
|
181
|
-
// 写入修复后的内容
|
|
182
|
-
fs.writeFileSync(filePath, content);
|
|
183
|
-
console.log(`✅ 修复 ${file} 的导入路径`);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
console.log('✅ 所有 API 文件的导入路径已修复');
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// 重命名 API 方法,使其更专业
|
|
190
|
-
async function renameApiMethods() {
|
|
191
|
-
console.log('🔧 重命名 API 方法...');
|
|
192
|
-
|
|
193
|
-
const apiDir = path.join(CONFIG.output, 'api');
|
|
194
|
-
|
|
195
|
-
// 获取所有 API 文件
|
|
196
|
-
const apiFiles = fs.readdirSync(apiDir).filter(file =>
|
|
197
|
-
file.endsWith('.ts') &&
|
|
198
|
-
file !== 'index.ts' &&
|
|
199
|
-
file !== 'httpClient.ts' &&
|
|
200
|
-
/[A-Z]/.test(file[0]) // 首字母大写的文件
|
|
201
|
-
);
|
|
202
|
-
|
|
203
|
-
// 定义方法名映射
|
|
204
|
-
const methodNameMap = {
|
|
205
|
-
'ControllerCreate': 'create',
|
|
206
|
-
'ControllerFindAll': 'findAll',
|
|
207
|
-
'ControllerFindById': 'findById',
|
|
208
|
-
'ControllerUpdateById': 'updateById',
|
|
209
|
-
'ControllerDeleteById': 'deleteById',
|
|
210
|
-
'ControllerFindArticlesByCategory': 'findByCategory',
|
|
211
|
-
'ControllerFindArticlesByTag': 'findByTag',
|
|
212
|
-
'ControllerGetRecommendArticles': 'getRecommendations',
|
|
213
|
-
'ControllerGetArchives': 'getArchives',
|
|
214
|
-
'ControllerRecommend': 'recommend',
|
|
215
|
-
'ControllerCheckPassword': 'checkPassword',
|
|
216
|
-
'ControllerUpdateViewsById': 'updateViews',
|
|
217
|
-
'ControllerUpdateLikesById': 'updateLikes'
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
for (const file of apiFiles) {
|
|
221
|
-
const filePath = path.join(apiDir, file);
|
|
222
|
-
let content = fs.readFileSync(filePath, 'utf8');
|
|
223
|
-
|
|
224
|
-
// 重命名方法
|
|
225
|
-
for (const [oldSuffix, newName] of Object.entries(methodNameMap)) {
|
|
226
|
-
const regex = new RegExp(`(\\w+)${oldSuffix}`, 'g');
|
|
227
|
-
content = content.replace(regex, newName);
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// 写入修复后的内容
|
|
231
|
-
fs.writeFileSync(filePath, content);
|
|
232
|
-
console.log(`✅ 重命名 ${file} 中的方法`);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
console.log('✅ 所有 API 方法已重命名');
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// 创建统一的类型索引
|
|
239
|
-
async function createTypeIndex() {
|
|
240
|
-
console.log('📝 创建统一的类型索引...');
|
|
241
|
-
|
|
242
|
-
const typesDir = path.join(CONFIG.output, 'types');
|
|
243
|
-
|
|
244
|
-
// 获取所有类型文件
|
|
245
|
-
const typeFiles = fs.readdirSync(typesDir).filter(file => file.endsWith('.ts') && file !== 'index.ts');
|
|
246
|
-
|
|
247
|
-
let indexContent = '// 类型定义索引\n// 自动生成,请勿手动修改\n\n';
|
|
248
|
-
|
|
249
|
-
// 添加所有类型文件的导出
|
|
250
|
-
typeFiles.forEach(file => {
|
|
251
|
-
const moduleName = file.replace('.ts', '');
|
|
252
|
-
indexContent += `export * from './${moduleName}';\n`;
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
// 写入索引文件
|
|
256
|
-
fs.writeFileSync(path.join(typesDir, 'index.ts'), indexContent);
|
|
257
|
-
console.log('✅ 类型索引文件已创建');
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// 创建统一的 API 索引
|
|
261
|
-
async function createApiIndex() {
|
|
262
|
-
console.log('📝 创建统一的 API 索引...');
|
|
263
|
-
|
|
264
|
-
const apiDir = path.join(CONFIG.output, 'api');
|
|
265
|
-
|
|
266
|
-
// 获取所有 API 文件
|
|
267
|
-
const apiFiles = fs.readdirSync(apiDir).filter(file => file.endsWith('.ts') && file !== 'index.ts' && file !== 'api-instance.ts');
|
|
268
|
-
|
|
269
|
-
let indexContent = '// API 客户端索引\n// 自动生成,请勿手动修改\n\n';
|
|
270
|
-
|
|
271
|
-
// 添加所有 API 文件的导出
|
|
272
|
-
apiFiles.forEach(file => {
|
|
273
|
-
const moduleName = file.replace('.ts', '');
|
|
274
|
-
indexContent += `export * from './${moduleName}';\n`;
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
// 添加 HttpClient 导出
|
|
278
|
-
indexContent += `\nexport { default as HttpClient } from './httpClient';\n`;
|
|
279
|
-
indexContent += `export type { HttpClientConfig } from './httpClient';\n`;
|
|
280
|
-
|
|
281
|
-
// 写入索引文件
|
|
282
|
-
fs.writeFileSync(path.join(apiDir, 'index.ts'), indexContent);
|
|
283
|
-
console.log('✅ API 索引文件已创建');
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// 创建主入口文件
|
|
287
|
-
async function createMainIndex() {
|
|
288
|
-
console.log('📝 创建主入口文件...');
|
|
289
|
-
|
|
290
|
-
const mainIndexContent = `// Auto-generated API client
|
|
291
|
-
// Generated from Swagger/OpenAPI specification
|
|
292
|
-
|
|
293
|
-
export * from './api';
|
|
294
|
-
export * from './types';
|
|
295
|
-
export * from './utils';
|
|
296
|
-
|
|
297
|
-
export { default } from './api/api-instance';
|
|
298
|
-
`;
|
|
299
|
-
|
|
300
|
-
fs.writeFileSync(path.join(CONFIG.output, 'index.ts'), mainIndexContent);
|
|
301
|
-
console.log('✅ 主入口文件已创建');
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
// 创建 API 实例化文件
|
|
305
|
-
async function createApiInstance() {
|
|
306
|
-
console.log('📝 创建 API 实例化文件...');
|
|
307
|
-
|
|
308
|
-
const apiDir = path.join(CONFIG.output, 'api');
|
|
309
|
-
|
|
310
|
-
// 获取所有 API 文件(排除 index.ts 和 httpClient.ts)
|
|
311
|
-
const apiFiles = fs.readdirSync(apiDir).filter(file =>
|
|
312
|
-
file.endsWith('.ts') &&
|
|
313
|
-
file !== 'index.ts' &&
|
|
314
|
-
file !== 'httpClient.ts' &&
|
|
315
|
-
file !== 'api-instance.ts' &&
|
|
316
|
-
/[A-Z]/.test(file[0]) // 首字母大写的文件
|
|
317
|
-
);
|
|
318
|
-
|
|
319
|
-
// 提取 API 类名(去掉 .ts 后缀)
|
|
320
|
-
const apiClassNames = apiFiles.map(file => file.replace('.ts', ''));
|
|
321
|
-
|
|
322
|
-
// 生成导入语句
|
|
323
|
-
const imports = apiClassNames.map(className =>
|
|
324
|
-
`import { ${className} } from './${className}';`
|
|
325
|
-
).join('\n');
|
|
326
|
-
|
|
327
|
-
// 生成实例化语句
|
|
328
|
-
const instances = apiClassNames.map(className => {
|
|
329
|
-
const instanceName = className.charAt(0).toLowerCase() + className.slice(1);
|
|
330
|
-
return ` ${instanceName}: new ${className}(config),`;
|
|
331
|
-
}).join('\n');
|
|
332
|
-
|
|
333
|
-
// 生成类型定义
|
|
334
|
-
const types = apiClassNames.map(className => {
|
|
335
|
-
const instanceName = className.charAt(0).toLowerCase() + className.slice(1);
|
|
336
|
-
return ` ${instanceName}: ${className}<SecurityDataType>;`;
|
|
337
|
-
}).join('\n');
|
|
338
|
-
|
|
339
|
-
const apiInstanceContent = `// API 实例化文件
|
|
340
|
-
// 自动生成,请勿手动修改
|
|
341
|
-
|
|
342
|
-
import { HttpClient, HttpClientConfig } from './httpClient';
|
|
343
|
-
${imports}
|
|
344
|
-
|
|
345
|
-
export interface ApiConfig<SecurityDataType = unknown> extends HttpClientConfig<SecurityDataType> {
|
|
346
|
-
// 可以添加额外的配置项
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
export interface ApiInstance<SecurityDataType = unknown> {
|
|
350
|
-
${types}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* 创建 API 实例
|
|
355
|
-
* @param config API 配置
|
|
356
|
-
* @returns API 实例对象
|
|
357
|
-
*/
|
|
358
|
-
export function createApiInstance<SecurityDataType = unknown>(
|
|
359
|
-
config: ApiConfig<SecurityDataType> = {}
|
|
360
|
-
): ApiInstance<SecurityDataType> {
|
|
361
|
-
const httpClient = new HttpClient<SecurityDataType>(config);
|
|
362
|
-
|
|
363
|
-
return {
|
|
364
|
-
${instances}
|
|
365
|
-
};
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
// 默认 API 实例
|
|
369
|
-
export const api = createApiInstance();
|
|
370
|
-
|
|
371
|
-
export default api;
|
|
372
|
-
`;
|
|
373
|
-
|
|
374
|
-
fs.writeFileSync(path.join(apiDir, 'api-instance.ts'), apiInstanceContent);
|
|
375
|
-
console.log('✅ API 实例化文件已创建');
|
|
376
|
-
|
|
377
|
-
// 更新 API 索引文件,添加对 api-instance.ts 的导出
|
|
378
|
-
const apiIndexPath = path.join(apiDir, 'index.ts');
|
|
379
|
-
let apiIndexContent = fs.readFileSync(apiIndexPath, 'utf8');
|
|
380
|
-
|
|
381
|
-
apiIndexContent += '\n// API 实例化\nexport * from \'./api-instance\';\n';
|
|
382
|
-
apiIndexContent += 'export { default as api } from \'./api-instance\';\n';
|
|
383
|
-
|
|
384
|
-
fs.writeFileSync(apiIndexPath, apiIndexContent);
|
|
385
|
-
console.log('✅ 更新 API 索引文件');
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
// 生成工具函数
|
|
389
|
-
async function generateUtils() {
|
|
390
|
-
const utilsDir = path.join(CONFIG.output, 'utils');
|
|
391
|
-
fs.ensureDirSync(utilsDir);
|
|
392
|
-
|
|
393
|
-
// HTTP 客户端配置
|
|
394
|
-
const httpUtilsContent = `import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
|
|
395
|
-
|
|
396
|
-
// 创建自定义 axios 实例
|
|
397
|
-
export const createHttpClient = (baseURL?: string) => {
|
|
398
|
-
const instance = axios.create({
|
|
399
|
-
baseURL: baseURL || process.env.API_BASE_URL || 'http://localhost:3002',
|
|
400
|
-
timeout: 30000,
|
|
401
|
-
headers: {
|
|
402
|
-
'Content-Type': 'application/json',
|
|
403
|
-
},
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
// 请求拦截器
|
|
407
|
-
instance.interceptors.request.use(
|
|
408
|
-
(config: AxiosRequestConfig) => {
|
|
409
|
-
// 添加认证令牌
|
|
410
|
-
const token = localStorage.getItem('auth_token');
|
|
411
|
-
if (token && config.headers) {
|
|
412
|
-
config.headers.Authorization = \`Bearer \${token}\`;
|
|
413
|
-
}
|
|
414
|
-
return config;
|
|
415
|
-
},
|
|
416
|
-
(error) => {
|
|
417
|
-
return Promise.reject(error);
|
|
418
|
-
}
|
|
419
|
-
);
|
|
420
|
-
|
|
421
|
-
// 响应拦截器
|
|
422
|
-
instance.interceptors.response.use(
|
|
423
|
-
(response: AxiosResponse) => {
|
|
424
|
-
return response.data;
|
|
425
|
-
},
|
|
426
|
-
(error) => {
|
|
427
|
-
// 统一错误处理
|
|
428
|
-
if (error.response?.status === 401) {
|
|
429
|
-
// 未授权处理
|
|
430
|
-
localStorage.removeItem('auth_token');
|
|
431
|
-
window.location.href = '/login';
|
|
432
|
-
}
|
|
433
|
-
return Promise.reject(error.response?.data || error);
|
|
434
|
-
}
|
|
435
|
-
);
|
|
436
|
-
|
|
437
|
-
return instance;
|
|
438
|
-
};
|
|
439
|
-
|
|
440
|
-
// 默认 HTTP 客户端实例
|
|
441
|
-
export const httpClient = createHttpClient();
|
|
442
|
-
|
|
443
|
-
export default httpClient;
|
|
444
|
-
`;
|
|
445
|
-
|
|
446
|
-
// 通用工具函数
|
|
447
|
-
const commonUtilsContent = `// 通用工具函数
|
|
448
|
-
|
|
449
|
-
// 日期格式化
|
|
450
|
-
export const formatDate = (date: Date, format: string = 'YYYY-MM-DD'): string => {
|
|
451
|
-
const year = date.getFullYear();
|
|
452
|
-
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
453
|
-
const day = String(date.getDate()).padStart(2, '0');
|
|
454
|
-
|
|
455
|
-
return format
|
|
456
|
-
.replace('YYYY', String(year))
|
|
457
|
-
.replace('MM', month)
|
|
458
|
-
.replace('DD', day);
|
|
459
|
-
};
|
|
460
|
-
|
|
461
|
-
// 深度克隆
|
|
462
|
-
export const deepClone = <T>(obj: T): T => {
|
|
463
|
-
if (obj === null || typeof obj !== 'object') {
|
|
464
|
-
return obj;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
if (obj instanceof Date) {
|
|
468
|
-
return new Date(obj.getTime()) as unknown as T;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
if (Array.isArray(obj)) {
|
|
472
|
-
return obj.map(item => deepClone(item)) as unknown as T;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
if (typeof obj === 'object') {
|
|
476
|
-
const cloned = {} as T;
|
|
477
|
-
for (const key in obj) {
|
|
478
|
-
if (obj.hasOwnProperty(key)) {
|
|
479
|
-
cloned[key] = deepClone(obj[key]);
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
return cloned;
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
return obj;
|
|
486
|
-
};
|
|
487
|
-
|
|
488
|
-
// API 响应处理
|
|
489
|
-
export interface ApiResponse<T = any> {
|
|
490
|
-
code: number;
|
|
491
|
-
message: string;
|
|
492
|
-
data: T;
|
|
493
|
-
timestamp: number;
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
// 分页响应
|
|
497
|
-
export interface PaginatedResponse<T = any> {
|
|
498
|
-
items: T[];
|
|
499
|
-
total: number;
|
|
500
|
-
page: number;
|
|
501
|
-
limit: number;
|
|
502
|
-
totalPages: number;
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
// 错误处理
|
|
506
|
-
export class ApiError extends Error {
|
|
507
|
-
constructor(
|
|
508
|
-
public code: number,
|
|
509
|
-
message: string,
|
|
510
|
-
public details?: any
|
|
511
|
-
) {
|
|
512
|
-
super(message);
|
|
513
|
-
this.name = 'ApiError';
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
`;
|
|
517
|
-
|
|
518
|
-
// 工具索引文件
|
|
519
|
-
const utilsIndexContent = `// 工具函数索引
|
|
520
|
-
// 自动生成,请勿手动修改
|
|
521
|
-
|
|
522
|
-
export * from './http';
|
|
523
|
-
export * from './common';
|
|
524
|
-
`;
|
|
525
|
-
|
|
526
|
-
// 写入工具函数
|
|
527
|
-
const httpUtilsPath = path.join(utilsDir, 'http.ts');
|
|
528
|
-
const commonUtilsPath = path.join(utilsDir, 'common.ts');
|
|
529
|
-
const utilsIndexPath = path.join(utilsDir, 'index.ts');
|
|
530
|
-
|
|
531
|
-
// 检查文件是否存在,避免覆盖可能的自定义修改
|
|
532
|
-
if (!fs.existsSync(httpUtilsPath)) {
|
|
533
|
-
fs.writeFileSync(httpUtilsPath, httpUtilsContent);
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
if (!fs.existsSync(commonUtilsPath)) {
|
|
537
|
-
fs.writeFileSync(commonUtilsPath, commonUtilsContent);
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
if (!fs.existsSync(utilsIndexPath)) {
|
|
541
|
-
fs.writeFileSync(utilsIndexPath, utilsIndexContent);
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
console.log('📄 工具函数生成完成');
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
// 执行生成
|
|
548
|
-
generateApiTypes()
|
|
549
|
-
.then(() => {
|
|
550
|
-
console.log('🎉 API 生成过程完成!');
|
|
551
|
-
console.log('📁 生成的文件结构:');
|
|
552
|
-
console.log(' - src/api/ # API 客户端');
|
|
553
|
-
console.log(' - src/api/api-instance.ts # API 实例化文件');
|
|
554
|
-
console.log(' - src/types/ # 类型定义');
|
|
555
|
-
console.log(' - src/utils/ # 工具函数');
|
|
556
|
-
console.log(' - src/index.ts # 主入口文件');
|
|
557
|
-
console.log('');
|
|
558
|
-
console.log('💡 使用方法:');
|
|
559
|
-
console.log(' 1. 直接使用默认实例:');
|
|
560
|
-
console.log(' import api from \'@/api\';');
|
|
561
|
-
console.log(' api.article.findAll();');
|
|
562
|
-
console.log('');
|
|
563
|
-
console.log(' 2. 创建自定义实例:');
|
|
564
|
-
console.log(' import { createApiInstance } from \'@/api\';');
|
|
565
|
-
console.log(' const customApi = createApiInstance({ baseURL: \'https://api.example.com\' });');
|
|
566
|
-
console.log(' customApi.article.findAll();');
|
|
567
|
-
})
|
|
568
|
-
.catch((error) => {
|
|
569
|
-
console.error('❌ API 生成过程失败:', error.message);
|
|
570
|
-
process.exit(1);
|
|
571
|
-
});
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
const { execSync } = require('child_process');
|
|
2
|
-
const { unlinkSync, existsSync } = require('fs');
|
|
3
|
-
const { join } = require('path');
|
|
4
|
-
|
|
5
|
-
console.log('🚀 Starting full API types generation process...\n');
|
|
6
|
-
|
|
7
|
-
try {
|
|
8
|
-
// Step 1: Enter server directory and generate swagger.json
|
|
9
|
-
console.log('1️⃣ Generating Swagger JSON in server directory...');
|
|
10
|
-
try {
|
|
11
|
-
execSync('cd ../server && npm run generate:swagger', { stdio: 'inherit' });
|
|
12
|
-
console.log('✅ Swagger JSON generated successfully in server directory!\n');
|
|
13
|
-
} catch (error) {
|
|
14
|
-
console.log('⚠️ Failed to generate new swagger.json, checking for existing file...\n');
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Step 2: Check if swagger.json exists in server directory
|
|
18
|
-
const serverSwaggerPath = join(__dirname, '../../server/public/swagger.json');
|
|
19
|
-
if (!existsSync(serverSwaggerPath)) {
|
|
20
|
-
console.error('❌ No swagger.json file available in server directory');
|
|
21
|
-
process.exit(1);
|
|
22
|
-
}
|
|
23
|
-
console.log('✅ Using swagger.json from server directory!\n');
|
|
24
|
-
|
|
25
|
-
// Step 3: Generate TypeScript definitions directly to client/src
|
|
26
|
-
console.log('2️⃣ Generating TypeScript definitions to client/src...');
|
|
27
|
-
execSync('node scripts/generate-api-types.js', { stdio: 'inherit' });
|
|
28
|
-
console.log('✅ TypeScript definitions generated successfully!\n');
|
|
29
|
-
|
|
30
|
-
// Step 4: Clean up - remove swagger.json from server directory
|
|
31
|
-
console.log('3️⃣ Cleaning up swagger.json files...');
|
|
32
|
-
|
|
33
|
-
// Remove from server directory
|
|
34
|
-
if (existsSync(serverSwaggerPath)) {
|
|
35
|
-
unlinkSync(serverSwaggerPath);
|
|
36
|
-
console.log('✅ Removed swagger.json from server directory');
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
console.log('✅ Cleanup completed!\n');
|
|
40
|
-
|
|
41
|
-
console.log('🎉 Full generation process completed successfully!');
|
|
42
|
-
console.log('📁 Generated files are available in client/src/');
|
|
43
|
-
|
|
44
|
-
} catch (error) {
|
|
45
|
-
console.error('❌ Error during generation process:', error.message);
|
|
46
|
-
process.exit(1);
|
|
47
|
-
}
|