import {type Edge, type Node} from '@xyflow/react' export const buildEL = (nodes: Node[], edges: Edge[]): string => { const nodeMap: Map = new Map() // 构建邻接列表和内图 const adjList = new Map() const inDegree = new Map() for (const node of nodes) { nodeMap.set(node.id, node) adjList.set(node.id, []) inDegree.set(node.id, 0) } for (const edge of edges) { adjList.get(edge.source)!.push(edge.target) inDegree.set(edge.target, inDegree.get(edge.target)! + 1) } // Compute levels (longest path from start) const levelMap = new Map() function computeLevel(nodeId: string): number { if (levelMap.has(nodeId)) return levelMap.get(nodeId)! const preds = edges.filter(e => e.target === nodeId).map(e => e.source) const level = preds.length === 0 ? 0 : Math.max(...preds.map(p => computeLevel(p))) + 1 levelMap.set(nodeId, level) return level } for (const node of nodes) computeLevel(node.id) // Group nodes by level const maxLevel = Math.max(...Array.from(levelMap.values())) const levels: string[][] = Array.from({length: maxLevel + 1}, () => []) for (const node of nodes) levels[levelMap.get(node.id)!].push(node.id) const covertNodeFromId = (id: string) => { let node = nodeMap.get(id)! return `node("${node.type}").bind("nodeId", ${node.id})` } // Build EL expression const expressions: string[] = [] for (let i = 0; i <= maxLevel; i++) { const nodesAtLevel = levels[i] if (nodesAtLevel.length === 0) continue // 识别从这个级别开始的串行链 const serialChains: string[] = [] for (const nodeId of nodesAtLevel) { let chain = [nodeId] let current = nodeId while (adjList.get(current)?.length === 1) { const next = adjList.get(current)![0] if (inDegree.get(next) === 1 && levelMap.get(next) === i + chain.length) { chain.push(next) current = next } else break } if (chain.length > 1) { serialChains.push(`THEN(${chain.map(id => covertNodeFromId(id)).join(',')})`) // Remove processed nodes from their levels for (let j = 1; j < chain.length; j++) { const level = levelMap.get(chain[j])! levels[level] = levels[level].filter(n => n !== chain[j]) } } else { serialChains.push(covertNodeFromId(nodeId)) } } // Combine chains or nodes at this level expressions.push(serialChains.length > 1 ? `WHEN(${serialChains.join(', ')})` : serialChains[0]) } return `THEN(${expressions.join(',')})` }