refactor(editor-app): 改进架构和类型安全 (#226)
* refactor(editor-app): 改进架构和类型安全 * refactor(editor-app): 开始拆分 Inspector.tsx - 创建基础架构 * refactor(editor-app): 完成 Inspector.tsx 拆分 * refactor(editor-app): 优化 Inspector 类型定义,消除所有 any 使用 * refactor(editor): 实现可扩展的属性渲染器系统 * Potential fix for code scanning alert no. 231: Unused variable, import, function or class Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> * fix(ci): 防止 Codecov 服务故障阻塞 CI 流程 --------- Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
This commit is contained in:
9
packages/editor-app/src/domain/errors/DomainError.ts
Normal file
9
packages/editor-app/src/domain/errors/DomainError.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
export abstract class DomainError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = this.constructor.name;
|
||||
Object.setPrototypeOf(this, new.target.prototype);
|
||||
}
|
||||
|
||||
abstract getUserMessage(): string;
|
||||
}
|
||||
54
packages/editor-app/src/domain/errors/FileOperationError.ts
Normal file
54
packages/editor-app/src/domain/errors/FileOperationError.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { DomainError } from './DomainError';
|
||||
|
||||
export class FileOperationError extends DomainError {
|
||||
constructor(
|
||||
message: string,
|
||||
public readonly filePath?: string,
|
||||
public readonly operation?: 'read' | 'write' | 'delete' | 'parse' | 'create',
|
||||
public readonly originalError?: Error
|
||||
) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
getUserMessage(): string {
|
||||
const operationMap = {
|
||||
read: '读取',
|
||||
write: '写入',
|
||||
delete: '删除',
|
||||
parse: '解析',
|
||||
create: '创建'
|
||||
};
|
||||
|
||||
const operationText = this.operation ? operationMap[this.operation] : '操作';
|
||||
const fileText = this.filePath ? ` ${this.filePath}` : '';
|
||||
|
||||
return `文件${operationText}失败${fileText}: ${this.message}`;
|
||||
}
|
||||
|
||||
static readFailed(filePath: string, error?: Error): FileOperationError {
|
||||
return new FileOperationError(
|
||||
error?.message || '无法读取文件',
|
||||
filePath,
|
||||
'read',
|
||||
error
|
||||
);
|
||||
}
|
||||
|
||||
static writeFailed(filePath: string, error?: Error): FileOperationError {
|
||||
return new FileOperationError(
|
||||
error?.message || '无法写入文件',
|
||||
filePath,
|
||||
'write',
|
||||
error
|
||||
);
|
||||
}
|
||||
|
||||
static parseFailed(filePath: string, error?: Error): FileOperationError {
|
||||
return new FileOperationError(
|
||||
error?.message || '文件格式不正确',
|
||||
filePath,
|
||||
'parse',
|
||||
error
|
||||
);
|
||||
}
|
||||
}
|
||||
44
packages/editor-app/src/domain/errors/NetworkError.ts
Normal file
44
packages/editor-app/src/domain/errors/NetworkError.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { DomainError } from './DomainError';
|
||||
|
||||
export class NetworkError extends DomainError {
|
||||
constructor(
|
||||
message: string,
|
||||
public readonly url?: string,
|
||||
public readonly statusCode?: number,
|
||||
public readonly method?: string,
|
||||
public readonly originalError?: Error
|
||||
) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
getUserMessage(): string {
|
||||
if (this.statusCode) {
|
||||
return `网络请求失败 (${this.statusCode}): ${this.message}`;
|
||||
}
|
||||
return `网络请求失败: ${this.message}`;
|
||||
}
|
||||
|
||||
static requestFailed(url: string, error?: Error): NetworkError {
|
||||
return new NetworkError(error?.message || '请求失败', url, undefined, undefined, error);
|
||||
}
|
||||
|
||||
static timeout(url: string): NetworkError {
|
||||
return new NetworkError('请求超时', url);
|
||||
}
|
||||
|
||||
static unauthorized(): NetworkError {
|
||||
return new NetworkError('未授权,请先登录', undefined, 401);
|
||||
}
|
||||
|
||||
static forbidden(): NetworkError {
|
||||
return new NetworkError('没有权限访问此资源', undefined, 403);
|
||||
}
|
||||
|
||||
static notFound(url: string): NetworkError {
|
||||
return new NetworkError('资源不存在', url, 404);
|
||||
}
|
||||
|
||||
static serverError(): NetworkError {
|
||||
return new NetworkError('服务器错误', undefined, 500);
|
||||
}
|
||||
}
|
||||
57
packages/editor-app/src/domain/errors/PluginError.ts
Normal file
57
packages/editor-app/src/domain/errors/PluginError.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { DomainError } from './DomainError';
|
||||
|
||||
export class PluginError extends DomainError {
|
||||
constructor(
|
||||
message: string,
|
||||
public readonly pluginId?: string,
|
||||
public readonly pluginName?: string,
|
||||
public readonly operation?: 'load' | 'activate' | 'deactivate' | 'execute',
|
||||
public readonly originalError?: Error
|
||||
) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
getUserMessage(): string {
|
||||
const operationMap = {
|
||||
load: '加载',
|
||||
activate: '激活',
|
||||
deactivate: '停用',
|
||||
execute: '执行'
|
||||
};
|
||||
|
||||
const operationText = this.operation ? operationMap[this.operation] : '操作';
|
||||
const pluginText = this.pluginName || this.pluginId || '插件';
|
||||
|
||||
return `${pluginText}${operationText}失败: ${this.message}`;
|
||||
}
|
||||
|
||||
static loadFailed(pluginId: string, error?: Error): PluginError {
|
||||
return new PluginError(
|
||||
error?.message || '插件加载失败',
|
||||
pluginId,
|
||||
undefined,
|
||||
'load',
|
||||
error
|
||||
);
|
||||
}
|
||||
|
||||
static activateFailed(pluginId: string, pluginName: string, error?: Error): PluginError {
|
||||
return new PluginError(
|
||||
error?.message || '插件激活失败',
|
||||
pluginId,
|
||||
pluginName,
|
||||
'activate',
|
||||
error
|
||||
);
|
||||
}
|
||||
|
||||
static executeFailed(pluginId: string, error?: Error): PluginError {
|
||||
return new PluginError(
|
||||
error?.message || '插件执行失败',
|
||||
pluginId,
|
||||
undefined,
|
||||
'execute',
|
||||
error
|
||||
);
|
||||
}
|
||||
}
|
||||
36
packages/editor-app/src/domain/errors/ValidationError.ts
Normal file
36
packages/editor-app/src/domain/errors/ValidationError.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { DomainError } from './DomainError';
|
||||
|
||||
export class ValidationError extends DomainError {
|
||||
constructor(
|
||||
message: string,
|
||||
public readonly field?: string,
|
||||
public readonly value?: unknown
|
||||
) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
getUserMessage(): string {
|
||||
if (this.field) {
|
||||
return `验证失败: ${this.field} - ${this.message}`;
|
||||
}
|
||||
return `验证失败: ${this.message}`;
|
||||
}
|
||||
|
||||
static requiredField(field: string): ValidationError {
|
||||
return new ValidationError(`字段 ${field} 是必需的`, field);
|
||||
}
|
||||
|
||||
static invalidValue(field: string, value: unknown, reason?: string): ValidationError {
|
||||
const message = reason
|
||||
? `字段 ${field} 的值无效: ${reason}`
|
||||
: `字段 ${field} 的值无效`;
|
||||
return new ValidationError(message, field, value);
|
||||
}
|
||||
|
||||
static invalidFormat(field: string, expectedFormat: string): ValidationError {
|
||||
return new ValidationError(
|
||||
`字段 ${field} 格式不正确,期望格式: ${expectedFormat}`,
|
||||
field
|
||||
);
|
||||
}
|
||||
}
|
||||
5
packages/editor-app/src/domain/errors/index.ts
Normal file
5
packages/editor-app/src/domain/errors/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export { DomainError } from './DomainError';
|
||||
export { ValidationError } from './ValidationError';
|
||||
export { FileOperationError } from './FileOperationError';
|
||||
export { PluginError } from './PluginError';
|
||||
export { NetworkError } from './NetworkError';
|
||||
Reference in New Issue
Block a user