free-layout-scope-chain.ts 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. import { inject, optional, postConstruct } from 'inversify';
  2. import { Scope, ScopeChain } from '@flowgram.ai/variable-core';
  3. import { WorkflowNodeLinesData, WorkflowNodeMeta } from '@flowgram.ai/free-layout-core';
  4. import {
  5. FlowNodeEntity,
  6. FlowDocument,
  7. FlowVirtualTree,
  8. FlowNodeBaseType,
  9. } from '@flowgram.ai/document';
  10. import { EntityManager } from '@flowgram.ai/core';
  11. import { VariableLayoutConfig } from '../variable-layout-config';
  12. import { FlowNodeScope, FlowNodeScopeTypeEnum } from '../types';
  13. import { ScopeChainTransformService } from '../services/scope-chain-transform-service';
  14. import { GlobalScope } from '../scopes/global-scope';
  15. import { FlowNodeVariableData } from '../flow-node-variable-data';
  16. /**
  17. * 自由布局作用域链实现
  18. */
  19. export class FreeLayoutScopeChain extends ScopeChain {
  20. @inject(EntityManager) entityManager: EntityManager;
  21. @inject(FlowDocument)
  22. protected flowDocument: FlowDocument;
  23. @optional()
  24. @inject(VariableLayoutConfig)
  25. protected configs?: VariableLayoutConfig;
  26. @inject(ScopeChainTransformService)
  27. protected transformService: ScopeChainTransformService;
  28. get tree(): FlowVirtualTree<FlowNodeEntity> {
  29. return this.flowDocument.originTree;
  30. }
  31. @postConstruct()
  32. onInit() {
  33. this.toDispose.pushAll([
  34. // 线条发生变化时,会触发作用域链的更新
  35. this.entityManager.onEntityDataChange(({ entityDataType }) => {
  36. if (entityDataType === WorkflowNodeLinesData.type) {
  37. this.refreshAllChange();
  38. }
  39. }),
  40. // 树变化时候刷新作用域
  41. this.tree.onTreeChange(() => {
  42. this.refreshAllChange();
  43. }),
  44. ]);
  45. }
  46. // 获取同一层级所有输入节点
  47. protected getAllInputLayerNodes(curr: FlowNodeEntity): FlowNodeEntity[] {
  48. const currParent = this.getNodeParent(curr);
  49. return (curr.getData(WorkflowNodeLinesData)?.allInputNodes || []).filter(
  50. (_node) => this.getNodeParent(_node) === currParent
  51. );
  52. }
  53. // 获取同一层级所有输出节点
  54. protected getAllOutputLayerNodes(curr: FlowNodeEntity): FlowNodeEntity[] {
  55. const currParent = this.getNodeParent(curr);
  56. return (curr.getData(WorkflowNodeLinesData)?.allOutputNodes || []).filter(
  57. (_node) => this.getNodeParent(_node) === currParent
  58. );
  59. }
  60. getDeps(scope: FlowNodeScope): FlowNodeScope[] {
  61. const { node } = scope.meta || {};
  62. if (!node) {
  63. return this.transformService.transformDeps([], { scope });
  64. }
  65. const deps: FlowNodeScope[] = [];
  66. // 1. 找到依赖的节点
  67. let curr: FlowNodeEntity | undefined = node;
  68. while (curr) {
  69. const allInputNodes: FlowNodeEntity[] = this.getAllInputLayerNodes(curr);
  70. // 2. 获取所有依赖节点的 public 作用域
  71. deps.push(
  72. ...allInputNodes.map((_node) => _node.getData(FlowNodeVariableData).public).filter(Boolean)
  73. );
  74. // 父节点的 private 也可以访问
  75. const currVarData: FlowNodeVariableData = curr.getData(FlowNodeVariableData);
  76. if (currVarData?.private && scope !== currVarData.private) {
  77. deps.push(currVarData.private);
  78. }
  79. curr = this.getNodeParent(curr);
  80. }
  81. // If scope is GlobalScope, add globalScope to deps
  82. const globalScope = this.variableEngine.getScopeById(GlobalScope.ID);
  83. if (globalScope) {
  84. deps.unshift(globalScope);
  85. }
  86. const uniqDeps = Array.from(new Set(deps));
  87. return this.transformService.transformDeps(uniqDeps, { scope });
  88. }
  89. getCovers(scope: FlowNodeScope): FlowNodeScope[] {
  90. // If scope is GlobalScope, return all scopes except GlobalScope
  91. if (GlobalScope.is(scope)) {
  92. const scopes = this.variableEngine
  93. .getAllScopes({ sort: true })
  94. .filter((_scope) => !GlobalScope.is(_scope));
  95. return this.transformService.transformCovers(scopes, { scope });
  96. }
  97. const { node } = scope.meta || {};
  98. if (!node) {
  99. return this.transformService.transformCovers([], { scope });
  100. }
  101. const isPrivate = scope.meta.type === FlowNodeScopeTypeEnum.private;
  102. // 1. BFS 找到所有覆盖的节点
  103. const queue: FlowNodeEntity[] = [];
  104. if (isPrivate) {
  105. // private 只能覆盖其子节点
  106. queue.push(...this.getNodeChildren(node));
  107. } else {
  108. // 否则覆盖其所有输出线的节点
  109. queue.push(...(this.getAllOutputLayerNodes(node) || []));
  110. }
  111. // 2. 获取所有覆盖节点的 public、private 作用域
  112. const scopes: FlowNodeScope[] = [];
  113. while (queue.length) {
  114. const _node = queue.shift()!;
  115. const variableData: FlowNodeVariableData = _node.getData(FlowNodeVariableData);
  116. scopes.push(...variableData.allScopes);
  117. const children = _node && this.getNodeChildren(_node);
  118. if (children?.length) {
  119. queue.push(...children);
  120. }
  121. }
  122. // 3. 如果当前 scope 是 private,则当前节点的 public 也可覆盖
  123. const currentVariableData: FlowNodeVariableData = node.getData(FlowNodeVariableData);
  124. if (isPrivate && currentVariableData.public) {
  125. scopes.push(currentVariableData.public);
  126. }
  127. const uniqScopes = Array.from(new Set(scopes));
  128. return this.transformService.transformCovers(uniqScopes, { scope });
  129. }
  130. getNodeChildren(node: FlowNodeEntity): FlowNodeEntity[] {
  131. if (this.configs?.getNodeChildren) {
  132. return this.configs.getNodeChildren?.(node);
  133. }
  134. const nodeMeta = node.getNodeMeta<WorkflowNodeMeta>();
  135. const subCanvas = nodeMeta.subCanvas?.(node);
  136. if (subCanvas) {
  137. // 子画布本身不存在 children
  138. if (subCanvas.isCanvas) {
  139. return [];
  140. } else {
  141. return subCanvas.canvasNode.collapsedChildren;
  142. }
  143. }
  144. // 部分场景通过连线来表达父子关系,因此需要上层配置
  145. return this.tree.getChildren(node);
  146. }
  147. getNodeParent(node: FlowNodeEntity): FlowNodeEntity | undefined {
  148. // 部分场景通过连线来表达父子关系,因此需要上层配置
  149. if (this.configs?.getNodeParent) {
  150. return this.configs.getNodeParent(node);
  151. }
  152. let parent = node.document.originTree.getParent(node);
  153. // If currentParent is Group, get the parent of parent
  154. while (parent?.flowNodeType === FlowNodeBaseType.GROUP) {
  155. parent = parent.parent;
  156. }
  157. if (!parent) {
  158. return parent;
  159. }
  160. const nodeMeta = parent.getNodeMeta<WorkflowNodeMeta>();
  161. const subCanvas = nodeMeta.subCanvas?.(parent);
  162. if (subCanvas?.isCanvas) {
  163. // Get real parent node by subCanvas Configuration
  164. return subCanvas.parentNode;
  165. }
  166. return parent;
  167. }
  168. sortAll(): Scope[] {
  169. // 暂未实现
  170. console.warn('FreeLayoutScopeChain.sortAll is not implemented');
  171. return [];
  172. }
  173. }