refactor: 统一错误处理机制
- 引入 ConfigError/TemplateError/BuildError/FileError 与 wrapAsyncError,统一错误输出 - generator 入口接入 wrapAsyncError,确保命令行执行路径一致 - 兜底逻辑使用 instanceof,保留 BuildError/TemplateError 上下文信息 - 合并格式化提交(仅缩进/换行调整)
This commit is contained in:
127
src/generator/utils/errors.js
Normal file
127
src/generator/utils/errors.js
Normal file
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* 自定义错误类 - 配置相关错误
|
||||
*/
|
||||
class ConfigError extends Error {
|
||||
constructor(message, suggestions = []) {
|
||||
super(message);
|
||||
this.name = 'ConfigError';
|
||||
this.suggestions = suggestions;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义错误类 - 模板相关错误
|
||||
*/
|
||||
class TemplateError extends Error {
|
||||
constructor(message, templatePath = null) {
|
||||
super(message);
|
||||
this.name = 'TemplateError';
|
||||
this.templatePath = templatePath;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义错误类 - 构建相关错误
|
||||
*/
|
||||
class BuildError extends Error {
|
||||
constructor(message, context = {}) {
|
||||
super(message);
|
||||
this.name = 'BuildError';
|
||||
this.context = context;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义错误类 - 文件操作相关错误
|
||||
*/
|
||||
class FileError extends Error {
|
||||
constructor(message, filePath = null, suggestions = []) {
|
||||
super(message);
|
||||
this.name = 'FileError';
|
||||
this.filePath = filePath;
|
||||
this.suggestions = suggestions;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一错误处理器 - 专业紧凑版(中文)
|
||||
* @param {Error} error - 错误对象
|
||||
* @param {number} exitCode - 退出码,默认为 1
|
||||
*/
|
||||
function handleError(error, exitCode = 1) {
|
||||
// 错误标题行
|
||||
console.error(`\n✖ ${error.name}: ${error.message}`);
|
||||
|
||||
// 文件路径(如果有)
|
||||
if (error.filePath || error.templatePath) {
|
||||
const path = error.filePath || error.templatePath;
|
||||
console.error(` 位置: ${path}`);
|
||||
}
|
||||
|
||||
// 上下文信息(如果有)
|
||||
if (error.context && Object.keys(error.context).length > 0) {
|
||||
console.error('│');
|
||||
for (const [key, value] of Object.entries(error.context)) {
|
||||
console.error(`│ ${key}: ${value}`);
|
||||
}
|
||||
}
|
||||
|
||||
// 修复建议(如果有)
|
||||
if (error.suggestions && error.suggestions.length > 0) {
|
||||
console.error('│');
|
||||
console.error('➜ 解决方案:');
|
||||
error.suggestions.forEach((suggestion, index) => {
|
||||
console.error(` ${index + 1}. ${suggestion}`);
|
||||
});
|
||||
}
|
||||
|
||||
// DEBUG 提示(仅在非 DEBUG 模式下显示)
|
||||
if (process.env.DEBUG) {
|
||||
console.error('\n堆栈跟踪:');
|
||||
console.error(error.stack);
|
||||
} else {
|
||||
console.error('\n(设置 DEBUG=1 查看堆栈跟踪)');
|
||||
}
|
||||
|
||||
console.error(); // 空行结束
|
||||
process.exit(exitCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 包装异步函数,自动处理未捕获的错误
|
||||
* @param {Function} fn - 异步函数
|
||||
* @returns {Function} 包装后的函数
|
||||
*/
|
||||
function wrapAsyncError(fn) {
|
||||
return async (...args) => {
|
||||
try {
|
||||
return await fn(...args);
|
||||
} catch (error) {
|
||||
// 如果是自定义错误,直接使用 handleError
|
||||
if (
|
||||
error instanceof ConfigError ||
|
||||
error instanceof TemplateError ||
|
||||
error instanceof BuildError ||
|
||||
error instanceof FileError
|
||||
) {
|
||||
handleError(error);
|
||||
} else {
|
||||
// 否则包装为 BuildError
|
||||
handleError(
|
||||
new BuildError(error.message || '未知错误', {
|
||||
原始错误类型: error.name || 'Error',
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
ConfigError,
|
||||
TemplateError,
|
||||
BuildError,
|
||||
FileError,
|
||||
handleError,
|
||||
wrapAsyncError,
|
||||
};
|
||||
Reference in New Issue
Block a user