mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-20 19:32:15 +00:00
refactor(core): Reorganize n8n-core and enforce file-name casing (no-changelog) (#12667)
This commit is contained in:
committed by
GitHub
parent
e7f00bcb7f
commit
05858c2153
@@ -0,0 +1,114 @@
|
||||
import { NodeConnectionType, type INode } from 'n8n-workflow';
|
||||
|
||||
import type { GraphConnection } from './directed-graph';
|
||||
import { DirectedGraph } from './directed-graph';
|
||||
|
||||
function findSubgraphRecursive(
|
||||
graph: DirectedGraph,
|
||||
destinationNode: INode,
|
||||
current: INode,
|
||||
trigger: INode,
|
||||
newGraph: DirectedGraph,
|
||||
currentBranch: GraphConnection[],
|
||||
) {
|
||||
// If the current node is the chosen trigger keep this branch.
|
||||
if (current === trigger) {
|
||||
for (const connection of currentBranch) {
|
||||
newGraph.addNodes(connection.from, connection.to);
|
||||
newGraph.addConnection(connection);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const parentConnections = graph.getDirectParentConnections(current);
|
||||
|
||||
// If the current node has no parents, don’t keep this branch.
|
||||
if (parentConnections.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the current node is the destination node again, don’t keep this branch.
|
||||
const isCycleWithDestinationNode =
|
||||
current === destinationNode && currentBranch.some((c) => c.to === destinationNode);
|
||||
if (isCycleWithDestinationNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the current node was already visited, keep this branch.
|
||||
const isCycleWithCurrentNode = currentBranch.some((c) => c.to === current);
|
||||
if (isCycleWithCurrentNode) {
|
||||
// TODO: write function that adds nodes when adding connections
|
||||
for (const connection of currentBranch) {
|
||||
newGraph.addNodes(connection.from, connection.to);
|
||||
newGraph.addConnection(connection);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Recurse on each parent.
|
||||
for (const parentConnection of parentConnections) {
|
||||
// Skip parents that are connected via non-Main connection types. They are
|
||||
// only utility nodes for AI and are not part of the data or control flow
|
||||
// and can never lead too the trigger.
|
||||
if (parentConnection.type !== NodeConnectionType.Main) {
|
||||
continue;
|
||||
}
|
||||
|
||||
findSubgraphRecursive(graph, destinationNode, parentConnection.from, trigger, newGraph, [
|
||||
...currentBranch,
|
||||
parentConnection,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all nodes that can lead from the trigger to the destination node.
|
||||
*
|
||||
* The algorithm is:
|
||||
* Start with Destination Node
|
||||
*
|
||||
* 1. if the current node is the chosen trigger keep this branch
|
||||
* 2. if the current node has no parents, don’t keep this branch
|
||||
* 3. if the current node is the destination node again, don’t keep this
|
||||
* branch
|
||||
* 4. if the current node was already visited, keep this branch
|
||||
* 5. Recurse on each parent
|
||||
* 6. Re-add all connections that don't use the `Main` connections type.
|
||||
* Theses are used by nodes called root nodes and they are not part of the
|
||||
* dataflow in the graph they are utility nodes, like the AI model used in a
|
||||
* lang chain node.
|
||||
*/
|
||||
export function findSubgraph(options: {
|
||||
graph: DirectedGraph;
|
||||
destination: INode;
|
||||
trigger: INode;
|
||||
}): DirectedGraph {
|
||||
const graph = options.graph;
|
||||
const destination = options.destination;
|
||||
const trigger = options.trigger;
|
||||
const subgraph = new DirectedGraph();
|
||||
|
||||
findSubgraphRecursive(graph, destination, destination, trigger, subgraph, []);
|
||||
|
||||
// For each node in the subgraph, if it has parent connections of a type that
|
||||
// is not `Main` in the input graph, add the connections and the nodes
|
||||
// connected to it to the subgraph
|
||||
//
|
||||
// Without this all AI related workflows would not work when executed
|
||||
// partially, because all utility nodes would be missing.
|
||||
for (const node of subgraph.getNodes().values()) {
|
||||
const parentConnections = graph.getParentConnections(node);
|
||||
|
||||
for (const connection of parentConnections) {
|
||||
if (connection.type === NodeConnectionType.Main) {
|
||||
continue;
|
||||
}
|
||||
|
||||
subgraph.addNodes(connection.from, connection.to);
|
||||
subgraph.addConnection(connection);
|
||||
}
|
||||
}
|
||||
|
||||
return subgraph;
|
||||
}
|
||||
Reference in New Issue
Block a user