refactor: reorganize package structure and decouple framework packages (#338)
* refactor: reorganize package structure and decouple framework packages ## Package Structure Reorganization - Reorganized 55 packages into categorized subdirectories: - packages/framework/ - Generic framework (Laya/Cocos compatible) - packages/engine/ - ESEngine core modules - packages/rendering/ - Rendering modules (WASM dependent) - packages/physics/ - Physics modules - packages/streaming/ - World streaming - packages/network-ext/ - Network extensions - packages/editor/ - Editor framework and plugins - packages/rust/ - Rust WASM engine - packages/tools/ - Build tools and SDK ## Framework Package Decoupling - Decoupled behavior-tree and blueprint packages from ESEngine dependencies - Created abstracted interfaces (IBTAssetManager, IBehaviorTreeAssetContent) - ESEngine-specific code moved to esengine/ subpath exports - Framework packages now usable with Cocos/Laya without ESEngine ## CI Configuration - Updated CI to only type-check and lint framework packages - Added type-check:framework and lint:framework scripts ## Breaking Changes - Package import paths changed due to directory reorganization - ESEngine integrations now use subpath imports (e.g., '@esengine/behavior-tree/esengine') * fix: update es-engine file path after directory reorganization * docs: update README to focus on framework over engine * ci: only build framework packages, remove Rust/WASM dependencies * fix: remove esengine subpath from behavior-tree and blueprint builds ESEngine integration code will only be available in full engine builds. Framework packages are now purely engine-agnostic. * fix: move network-protocols to framework, build both in CI * fix: update workflow paths from packages/core to packages/framework/core * fix: exclude esengine folder from type-check in behavior-tree and blueprint * fix: update network tsconfig references to new paths * fix: add test:ci:framework to only test framework packages in CI * fix: only build core and math npm packages in CI * fix: exclude test files from CodeQL and fix string escaping security issue
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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/editor-app/src/domain/errors/NetworkError.ts
Normal file
44
packages/editor/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/editor-app/src/domain/errors/PluginError.ts
Normal file
57
packages/editor/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
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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/editor-app/src/domain/errors/index.ts
Normal file
5
packages/editor/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';
|
||||
5
packages/editor/editor-app/src/domain/index.ts
Normal file
5
packages/editor/editor-app/src/domain/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export * from './errors';
|
||||
export * from './models';
|
||||
export * from './value-objects';
|
||||
export * from './interfaces';
|
||||
export * from './services';
|
||||
@@ -0,0 +1 @@
|
||||
export {};
|
||||
1
packages/editor/editor-app/src/domain/models/index.ts
Normal file
1
packages/editor/editor-app/src/domain/models/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
1
packages/editor/editor-app/src/domain/services/index.ts
Normal file
1
packages/editor/editor-app/src/domain/services/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export {};
|
||||
@@ -0,0 +1 @@
|
||||
export {};
|
||||
Reference in New Issue
Block a user