import type { CanvasNode } from '@/types'; import type { VueFlowStore } from '@vue-flow/core'; export function useCanvasTraversal({ getIncomers, getOutgoers }: VueFlowStore) { function sortNodesByVerticalPosition(nodes: CanvasNode[]) { return nodes.sort((a, b) => a.position.y - b.position.y); } function getIncomingNodes(id: string) { return sortNodesByVerticalPosition(getIncomers(id)); } function getOutgoingNodes(id: string) { return sortNodesByVerticalPosition(getOutgoers(id)); } function getSiblingNodes(id: string) { const incomingSiblings = getIncomers(id).flatMap((incomingNode) => getOutgoers(incomingNode.id), ); const outgoingSiblings = getOutgoers(id).flatMap((outgoingNode) => getIncomers(outgoingNode.id), ); return sortNodesByVerticalPosition( [...incomingSiblings, ...outgoingSiblings].filter( (node, index, nodes) => nodes.findIndex((n) => n.id === node.id) === index, ), ); } function getDownstreamNodes(id: string, visited: string[] = []): CanvasNode[] { if (visited.includes(id)) { return []; } visited.push(id); const downstreamNodes = getOutgoers(id); return [ ...downstreamNodes, ...downstreamNodes.flatMap((node) => getDownstreamNodes(node.id, visited)), ].filter((node, index, nodes) => nodes.findIndex((n) => n.id === node.id) === index); } function getUpstreamNodes(id: string, visited: string[] = []): CanvasNode[] { if (visited.includes(id)) { return []; } visited.push(id); const upstreamNodes = getIncomers(id); return [ ...upstreamNodes, ...upstreamNodes.flatMap((node) => getUpstreamNodes(node.id, visited)), ].filter((node, index, nodes) => nodes.findIndex((n) => n.id === node.id) === index); } return { sortNodesByVerticalPosition, getIncomingNodes, getOutgoingNodes, getSiblingNodes, getDownstreamNodes, getUpstreamNodes, }; }