Skip to content

Commit d4a8568

Browse files
committed
refactor: update toolkit generator
1 parent e44d91c commit d4a8568

25 files changed

+234
-345
lines changed

client/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@fecommunity/reactpress-client",
3-
"version": "1.0.0-beta.22",
3+
"version": "1.0.0-beta.23",
44
"bin": {
55
"reactpress-client": "./bin/reactpress-client.js"
66
},
@@ -85,4 +85,4 @@
8585
"tsconfig-paths-webpack-plugin": "^3.5.2",
8686
"typescript": "4.6.2"
8787
}
88-
}
88+
}

scripts/publish-packages.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ const packages = [
2323
name: '@fecommunity/reactpress-client',
2424
path: 'client',
2525
description: 'Frontend application package'
26+
},
27+
{
28+
name: '@fecommunity/reactpress-toolkit',
29+
path: 'toolkit',
30+
description: 'API client and utilities toolkit'
2631
}
2732
];
2833

@@ -264,6 +269,8 @@ function buildPackage(packagePath, packageName) {
264269
execSync('pnpm run prebuild && pnpm run build', { cwd: path.join(process.cwd(), packagePath), stdio: 'inherit' });
265270
} else if (packagePath === 'client') {
266271
execSync('pnpm run prebuild && pnpm run build', { cwd: path.join(process.cwd(), packagePath), stdio: 'inherit' });
272+
} else if (packagePath === 'toolkit') {
273+
execSync('pnpm run build', { cwd: path.join(process.cwd(), packagePath), stdio: 'inherit' });
267274
}
268275
console.log(chalk.green(`✅ ${packageName} built successfully`));
269276
} catch (error) {

server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@fecommunity/reactpress-server",
3-
"version": "1.0.0-beta.47",
3+
"version": "1.0.0-beta.48",
44
"description": "ReactPress Server - NestJS-based backend API for ReactPress CMS",
55
"author": "fecommunity",
66
"license": "MIT",

toolkit/package.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
{
2-
"name": "@fecommunity/reactpress-tookit",
3-
"version": "1.0.0-beta.0",
2+
"name": "@fecommunity/reactpress-toolkit",
3+
"version": "1.0.0-beta.1",
44
"main": "index.js",
55
"scripts": {
6-
"generate": "node scripts/generate-swagger.js"
6+
"generate": "node scripts/generate-swagger.js",
7+
"build": "tsc"
78
},
9+
"files": [
10+
"dist"
11+
],
812
"keywords": [],
913
"author": "",
1014
"license": "ISC",

toolkit/scripts/generate-api-types.js

Lines changed: 50 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ async function generateApiTypes() {
3838
hooks: {
3939
onPrepareConfig: (currentConfiguration) => {
4040
const config = currentConfiguration.config;
41-
config.fileNames.httpClient = 'httpClient'; // http客户端文件名
41+
config.fileNames.httpClient = 'HttpClient'; // 使用大驼峰命名
4242
return { ...currentConfiguration, config };
4343
},
4444
},
@@ -82,7 +82,7 @@ async function organizeGeneratedFiles() {
8282

8383
if (file.endsWith('.ts')) {
8484
// 根据文件名判断文件类型
85-
if (file === 'httpClient.ts' || file === 'api-client.ts' || /[A-Z]/.test(file[0])) {
85+
if (file === 'HttpClient.ts' || file === 'ApiClient.ts' || /[A-Z]/.test(file[0])) {
8686
// API 文件:首字母大写的文件或特定的客户端文件
8787
fs.moveSync(filePath, path.join(apiDir, file), { overwrite: true });
8888
console.log(`📄 移动 API 文件: ${file} -> api/`);
@@ -128,7 +128,7 @@ async function organizeGeneratedFiles() {
128128
async function fixHttpClient() {
129129
console.log('🔧 修复 HttpClient 类...');
130130

131-
const httpClientPath = path.join(CONFIG.output, 'api', 'httpClient.ts');
131+
const httpClientPath = path.join(CONFIG.output, 'api', 'HttpClient.ts');
132132

133133
if (fs.existsSync(httpClientPath)) {
134134
let content = fs.readFileSync(httpClientPath, 'utf8');
@@ -140,10 +140,15 @@ async function fixHttpClient() {
140140
content = content.replace(/interface ApiConfig/, 'interface HttpClientConfig');
141141
content = content.replace(/ApiConfig<SecurityDataType>/g, 'HttpClientConfig<SecurityDataType>');
142142

143+
// 添加默认导出
144+
if (!content.includes('export default HttpClient')) {
145+
content += '\n\nexport default HttpClient;\n';
146+
}
147+
143148
fs.writeFileSync(httpClientPath, content);
144149
console.log('✅ HttpClient 修复完成');
145150
} else {
146-
console.log('⚠️ httpClient.ts 文件不存在,跳过修复');
151+
console.log('⚠️ HttpClient.ts 文件不存在,跳过修复');
147152
}
148153
}
149154

@@ -166,6 +171,12 @@ async function fixApiImports() {
166171
"from '../types/data-contracts'"
167172
);
168173

174+
// 修复 HttpClient 导入路径
175+
content = content.replace(
176+
/from '\.\/httpClient'/g,
177+
"from './HttpClient'"
178+
);
179+
169180
// 修复其他可能的类型导入
170181
content = content.replace(
171182
/from '\.\/([^']+)'/g,
@@ -196,36 +207,24 @@ async function renameApiMethods() {
196207
const apiFiles = fs.readdirSync(apiDir).filter(file =>
197208
file.endsWith('.ts') &&
198209
file !== 'index.ts' &&
199-
file !== 'httpClient.ts' &&
210+
file !== 'HttpClient.ts' &&
200211
/[A-Z]/.test(file[0]) // 首字母大写的文件
201212
);
202213

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-
220214
for (const file of apiFiles) {
221215
const filePath = path.join(apiDir, file);
222216
let content = fs.readFileSync(filePath, 'utf8');
223217

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-
}
218+
// 使用正则表达式匹配并重命名方法
219+
// 匹配模式: 方法名以 Controller 开头,后面跟着大写字母
220+
content = content.replace(
221+
/(\w+)Controller([A-Z]\w+)/g,
222+
(match, prefix, methodName) => {
223+
// 将方法名的首字母小写
224+
const newMethodName = methodName.charAt(0).toLowerCase() + methodName.slice(1);
225+
return `${prefix}${newMethodName}`;
226+
}
227+
);
229228

230229
// 写入修复后的内容
231230
fs.writeFileSync(filePath, content);
@@ -264,7 +263,7 @@ async function createApiIndex() {
264263
const apiDir = path.join(CONFIG.output, 'api');
265264

266265
// 获取所有 API 文件
267-
const apiFiles = fs.readdirSync(apiDir).filter(file => file.endsWith('.ts') && file !== 'index.ts' && file !== 'api-instance.ts');
266+
const apiFiles = fs.readdirSync(apiDir).filter(file => file.endsWith('.ts') && file !== 'index.ts' && file !== 'ApiInstance.ts');
268267

269268
let indexContent = '// API 客户端索引\n// 自动生成,请勿手动修改\n\n';
270269

@@ -275,8 +274,8 @@ async function createApiIndex() {
275274
});
276275

277276
// 添加 HttpClient 导出
278-
indexContent += `\nexport { default as HttpClient } from './httpClient';\n`;
279-
indexContent += `export type { HttpClientConfig } from './httpClient';\n`;
277+
indexContent += `\nexport { default as HttpClient } from './HttpClient';\n`;
278+
indexContent += `export type { HttpClientConfig } from './HttpClient';\n`;
280279

281280
// 写入索引文件
282281
fs.writeFileSync(path.join(apiDir, 'index.ts'), indexContent);
@@ -294,7 +293,7 @@ export * from './api';
294293
export * from './types';
295294
export * from './utils';
296295
297-
export { default } from './api/api-instance';
296+
export { default } from './api/ApiInstance';
298297
`;
299298

300299
fs.writeFileSync(path.join(CONFIG.output, 'index.ts'), mainIndexContent);
@@ -307,12 +306,12 @@ async function createApiInstance() {
307306

308307
const apiDir = path.join(CONFIG.output, 'api');
309308

310-
// 获取所有 API 文件(排除 index.ts 和 httpClient.ts)
309+
// 获取所有 API 文件(排除 index.ts 和 HttpClient.ts)
311310
const apiFiles = fs.readdirSync(apiDir).filter(file =>
312311
file.endsWith('.ts') &&
313312
file !== 'index.ts' &&
314-
file !== 'httpClient.ts' &&
315-
file !== 'api-instance.ts' &&
313+
file !== 'HttpClient.ts' &&
314+
file !== 'ApiInstance.ts' &&
316315
/[A-Z]/.test(file[0]) // 首字母大写的文件
317316
);
318317

@@ -339,7 +338,7 @@ async function createApiInstance() {
339338
const apiInstanceContent = `// API 实例化文件
340339
// 自动生成,请勿手动修改
341340
342-
import { HttpClient, HttpClientConfig } from './httpClient';
341+
import { HttpClient, HttpClientConfig } from './HttpClient';
343342
${imports}
344343
345344
export interface ApiConfig<SecurityDataType = unknown> extends HttpClientConfig<SecurityDataType> {
@@ -371,15 +370,16 @@ export const api = createApiInstance();
371370
export default api;
372371
`;
373372

374-
fs.writeFileSync(path.join(apiDir, 'api-instance.ts'), apiInstanceContent);
373+
// 使用大驼峰命名
374+
fs.writeFileSync(path.join(apiDir, 'ApiInstance.ts'), apiInstanceContent);
375375
console.log('✅ API 实例化文件已创建');
376376

377-
// 更新 API 索引文件,添加对 api-instance.ts 的导出
377+
// 更新 API 索引文件,添加对 ApiInstance.ts 的导出
378378
const apiIndexPath = path.join(apiDir, 'index.ts');
379379
let apiIndexContent = fs.readFileSync(apiIndexPath, 'utf8');
380380

381-
apiIndexContent += '\n// API 实例化\nexport * from \'./api-instance\';\n';
382-
apiIndexContent += 'export { default as api } from \'./api-instance\';\n';
381+
apiIndexContent += '\n// API 实例化\nexport * from \'./ApiInstance\';\n';
382+
apiIndexContent += 'export { default as api } from \'./ApiInstance\';\n';
383383

384384
fs.writeFileSync(apiIndexPath, apiIndexContent);
385385
console.log('✅ 更新 API 索引文件');
@@ -390,8 +390,8 @@ async function generateUtils() {
390390
const utilsDir = path.join(CONFIG.output, 'utils');
391391
fs.ensureDirSync(utilsDir);
392392

393-
// HTTP 客户端配置
394-
const httpUtilsContent = `import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
393+
// HTTP 客户端配置 - 修复类型错误
394+
const httpUtilsContent = `import axios, { AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
395395
396396
// 创建自定义 axios 实例
397397
export const createHttpClient = (baseURL?: string) => {
@@ -403,9 +403,9 @@ export const createHttpClient = (baseURL?: string) => {
403403
},
404404
});
405405
406-
// 请求拦截器
406+
// 请求拦截器 - 修复类型错误
407407
instance.interceptors.request.use(
408-
(config: AxiosRequestConfig) => {
408+
(config: InternalAxiosRequestConfig) => {
409409
// 添加认证令牌
410410
const token = localStorage.getItem('auth_token');
411411
if (token && config.headers) {
@@ -512,6 +512,11 @@ export class ApiError extends Error {
512512
super(message);
513513
this.name = 'ApiError';
514514
}
515+
516+
// 检查是否为 ApiError 实例
517+
static isInstance(error: any): error is ApiError {
518+
return error instanceof ApiError;
519+
}
515520
}
516521
`;
517522

@@ -550,7 +555,8 @@ generateApiTypes()
550555
console.log('🎉 API 生成过程完成!');
551556
console.log('📁 生成的文件结构:');
552557
console.log(' - src/api/ # API 客户端');
553-
console.log(' - src/api/api-instance.ts # API 实例化文件');
558+
console.log(' - src/api/ApiInstance.ts # API 实例化文件');
559+
console.log(' - src/api/HttpClient.ts # HTTP 客户端');
554560
console.log(' - src/types/ # 类型定义');
555561
console.log(' - src/utils/ # 工具函数');
556562
console.log(' - src/index.ts # 主入口文件');

0 commit comments

Comments
 (0)