Просмотр исходного кода

fix: FlowNodeRegistry.extendChildRegistries extend nested, add document.isExtend (#269)

xiamidaxia 7 месяцев назад
Родитель
Сommit
755aaf2223

+ 116 - 0
packages/canvas-engine/document/__tests__/flow-node-registry.spec.ts

@@ -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');
+  });
+});

+ 13 - 0
packages/canvas-engine/document/src/flow-document.ts

@@ -433,10 +433,23 @@ export class FlowDocument<T = FlowDocumentJSON> implements Disposable {
           ...preRegistry?.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);
+  }
+
   /**
    * 导出数据,可以重载
    */

+ 30 - 0
packages/canvas-engine/document/src/typings/flow-node-register.ts

@@ -276,6 +276,10 @@ export interface FlowNodeRegistry<M extends FlowNodeMeta = FlowNodeMeta> {
     }
   ) => FlowNodeEntity;
 
+  /**
+   * 内部用于继承逻辑判断,不要使用
+   */
+  __extends__?: FlowNodeType[];
   /**
    * 扩展注册器
    */
@@ -283,17 +287,43 @@ export interface FlowNodeRegistry<M extends FlowNodeMeta = FlowNodeMeta> {
 }
 
 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(
     registry1: FlowNodeRegistry,
     registry2: FlowNodeRegistry,
     finalType: FlowNodeType
   ): FlowNodeRegistry {
+    const extendKeys = registry1.__extends__ ? registry1.__extends__.slice() : [];
+    if (registry1.type !== registry2.type) {
+      extendKeys.unshift(registry1.type);
+    }
     return {
       ...registry1,
       ...registry2,
+      extendChildRegistries: mergeChildRegistries(
+        registry1.extendChildRegistries,
+        registry2.extendChildRegistries
+      ),
       meta: { ...registry1.meta, ...registry2.meta },
       extend: undefined,
       type: finalType,
+      __extends__: extendKeys,
     };
   }