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:
YHH
2025-12-26 14:50:35 +08:00
committed by GitHub
parent a84ff902e4
commit 155411e743
1936 changed files with 4147 additions and 11578 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';

View File

@@ -0,0 +1,5 @@
export * from './errors';
export * from './models';
export * from './value-objects';
export * from './interfaces';
export * from './services';

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1 @@
export {};