mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-13 01:21:58 +00:00
feat: 增加 plugin 的 autoInit 注册方式
chore(test): 增加 plugin 的单测
This commit is contained in:
parent
20f3a927ae
commit
4f9be73b61
@ -20,6 +20,7 @@ module.exports = {
|
||||
'!src/icons/**',
|
||||
'!src/locale/**',
|
||||
'!src/builtin-simulator/utils/**',
|
||||
'!src/plugin/sequencify.ts',
|
||||
'!src/document/node/exclusive-group.ts',
|
||||
'!**/node_modules/**',
|
||||
'!**/vendor/**',
|
||||
|
||||
@ -48,7 +48,7 @@ export class LiveEditing {
|
||||
const npm = node?.componentMeta?.npm;
|
||||
const selected =
|
||||
[npm?.package, npm?.componentName].filter((item) => !!item).join('-') || node?.componentMeta?.componentName || '';
|
||||
editor?.emit('designer.builinSimulator.LiveEditing', {
|
||||
editor?.emit('designer.builtinSimulator.liveEditing', {
|
||||
selected,
|
||||
});
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Editor } from '@ali/lowcode-editor-core';
|
||||
import { CompositeObject, ILowCodePlugin, ILowCodePluginConfig, ILowCodePluginManager, ILowCodePluginContext } from './plugin-types';
|
||||
import { ILowCodePlugin, ILowCodePluginConfig, ILowCodePluginManager, ILowCodePluginContext, LowCodeRegisterOptions } from './plugin-types';
|
||||
import { LowCodePlugin } from './plugin';
|
||||
import LowCodePluginContext from './plugin-context';
|
||||
import { getLogger, invariant } from '../utils';
|
||||
@ -22,19 +22,23 @@ export class LowCodePluginManager implements ILowCodePluginManager {
|
||||
return new LowCodePluginContext(this.editor, this);
|
||||
}
|
||||
|
||||
register(
|
||||
pluginConfig: (ctx: ILowCodePluginContext, options?: CompositeObject) => ILowCodePluginConfig,
|
||||
options?: CompositeObject,
|
||||
): void {
|
||||
async register(
|
||||
pluginConfigCreator: (ctx: ILowCodePluginContext, pluginOptions?: any) => ILowCodePluginConfig,
|
||||
pluginOptions?: any,
|
||||
options?: LowCodeRegisterOptions,
|
||||
): Promise<void> {
|
||||
const ctx = this._getLowCodePluginContext();
|
||||
const config = pluginConfig(ctx, options);
|
||||
const config = pluginConfigCreator(ctx, pluginOptions);
|
||||
invariant(config.name, `${config.name} required`, config);
|
||||
ctx.setLogger(config);
|
||||
invariant(!this.pluginsMap.has(config.name), `${config.name} already exists`, this.pluginsMap.get(config.name));
|
||||
const plugin = new LowCodePlugin(this, config, options);
|
||||
const plugin = new LowCodePlugin(this, config, pluginOptions);
|
||||
if (options?.autoInit) {
|
||||
await plugin.init();
|
||||
}
|
||||
this.plugins.push(plugin);
|
||||
this.pluginsMap.set(plugin.name, plugin);
|
||||
logger.log('plugin registered with config:', config, ', options:', options);
|
||||
logger.log('plugin registered with config:', config, ', options:', pluginOptions);
|
||||
}
|
||||
|
||||
get(pluginName: string): ILowCodePlugin | undefined {
|
||||
@ -51,7 +55,7 @@ export class LowCodePluginManager implements ILowCodePluginManager {
|
||||
|
||||
async delete(pluginName: string): Promise<boolean> {
|
||||
const idx = this.plugins.findIndex(plugin => plugin.name === pluginName);
|
||||
if (idx < -1) return false;
|
||||
if (idx === -1) return false;
|
||||
const plugin = this.plugins[idx];
|
||||
await plugin.destroy();
|
||||
|
||||
|
||||
@ -10,9 +10,9 @@ import {
|
||||
export interface ILowCodePluginConfig {
|
||||
name: string;
|
||||
dep?: string[]; // 依赖插件名
|
||||
init(): void;
|
||||
init?(): void;
|
||||
destroy?(): void;
|
||||
exports?(): CompositeObject;
|
||||
exports?(): any;
|
||||
}
|
||||
|
||||
export interface ILowCodePluginCore {
|
||||
@ -22,10 +22,10 @@ export interface ILowCodePluginCore {
|
||||
config: ILowCodePluginConfig;
|
||||
logger: Logger;
|
||||
on(event: string | symbol, listener: (...args: any[]) => void): any;
|
||||
off(event: string | symbol, listener: (...args: any[]) => void): any;
|
||||
emit(event: string | symbol, ...args: any[]): boolean;
|
||||
removeAllListeners(event?: string | symbol): this;
|
||||
init(): void;
|
||||
init(forceInit?: boolean): void;
|
||||
isInited(): boolean;
|
||||
destroy(): void;
|
||||
toProxy(): any;
|
||||
setDisabled(flag: boolean): void;
|
||||
@ -62,9 +62,10 @@ interface ILowCodePluginManagerPluginAccessor {
|
||||
|
||||
export interface ILowCodePluginManagerCore {
|
||||
register(
|
||||
pluginConfig: (ctx: ILowCodePluginContext, options?: CompositeObject) => ILowCodePluginConfig,
|
||||
pluginConfigCreator: (ctx: ILowCodePluginContext, pluginOptions?: any) => ILowCodePluginConfig,
|
||||
pluginOptions?: any,
|
||||
options?: CompositeObject,
|
||||
): void;
|
||||
): Promise<void>;
|
||||
get(pluginName: string): ILowCodePlugin | undefined;
|
||||
getAll(): ILowCodePlugin[];
|
||||
has(pluginName: string): boolean;
|
||||
@ -74,3 +75,7 @@ export interface ILowCodePluginManagerCore {
|
||||
}
|
||||
|
||||
export type ILowCodePluginManager = ILowCodePluginManagerCore & ILowCodePluginManagerPluginAccessor;
|
||||
|
||||
export type LowCodeRegisterOptions = {
|
||||
autoInit?: boolean;
|
||||
};
|
||||
|
||||
@ -2,8 +2,8 @@ import {
|
||||
ILowCodePlugin,
|
||||
ILowCodePluginConfig,
|
||||
ILowCodePluginManager,
|
||||
CompositeObject,
|
||||
} from '@ali/lowcode-types';
|
||||
} from './plugin-types';
|
||||
import { CompositeObject } from '@ali/lowcode-types';
|
||||
import { EventEmitter } from 'events';
|
||||
import { getLogger, Logger, invariant } from '../utils';
|
||||
|
||||
@ -50,30 +50,36 @@ export class LowCodePlugin implements ILowCodePlugin {
|
||||
}
|
||||
|
||||
on(event: string | symbol, listener: (...args: any[]) => void): any {
|
||||
return this.emitter.on(event, listener);
|
||||
this.emitter.on(event, listener);
|
||||
return () => {
|
||||
this.emitter.off(event, listener);
|
||||
};
|
||||
}
|
||||
|
||||
emit(event: string | symbol, ...args: any[]) {
|
||||
return this.emitter.emit(event, ...args);
|
||||
}
|
||||
|
||||
off(event: string | symbol, listener: (...args: any[]) => void): any {
|
||||
return this.emitter.off(event, listener);
|
||||
}
|
||||
|
||||
removeAllListeners(event: string | symbol): any {
|
||||
return this.emitter.removeAllListeners(event);
|
||||
}
|
||||
|
||||
async init() {
|
||||
isInited() {
|
||||
return this._inited;
|
||||
}
|
||||
|
||||
async init(forceInit?: boolean) {
|
||||
if (this._inited && !forceInit) return;
|
||||
this.logger.log('method init called');
|
||||
await this.config.init?.call(undefined);
|
||||
this._inited = true;
|
||||
}
|
||||
|
||||
async destroy() {
|
||||
if (!this._inited) return;
|
||||
this.logger.log('method destroy called');
|
||||
await this.config?.destroy?.call(undefined);
|
||||
this._inited = false;
|
||||
}
|
||||
|
||||
setDisabled(flag = true) {
|
||||
@ -93,7 +99,7 @@ export class LowCodePlugin implements ILowCodePlugin {
|
||||
});
|
||||
}
|
||||
|
||||
dispose() {
|
||||
return this.manager.delete(this.name);
|
||||
async dispose() {
|
||||
await this.manager.delete(this.name);
|
||||
}
|
||||
}
|
||||
|
||||
172
packages/designer/tests/plugin/plugin-manager.test.ts
Normal file
172
packages/designer/tests/plugin/plugin-manager.test.ts
Normal file
@ -0,0 +1,172 @@
|
||||
import '../fixtures/window';
|
||||
import { Editor } from '@ali/lowcode-editor-core';
|
||||
import { LowCodePluginManager } from '../../src/plugin/plugin-manager';
|
||||
import { ILowCodePluginContext, ILowCodePluginManager } from '../../src/plugin/plugin-types';
|
||||
|
||||
const editor = new Editor();
|
||||
|
||||
describe('plugin 测试', () => {
|
||||
let pluginManager: ILowCodePluginManager;
|
||||
beforeEach(() => {
|
||||
pluginManager = new LowCodePluginManager(editor).toProxy();
|
||||
});
|
||||
afterEach(() => {
|
||||
pluginManager.dispose();
|
||||
});
|
||||
|
||||
it('注册插件,插件参数生成函数能被调用,且能拿到正确的 ctx / options', () => {
|
||||
const mockFn = jest.fn();
|
||||
pluginManager.register((ctx: ILowCodePluginContext, options: any) => {
|
||||
mockFn(ctx, options);
|
||||
return {
|
||||
name: 'demo1',
|
||||
};
|
||||
}, { test: 1 });
|
||||
|
||||
const [expectedCtx, expectedOptions] = mockFn.mock.calls[0];
|
||||
expect(expectedCtx).toHaveProperty('designer');
|
||||
expect(expectedCtx).toHaveProperty('designerCabin');
|
||||
expect(expectedCtx).toHaveProperty('editor');
|
||||
expect(expectedCtx).toHaveProperty('hotkey');
|
||||
expect(expectedCtx).toHaveProperty('plugins');
|
||||
expect(expectedCtx).toHaveProperty('skeleton');
|
||||
expect(expectedCtx).toHaveProperty('logger');
|
||||
expect(expectedOptions).toEqual({ test: 1 });
|
||||
});
|
||||
|
||||
it('注册插件,调用插件 init 方法', async () => {
|
||||
const mockFn = jest.fn();
|
||||
pluginManager.register((ctx: ILowCodePluginContext, options: any) => {
|
||||
return {
|
||||
name: 'demo1',
|
||||
init: mockFn,
|
||||
exports() {
|
||||
return {
|
||||
x: 1,
|
||||
y: 2,
|
||||
}
|
||||
}
|
||||
};
|
||||
}, { test: 1 });
|
||||
await pluginManager.init();
|
||||
expect(pluginManager.size).toBe(1);
|
||||
expect(pluginManager.has('demo1')).toBeTruthy();
|
||||
expect(pluginManager.get('demo1')!.isInited()).toBeTruthy();
|
||||
expect(pluginManager.demo1).toBeTruthy();
|
||||
expect(pluginManager.demo1.x).toBe(1);
|
||||
expect(pluginManager.demo1.y).toBe(2);
|
||||
expect(mockFn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('注册插件,调用 setDisabled 方法', async () => {
|
||||
const mockFn = jest.fn();
|
||||
pluginManager.register((ctx: ILowCodePluginContext, options: any) => {
|
||||
return {
|
||||
name: 'demo1',
|
||||
init: mockFn,
|
||||
};
|
||||
}, { test: 1 });
|
||||
await pluginManager.init();
|
||||
expect(pluginManager.demo1).toBeTruthy();
|
||||
pluginManager.setDisabled('demo1', true);
|
||||
expect(pluginManager.demo1).toBeUndefined();
|
||||
});
|
||||
|
||||
it('删除插件,调用插件 destory 方法', async () => {
|
||||
const mockFn = jest.fn();
|
||||
pluginManager.register((ctx: ILowCodePluginContext, options: any) => {
|
||||
return {
|
||||
name: 'demo1',
|
||||
destroy: mockFn,
|
||||
};
|
||||
}, { test: 1 });
|
||||
await pluginManager.init();
|
||||
await pluginManager.delete('demo1');
|
||||
expect(mockFn).toHaveBeenCalled();
|
||||
await pluginManager.delete('non-existing');
|
||||
});
|
||||
|
||||
it('dep 依赖', async () => {
|
||||
const mockFn = jest.fn();
|
||||
pluginManager.register((ctx: ILowCodePluginContext, options: any) => {
|
||||
return {
|
||||
name: 'demo1',
|
||||
dep: ['demo2'],
|
||||
init: () => mockFn('demo1'),
|
||||
};
|
||||
});
|
||||
pluginManager.register((ctx: ILowCodePluginContext, options: any) => {
|
||||
return {
|
||||
name: 'demo2',
|
||||
init: () => mockFn('demo2'),
|
||||
};
|
||||
});
|
||||
|
||||
await pluginManager.init();
|
||||
expect(mockFn).toHaveBeenNthCalledWith(1, 'demo2');
|
||||
expect(mockFn).toHaveBeenNthCalledWith(2, 'demo1');
|
||||
});
|
||||
|
||||
it('autoInit 功能', async () => {
|
||||
const mockFn = jest.fn();
|
||||
await pluginManager.register((ctx: ILowCodePluginContext, options: any) => {
|
||||
return {
|
||||
name: 'demo1',
|
||||
init: mockFn,
|
||||
};
|
||||
}, { test: 1 }, { autoInit: true });
|
||||
expect(mockFn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('插件不会重复 init,除非强制重新 init', async () => {
|
||||
const mockFn = jest.fn();
|
||||
pluginManager.register((ctx: ILowCodePluginContext, options: any) => {
|
||||
return {
|
||||
name: 'demo1',
|
||||
init: mockFn,
|
||||
};
|
||||
}, { test: 1 });
|
||||
await pluginManager.init();
|
||||
expect(mockFn).toHaveBeenCalledTimes(1);
|
||||
|
||||
pluginManager.get('demo1')!.init();
|
||||
expect(mockFn).toHaveBeenCalledTimes(1);
|
||||
|
||||
pluginManager.get('demo1')!.init(true);
|
||||
expect(mockFn).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('内部事件机制', async () => {
|
||||
const mockFn = jest.fn();
|
||||
pluginManager.register((ctx: ILowCodePluginContext, options: any) => {
|
||||
return {
|
||||
name: 'demo1',
|
||||
};
|
||||
}, { test: 1 });
|
||||
await pluginManager.init();
|
||||
const plugin = pluginManager.get('demo1')!;
|
||||
|
||||
plugin.on('haha', mockFn);
|
||||
plugin.emit('haha', 1, 2, 3);
|
||||
|
||||
expect(mockFn).toHaveBeenCalledTimes(1);
|
||||
expect(mockFn).toHaveBeenCalledWith(1, 2, 3);
|
||||
|
||||
plugin.removeAllListeners('haha');
|
||||
plugin.emit('haha', 1, 2, 3);
|
||||
expect(mockFn).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('dispose 方法', async () => {
|
||||
pluginManager.register((ctx: ILowCodePluginContext, options: any) => {
|
||||
return {
|
||||
name: 'demo1',
|
||||
};
|
||||
}, { test: 1 });
|
||||
await pluginManager.init();
|
||||
const plugin = pluginManager.get('demo1')!;
|
||||
await plugin.dispose();
|
||||
|
||||
expect(pluginManager.has('demo1')).toBeFalsy();
|
||||
})
|
||||
});
|
||||
@ -20,7 +20,7 @@
|
||||
"dependencies": {
|
||||
"@ali/lowcode-designer": "^1.0.31",
|
||||
"@ali/lowcode-editor-core": "^1.0.31",
|
||||
"@ali/lowcode-editor-setters": "^1.0.22",
|
||||
"@ali/lowcode-editor-setters": "1.0.29",
|
||||
"@ali/lowcode-editor-skeleton": "^1.0.31",
|
||||
"@ali/lowcode-plugin-designer": "^1.0.31",
|
||||
"@ali/lowcode-plugin-outline-pane": "^1.0.31",
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
"@ali/lowcode-plugin-designer": "^1.0.31",
|
||||
"@ali/lowcode-plugin-outline-pane": "^1.0.31",
|
||||
"@ali/lowcode-utils": "^1.0.31",
|
||||
"@ali/lowcode-editor-setters": "1.0.29",
|
||||
"@ali/ve-i18n-util": "^2.0.0",
|
||||
"@ali/ve-icons": "^4.1.9",
|
||||
"@ali/ve-less-variables": "2.0.3",
|
||||
|
||||
@ -17,4 +17,3 @@ export * from './node';
|
||||
export * from './transform-stage';
|
||||
export * from './code-intermediate';
|
||||
export * from './code-result';
|
||||
export * from './plugin';
|
||||
|
||||
@ -180,8 +180,8 @@ export interface Callbacks {
|
||||
onMouseDownHook?: (e: MouseEvent, currentNode: any) => any;
|
||||
onDblClickHook?: (e: MouseEvent, currentNode: any) => any;
|
||||
onClickHook?: (e: MouseEvent, currentNode: any) => any;
|
||||
onLocateHook?: (e: any, currentNode: any) => any;
|
||||
onAcceptHook?: (currentNode: any, locationData: any) => any;
|
||||
// onLocateHook?: (e: any, currentNode: any) => any;
|
||||
// onAcceptHook?: (currentNode: any, locationData: any) => any;
|
||||
onMoveHook?: (currentNode: any) => boolean; // thinkof 限制性拖拽
|
||||
onChildMoveHook?: (childNode: any, currentNode: any) => boolean;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user