refactor(core): Reorganize n8n-core and enforce file-name casing (no-changelog) (#12667)

This commit is contained in:
कारतोफ्फेलस्क्रिप्ट™
2025-01-17 15:17:25 +01:00
committed by GitHub
parent e7f00bcb7f
commit 05858c2153
132 changed files with 459 additions and 441 deletions
@@ -0,0 +1,219 @@
import * as a from 'assert/strict';
import {
NodeConnectionType,
type IExecuteData,
type INode,
type INodeExecutionData,
type IPinData,
type IRunData,
type ISourceData,
type ITaskDataConnectionsSource,
type IWaitingForExecution,
type IWaitingForExecutionSource,
} from 'n8n-workflow';
import type { DirectedGraph } from './directed-graph';
import { getIncomingDataFromAnyRun } from './get-incoming-data';
import { getSourceDataGroups } from './get-source-data-groups';
export function addWaitingExecution(
waitingExecution: IWaitingForExecution,
nodeName: string,
runIndex: number,
inputType: NodeConnectionType,
inputIndex: number,
executionData: INodeExecutionData[] | null,
) {
const waitingExecutionObject = waitingExecution[nodeName] ?? {};
const taskDataConnections = waitingExecutionObject[runIndex] ?? {};
const executionDataList = taskDataConnections[inputType] ?? [];
executionDataList[inputIndex] = executionData;
taskDataConnections[inputType] = executionDataList;
waitingExecutionObject[runIndex] = taskDataConnections;
waitingExecution[nodeName] = waitingExecutionObject;
}
export function addWaitingExecutionSource(
waitingExecutionSource: IWaitingForExecutionSource,
nodeName: string,
runIndex: number,
inputType: NodeConnectionType,
inputIndex: number,
sourceData: ISourceData | null,
) {
const waitingExecutionSourceObject = waitingExecutionSource[nodeName] ?? {};
const taskDataConnectionsSource = waitingExecutionSourceObject[runIndex] ?? {};
const sourceDataList = taskDataConnectionsSource[inputType] ?? [];
sourceDataList[inputIndex] = sourceData;
taskDataConnectionsSource[inputType] = sourceDataList;
waitingExecutionSourceObject[runIndex] = taskDataConnectionsSource;
waitingExecutionSource[nodeName] = waitingExecutionSourceObject;
}
/**
* Recreates the node execution stack, waiting executions and waiting
* execution sources from a directed graph, start nodes, the destination node,
* run and pinned data.
*
* This function aims to be able to recreate the internal state of the
* WorkflowExecute class at any point of time during an execution based on the
* data that is already available. Specifically it will recreate the
* `WorkflowExecute.runExecutionData.executionData` properties.
*
* This allows "restarting" an execution and having it only execute what's
* necessary to be able to execute the destination node accurately, e.g. as
* close as possible to what would happen in a production execution.
*/
export function recreateNodeExecutionStack(
graph: DirectedGraph,
startNodes: Set<INode>,
runData: IRunData,
pinData: IPinData,
): {
nodeExecutionStack: IExecuteData[];
waitingExecution: IWaitingForExecution;
waitingExecutionSource: IWaitingForExecutionSource;
} {
// Validate invariants.
// The graph needs to be free of disabled nodes. If it's not it hasn't been
// passed through findSubgraph.
for (const node of graph.getNodes().values()) {
a.notEqual(
node.disabled,
true,
`Graph contains disabled nodes. This is not supported. Make sure to pass the graph through "findSubgraph" before calling "recreateNodeExecutionStack". The node in question is "${node.name}"`,
);
}
// Initialize the nodeExecutionStack and waitingExecution with
// the data from runData
const nodeExecutionStack: IExecuteData[] = [];
const waitingExecution: IWaitingForExecution = {};
const waitingExecutionSource: IWaitingForExecutionSource = {};
for (const startNode of startNodes) {
const incomingStartNodeConnections = graph
.getDirectParentConnections(startNode)
.filter((c) => c.type === NodeConnectionType.Main);
let incomingData: INodeExecutionData[][] = [];
let incomingSourceData: ITaskDataConnectionsSource | null = null;
if (incomingStartNodeConnections.length === 0) {
incomingData.push([{ json: {} }]);
const executeData: IExecuteData = {
node: startNode,
data: { main: incomingData },
source: incomingSourceData,
};
nodeExecutionStack.push(executeData);
} else {
const sourceDataSets = getSourceDataGroups(graph, startNode, runData, pinData);
for (const sourceData of sourceDataSets) {
if (sourceData.complete) {
// All incoming connections have data, so let's put the node on the
// stack!
incomingData = [];
incomingSourceData = { main: [] };
for (const incomingConnection of sourceData.connections) {
let runIndex = 0;
const sourceNode = incomingConnection.from;
if (pinData[sourceNode.name]) {
incomingData.push(pinData[sourceNode.name]);
} else {
a.ok(
runData[sourceNode.name],
`Start node(${incomingConnection.to.name}) has an incoming connection with no run or pinned data. This is not supported. The connection in question is "${sourceNode.name}->${startNode.name}". Are you sure the start nodes come from the "findStartNodes" function?`,
);
const nodeIncomingData = getIncomingDataFromAnyRun(
runData,
sourceNode.name,
incomingConnection.type,
incomingConnection.outputIndex,
);
if (nodeIncomingData) {
runIndex = nodeIncomingData.runIndex;
incomingData.push(nodeIncomingData.data);
}
}
incomingSourceData.main.push({
previousNode: incomingConnection.from.name,
previousNodeOutput: incomingConnection.outputIndex,
previousNodeRun: runIndex,
});
}
const executeData: IExecuteData = {
node: startNode,
data: { main: incomingData },
source: incomingSourceData,
};
nodeExecutionStack.push(executeData);
} else {
const nodeName = startNode.name;
const nextRunIndex = waitingExecution[nodeName]
? Object.keys(waitingExecution[nodeName]).length
: 0;
for (const incomingConnection of sourceData.connections) {
const sourceNode = incomingConnection.from;
const maybeNodeIncomingData = getIncomingDataFromAnyRun(
runData,
sourceNode.name,
incomingConnection.type,
incomingConnection.outputIndex,
);
const nodeIncomingData = maybeNodeIncomingData?.data ?? null;
if (nodeIncomingData) {
addWaitingExecution(
waitingExecution,
nodeName,
nextRunIndex,
incomingConnection.type,
incomingConnection.inputIndex,
nodeIncomingData,
);
addWaitingExecutionSource(
waitingExecutionSource,
nodeName,
nextRunIndex,
incomingConnection.type,
incomingConnection.inputIndex,
nodeIncomingData
? {
previousNode: incomingConnection.from.name,
previousNodeRun: nextRunIndex,
previousNodeOutput: incomingConnection.outputIndex,
}
: null,
);
}
}
}
}
}
}
return {
nodeExecutionStack,
waitingExecution,
waitingExecutionSource,
};
}