import { GraphConfigData } from "@logicflow/core"; import MyContext from "./MyContext"; import ELNode from "./type/ELNode"; import { ELType, GroupType } from "./type/ELType"; import Queue from "./type/Queue"; interface SingleNodeParseConfig { targetNode?: ELNode // 遇到这个节点就终止 } export default class MyParse { private logicFlow: GraphConfigData; private context: MyContext; constructor(logicFlow: GraphConfigData) { this.logicFlow = logicFlow; this.context = new MyContext(); this.context.init(logicFlow); } public parse(): ELNode { const startId = this.context.startId; const node = new ELNode(); node.id = startId; this.parseThenChain(node); return this.context.pop(); } /** * 解析一条链 * @param node 这条链的开始节点 * @param defaultData 链前面的一些节点,这些节点是并行的 * @returns */ private parseThenChain(node: ELNode, targetNode?: ELNode, defaultData?: ELNode, id: string = ""): ELNode { this.context.createStackEnv({ type: ELType.THEN, aliasId: id } as ELNode); if (defaultData) { this.context.push(defaultData) } this.parseSingleNode(node, { targetNode }); return this.context.quitStackEnv(); } /** * 分析单个的then节点 * * @param node 节点id * @param isStart 是否是then链的起点 * @returns */ private parseSingleNode(node: ELNode, config: SingleNodeParseConfig) { const id = node.id; const inNum = this.context.getSourceNum(node); const outNum = this.context.getEndNum(node); const newConfig: SingleNodeParseConfig = { targetNode: config.targetNode } if (this.context.isEnd(id)) { this.context.setStackEndPoint(node); return null; } if (config.targetNode && config.targetNode.id === node.id) { this.context.setStackEndPoint(node); return null; } // 虚拟节点不展示,其他节点入栈 if (!this.context.isStart(id)) this.context.push(node); //先分析特殊节点 if (ELType.IF === node.type) { const next = this.parseIF(this.context.pop()); return this.parseSingleNode(next, newConfig); } if (ELType.SWITCH === node.type) { const next = this.parseWhich(this.context.pop()); return this.parseSingleNode(next, newConfig); } //需要考虑与或非表达式作为if起点的情况 if (ELType.GROUP === node.type) { let next = this.parseGroup(this.context.pop()); if (node.groupType === GroupType.LOGIC && outNum > 0 && !this.context.isEnd(this.context.getEndList(node)[0].id)) { const logicNode = this.context.pop(); next = this.parseIF(logicNode); } return this.parseSingleNode(next, newConfig); } //普通节点 if (outNum === 1) { return this.parseSingleNode(this.context.getEndList(node)[0], newConfig); } //否则为when节点 const next = this.parseWhenChain(node); return this.parseSingleNode(next, newConfig); } /** * 将各个分支依次压入栈中 * * @param node 分支收束的节点 */ private parseBranch(node: ELNode): ELNode { const follows = this.context.getEndList(node); let next = this.getBranchEnd(node) as ELNode follows.forEach(start => { if (start.id == next.id) { // 不解析空链 return } this.parseThenChain(start, next, undefined, node.type === ELType.SWITCH ? start.comingEdgeText : ""); //如果是WITCH节点,可以再边上添加id说明 }) return next; } private parseIF(node: ELNode) { const typenode = new ELNode() typenode.type = ELType.IF; this.context.createStackEnv(typenode); if (node.type === ELType.IF) node.type = ELType.ID; this.context.push(node); // const ends = this.context.getEndList(node); // const outNum = ends.length; // 当if节点分支数为1,必须在末尾 // if (outNum == 1) { // let child: ELNode; // let end: ELNode; // try { // child = ends[0]; // end = this.context.endPoints[child.id][0]; // if (!this.context.isEnd(end.id)) throw new Error(); // } catch (err) { // throw new Error("IF 判断节点的分支数必须为2"); // } // this.context.push(child); // this.context.setStackEndPoint(end); // return this.context.quitStackEnv(); // } // if (outNum != 2) throw new Error("IF 判断节点的分支数必须为2"); const end = this.parseBranch(node); this.context.setStackEndPoint(end); return this.context.quitStackEnv(); } /** * 解析Switch节点,这里不应该使用parseBranch,每一个后继节点都应该看成单独的一条链 * @param node type为Switch的节点 * @returns */ private parseWhich(node: ELNode): ELNode { const follows = this.context.getEndList(node); const outNum = follows.length; if (outNum <= 1) throw new Error("WHICH 分支节点的分支数必须大于1"); // 下面开始正式的解析 this.context.createStackEnv(node); const next = this.parseBranch(node); this.context.setStackEndPoint(next); return this.context.quitStackEnv(); } /** * 不包含提前收束节点的并行解析方法 * @param follows 所有开始节点 * @param end 收束节点 * @returns */ private parseWhenBase(follows: ELNode[], end: ELNode, datas: ELNode[]): ELNode { this.context.createStackEnv({ type: ELType.WHEN } as ELNode); follows.forEach((s, index) => { if (s.id == end.id) { // 不解析空链 return } this.parseThenChain(s, end, datas[index]); }) this.context.quitStackEnv(); return this.context.pop(); } /** * 解析When节点 * * @param node when的开始节点 * @returns when的结束节点,便于继续分析 */ private parseWhenChain(node: ELNode): ELNode { this.context.createStackEnv({ type: ELType.WHEN } as ELNode); const ends = this.context.getEndList(node) const next = this.getBranchEnd(node) as ELNode const endNodes = this.getBranchEnd(node, next) as Record const endMap: Record = {} //开始节点对应的收束节点 const endData: Record = {} // 节点对应的数据 // 先将对象的键值对转换为数组并按照 number[] 的长度从小到大排序 const sortedEntries = Object.entries(endNodes) .sort(([, a], [, b]) => a.length - b.length); // 遍历排序后的数组 sortedEntries.forEach(([endId, value]) => { const endNode = this.context.getNodeById(endId) if (value.length == 1) return // 长度为1说明不是收束节点 const follows: any[] = [] value.forEach(index => { const node = ends[index] if (endMap[node.id]) { follows.push(endMap[node.id]) } else { follows.push(node.id) } }) value.forEach(index => { const node = ends[index] endMap[node.id] = endId }) const fs = Array.from(new Set(follows)).map(nodeId => this.context.getNodeById(nodeId)) const data = this.parseWhenBase(fs, endNode, fs.map(f => endData[f.id])) endData[endId] = data }); this.context.push(endData[next.id]) this.context.setStackEndPoint(next); return this.context.quitStackEnv(); } /** * 解析group * @param node */ private parseGroup(node: ELNode): ELNode { const ends = this.context.getEndList(node); let res: ELNode; let toEnd: boolean = true;//是否直接连接到end,即没有后继节点 ends.forEach(end => { if (end.comingEdgeText) { this.parseThenChain(end); const then = this.context.elStack.pop(); switch (end.comingEdgeText) { case "START": node.startNode = then.child[0]; break; case "BREAK": node.breakNode = then.child[0]; break; case "EXCEPTION": node.exceptionNode = then.child[0]; break; } } else { res = end; toEnd = false; } }) this.context.elStack.push(node); if (toEnd) { return new ELNode(this.context.endId) } return res!; } /** * 获取分支的结束节点 ,原理就是获取每个分支都能走到的节点 * 用于switch,if等的解析,endNode 指定结束节点 */ private getBranchEnd(node: ELNode, endNode?: ELNode): ELNode | Record { const endNodes = {} //分支起点的出度,用于判断何时结束 let outNum = this.context.getEndNum(node); // 获取后继节点id列表 const nodes_id = this.context.getEndList(node).map(n => n.id) // 节点的访问次数 const visited_count: Record = {} while (true) { for (let i = 0; i < nodes_id.length; i++) { const id = nodes_id[i] if (!id) continue const n = this.context.getNodeById(id) //更新访问次数 if (!visited_count[n.id]) visited_count[n.id] = 0 visited_count[n.id]++ //记录每个节点对应的开始节点,用于WHEN解析 if (!endNodes[n.id]) endNodes[n.id] = [] endNodes[n.id].push(i) //访问次数达标,返回该节点 if (visited_count[n.id] === outNum) { // 如果是选择节点并且有空链,就将next推后 if (node.type === ELType.SWITCH && this.context.getEndList(node).some(x => x.id === n.id)) { return this.getBranchEnd(n) } if (endNode) return endNodes return n } if (this.context.isEnd(n.id) || n.id === endNode?.id) {//结束节点不再向后或者到达指定的结束节点 nodes_id[i] = "" } else if (this.context.getEndNum(n) > 1) { //递归解析 nodes_id[i] = (this.getBranchEnd(n) as ELNode).id } else { // 修改为下一个节点 nodes_id[i] = this.context.getEndList(n)[0].id } } } } }