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:
YHH
2025-11-18 22:28:13 +08:00
committed by GitHub
parent bce3a6e253
commit caed5428d5
48 changed files with 2221 additions and 44 deletions

View 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;
}

View 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
);
}
}

View 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);
}
}

View 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
);
}
}

View 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
);
}
}

View 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';