mirror of
https://gitee.com/ByteDance/flowgram.ai.git
synced 2025-07-07 17:43:29 +08:00
fix: FlowNodeRegistry.extendChildRegistries extend nested, add document.isExtend (#269)
This commit is contained in:
parent
bac29feb3a
commit
755aaf2223
@ -0,0 +1,116 @@
|
|||||||
|
import { beforeEach, describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
import { createDocumentContainer } from './flow-document-container.mock';
|
||||||
|
import { FlowDocument, FlowNodeRegistry } from '../src';
|
||||||
|
|
||||||
|
function registerNode(doc: FlowDocument, newRegistry: FlowNodeRegistry): FlowNodeRegistry {
|
||||||
|
doc.registerFlowNodes(newRegistry);
|
||||||
|
return doc.getNodeRegistry(newRegistry.type);
|
||||||
|
}
|
||||||
|
const mockRegistries: FlowNodeRegistry[] = [
|
||||||
|
{
|
||||||
|
type: 'dynamicSplit',
|
||||||
|
meta: {},
|
||||||
|
onCreate(node, json) {
|
||||||
|
return node.document.addInlineBlocks(node, json.blocks || []);
|
||||||
|
},
|
||||||
|
extendChildRegistries: [
|
||||||
|
{
|
||||||
|
type: 'blockIcon',
|
||||||
|
customKey: 'blockIcon_base',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'inlineBlocks',
|
||||||
|
customKey: 'inlineBlocks_base',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
onAdd: () => {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'a',
|
||||||
|
extend: 'dynamicSplit',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'b',
|
||||||
|
extend: 'a',
|
||||||
|
extendChildRegistries: [
|
||||||
|
{
|
||||||
|
type: 'blockIcon',
|
||||||
|
customKey: 'blockIcon_from_b',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'c',
|
||||||
|
extend: 'b',
|
||||||
|
extendChildRegistries: [
|
||||||
|
{
|
||||||
|
type: 'blockIcon',
|
||||||
|
customKey: 'blockIcon_from_c',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'inlineBlocks',
|
||||||
|
customKey: 'inlineBlocks_from_c',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
describe('flow-node-registry', () => {
|
||||||
|
let doc: FlowDocument;
|
||||||
|
beforeEach(() => {
|
||||||
|
const container = createDocumentContainer();
|
||||||
|
doc = container.get<FlowDocument>(FlowDocument);
|
||||||
|
doc.registerFlowNodes(...mockRegistries);
|
||||||
|
});
|
||||||
|
it('extend check', () => {
|
||||||
|
expect(doc.getNodeRegistry('dynamicSplit').__extends__).toEqual(undefined);
|
||||||
|
expect(doc.getNodeRegistry('a').__extends__).toEqual(['dynamicSplit']);
|
||||||
|
expect(doc.getNodeRegistry('b').__extends__).toEqual(['a', 'dynamicSplit']);
|
||||||
|
expect(doc.getNodeRegistry('c').__extends__).toEqual(['b', 'a', 'dynamicSplit']);
|
||||||
|
expect(doc.isExtend('dynamicSplit', 'dynamicSplit')).toBeFalsy();
|
||||||
|
expect(doc.isExtend('a', 'b')).toBeFalsy();
|
||||||
|
expect(doc.isExtend('a', 'dynamicSplit')).toBeTruthy();
|
||||||
|
expect(doc.isExtend('b', 'dynamicSplit')).toBeTruthy();
|
||||||
|
expect(doc.isExtend('b', 'a')).toBeTruthy();
|
||||||
|
expect(doc.isExtend('c', 'dynamicSplit')).toBeTruthy();
|
||||||
|
expect(doc.isExtend('c', 'b')).toBeTruthy();
|
||||||
|
expect(doc.isExtend('c', 'a')).toBeTruthy();
|
||||||
|
});
|
||||||
|
it('base extend', () => {
|
||||||
|
expect(doc.getNodeRegistry('a').onAdd).toBeTypeOf('function');
|
||||||
|
doc.addNode({
|
||||||
|
id: 'a',
|
||||||
|
type: 'a',
|
||||||
|
parent: doc.root,
|
||||||
|
});
|
||||||
|
expect(doc.toString()).toEqual(`root
|
||||||
|
|-- a
|
||||||
|
|---- $blockIcon$a
|
||||||
|
|---- $inlineBlocks$a`);
|
||||||
|
expect(doc.getNode('$blockIcon$a').getNodeRegistry().customKey).toBe('blockIcon_base');
|
||||||
|
});
|
||||||
|
it('extend nested', () => {
|
||||||
|
expect(doc.getNodeRegistry('b').onAdd).toBeTypeOf('function');
|
||||||
|
doc.addNode({
|
||||||
|
id: 'b',
|
||||||
|
type: 'b',
|
||||||
|
parent: doc.root,
|
||||||
|
});
|
||||||
|
doc.addNode({
|
||||||
|
id: 'c',
|
||||||
|
type: 'c',
|
||||||
|
parent: doc.root,
|
||||||
|
});
|
||||||
|
expect(doc.toString()).toEqual(`root
|
||||||
|
|-- b
|
||||||
|
|---- $blockIcon$b
|
||||||
|
|---- $inlineBlocks$b
|
||||||
|
|-- c
|
||||||
|
|---- $blockIcon$c
|
||||||
|
|---- $inlineBlocks$c`);
|
||||||
|
expect(doc.getNode('$blockIcon$b').getNodeRegistry().customKey).toBe('blockIcon_from_b');
|
||||||
|
expect(doc.getNode('$inlineBlocks$b').getNodeRegistry().customKey).toBe('inlineBlocks_base');
|
||||||
|
expect(doc.getNode('$blockIcon$c').getNodeRegistry().customKey).toBe('blockIcon_from_c');
|
||||||
|
expect(doc.getNode('$inlineBlocks$c').getNodeRegistry().customKey).toBe('inlineBlocks_from_c');
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -433,10 +433,23 @@ export class FlowDocument<T = FlowDocumentJSON> implements Disposable {
|
|||||||
...preRegistry?.meta,
|
...preRegistry?.meta,
|
||||||
...newRegistry?.meta,
|
...newRegistry?.meta,
|
||||||
},
|
},
|
||||||
|
extendChildRegistries: FlowNodeRegistry.mergeChildRegistries(
|
||||||
|
preRegistry?.extendChildRegistries,
|
||||||
|
newRegistry?.extendChildRegistries
|
||||||
|
),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check node extend
|
||||||
|
* @param currentType
|
||||||
|
* @param parentType
|
||||||
|
*/
|
||||||
|
isExtend(currentType: FlowNodeType, parentType: FlowNodeType): boolean {
|
||||||
|
return (this.getNodeRegistry(currentType).__extends__ || []).includes(parentType);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导出数据,可以重载
|
* 导出数据,可以重载
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -276,6 +276,10 @@ export interface FlowNodeRegistry<M extends FlowNodeMeta = FlowNodeMeta> {
|
|||||||
}
|
}
|
||||||
) => FlowNodeEntity;
|
) => FlowNodeEntity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内部用于继承逻辑判断,不要使用
|
||||||
|
*/
|
||||||
|
__extends__?: FlowNodeType[];
|
||||||
/**
|
/**
|
||||||
* 扩展注册器
|
* 扩展注册器
|
||||||
*/
|
*/
|
||||||
@ -283,17 +287,43 @@ export interface FlowNodeRegistry<M extends FlowNodeMeta = FlowNodeMeta> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export namespace FlowNodeRegistry {
|
export namespace FlowNodeRegistry {
|
||||||
|
export function mergeChildRegistries(
|
||||||
|
r1: FlowNodeRegistry[] = [],
|
||||||
|
r2: FlowNodeRegistry[] = []
|
||||||
|
): FlowNodeRegistry[] {
|
||||||
|
if (r1.length === 0 || r2.length === 0) {
|
||||||
|
return [...r1, ...r2];
|
||||||
|
}
|
||||||
|
const r1Filter = r1.map((r1Current) => {
|
||||||
|
const r2Current = r2.find((n) => n.type === r1Current.type);
|
||||||
|
if (r2Current) {
|
||||||
|
return merge(r1Current, r2Current, r1Current.type);
|
||||||
|
}
|
||||||
|
return r1Current;
|
||||||
|
});
|
||||||
|
const r2Filter = r2.filter((n) => !r1.some((r) => r.type === n.type));
|
||||||
|
return [...r1Filter, ...r2Filter];
|
||||||
|
}
|
||||||
export function merge(
|
export function merge(
|
||||||
registry1: FlowNodeRegistry,
|
registry1: FlowNodeRegistry,
|
||||||
registry2: FlowNodeRegistry,
|
registry2: FlowNodeRegistry,
|
||||||
finalType: FlowNodeType
|
finalType: FlowNodeType
|
||||||
): FlowNodeRegistry {
|
): FlowNodeRegistry {
|
||||||
|
const extendKeys = registry1.__extends__ ? registry1.__extends__.slice() : [];
|
||||||
|
if (registry1.type !== registry2.type) {
|
||||||
|
extendKeys.unshift(registry1.type);
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
...registry1,
|
...registry1,
|
||||||
...registry2,
|
...registry2,
|
||||||
|
extendChildRegistries: mergeChildRegistries(
|
||||||
|
registry1.extendChildRegistries,
|
||||||
|
registry2.extendChildRegistries
|
||||||
|
),
|
||||||
meta: { ...registry1.meta, ...registry2.meta },
|
meta: { ...registry1.meta, ...registry2.meta },
|
||||||
extend: undefined,
|
extend: undefined,
|
||||||
type: finalType,
|
type: finalType,
|
||||||
|
__extends__: extendKeys,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user