File size: 3,260 Bytes
e1ae2c6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/**
 * 自定义错误类 - 配置相关错误
 */
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) {
  const { formatPrefix, isVerbose } = require('./logger');

  // 错误标题行
  console.error(`\n${formatPrefix('ERROR')} ${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('建议:');
    error.suggestions.forEach((suggestion, index) => {
      console.error(`  ${index + 1}) ${suggestion}`);
    });
  }

  // DEBUG 提示(仅在非 DEBUG 模式下显示)
  if (process.env.DEBUG) {
    console.error('\n堆栈:');
    console.error(error.stack || String(error));
  } else if (isVerbose() && error && error.stack) {
    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,
};