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,30 @@
import { ReactElement } from 'react';
export interface PropertyContext {
readonly name: string;
readonly path?: string[];
readonly depth?: number;
readonly readonly?: boolean;
readonly decimalPlaces?: number;
readonly expandByDefault?: boolean;
readonly parentObject?: any;
readonly metadata?: Record<string, any>;
}
export interface IPropertyRenderer<T = any> {
readonly id: string;
readonly name: string;
readonly priority?: number;
canHandle(value: any, context: PropertyContext): value is T;
render(value: T, context: PropertyContext): ReactElement;
}
export interface IPropertyRendererRegistry {
register(renderer: IPropertyRenderer): void;
unregister(rendererId: string): void;
findRenderer(value: any, context: PropertyContext): IPropertyRenderer | undefined;
render(value: any, context: PropertyContext): ReactElement | null;
getAllRenderers(): IPropertyRenderer[];
hasRenderer(value: any, context: PropertyContext): boolean;
}

View File

@@ -0,0 +1,74 @@
import React from 'react';
import { IService, createLogger } from '@esengine/ecs-framework';
import { IPropertyRenderer, IPropertyRendererRegistry, PropertyContext } from './IPropertyRenderer';
const logger = createLogger('PropertyRendererRegistry');
export class PropertyRendererRegistry implements IPropertyRendererRegistry, IService {
private renderers: Map<string, IPropertyRenderer> = new Map();
register(renderer: IPropertyRenderer): void {
if (this.renderers.has(renderer.id)) {
logger.warn(`Overwriting existing property renderer: ${renderer.id}`);
}
this.renderers.set(renderer.id, renderer);
logger.debug(`Registered property renderer: ${renderer.name} (${renderer.id})`);
}
unregister(rendererId: string): void {
if (this.renderers.delete(rendererId)) {
logger.debug(`Unregistered property renderer: ${rendererId}`);
}
}
findRenderer(value: any, context: PropertyContext): IPropertyRenderer | undefined {
const renderers = Array.from(this.renderers.values())
.sort((a, b) => (b.priority || 0) - (a.priority || 0));
for (const renderer of renderers) {
try {
if (renderer.canHandle(value, context)) {
return renderer;
}
} catch (error) {
logger.error(`Error in canHandle for renderer ${renderer.id}:`, error);
}
}
return undefined;
}
render(value: any, context: PropertyContext): React.ReactElement | null {
const renderer = this.findRenderer(value, context);
if (!renderer) {
logger.debug(`No renderer found for value type: ${typeof value}`);
return null;
}
try {
return renderer.render(value, context);
} catch (error) {
logger.error(`Error rendering with ${renderer.id}:`, error);
return React.createElement(
'span',
{ style: { color: '#f87171', fontStyle: 'italic' } },
'[Render Error]'
);
}
}
getAllRenderers(): IPropertyRenderer[] {
return Array.from(this.renderers.values());
}
hasRenderer(value: any, context: PropertyContext): boolean {
return this.findRenderer(value, context) !== undefined;
}
dispose(): void {
this.renderers.clear();
logger.debug('PropertyRendererRegistry disposed');
}
}

View File

@@ -31,6 +31,8 @@ export * from './Services/IDialog';
export * from './Services/INotification';
export * from './Services/IInspectorProvider';
export * from './Services/InspectorRegistry';
export * from './Services/IPropertyRenderer';
export * from './Services/PropertyRendererRegistry';
export * from './Module/IEventBus';
export * from './Module/ICommandRegistry';