refactor: Migrate NodeConnectionType to const object type (no-changelog) (#14078)

Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
This commit is contained in:
Alex Grozav
2025-03-21 14:01:26 +02:00
committed by GitHub
co-authored by कारतोफ्फेलस्क्रिप्ट™
parent 7e8179b848
commit 8215e0b59f
703 changed files with 3102 additions and 3016 deletions
@@ -14,7 +14,7 @@ import type {
INodeTypes,
ICredentialDataDecryptedObject,
} from 'n8n-workflow';
import { ApplicationError, ExpressionError, NodeConnectionType } from 'n8n-workflow';
import { ApplicationError, ExpressionError, NodeConnectionTypes } from 'n8n-workflow';
import { describeCommonTests } from './shared-tests';
import { ExecuteContext } from '../execute-context';
@@ -92,7 +92,7 @@ describe('ExecuteContext', () => {
describe('getInputData', () => {
const inputIndex = 0;
const connectionType = NodeConnectionType.Main;
const connectionType = NodeConnectionTypes.Main;
afterEach(() => {
inputData[connectionType] = [[{ json: { test: 'data' } }]];
@@ -105,10 +105,8 @@ describe('ExecuteContext', () => {
});
it('should return an empty array if the input name does not exist', () => {
const connectionType = 'nonExistent';
expect(executeContext.getInputData(inputIndex, connectionType as NodeConnectionType)).toEqual(
[],
);
const connectionType = 'nonExistent' as typeof NodeConnectionTypes.Main;
expect(executeContext.getInputData(inputIndex, connectionType)).toEqual([]);
});
it('should throw an error if the input index is out of range', () => {
@@ -14,7 +14,7 @@ import type {
INodeTypes,
ICredentialDataDecryptedObject,
} from 'n8n-workflow';
import { ApplicationError, NodeConnectionType } from 'n8n-workflow';
import { ApplicationError, NodeConnectionTypes } from 'n8n-workflow';
import { describeCommonTests } from './shared-tests';
import { ExecuteSingleContext } from '../execute-single-context';
@@ -91,7 +91,7 @@ describe('ExecuteSingleContext', () => {
describe('getInputData', () => {
const inputIndex = 0;
const connectionType = NodeConnectionType.Main;
const connectionType = NodeConnectionTypes.Main;
afterEach(() => {
inputData[connectionType] = [[{ json: { test: 'data' } }]];
@@ -104,12 +104,10 @@ describe('ExecuteSingleContext', () => {
});
it('should return an empty object if the input name does not exist', () => {
const connectionType = 'nonExistent';
const connectionType = 'nonExistent' as typeof NodeConnectionTypes.Main;
const expectedData = { json: {} };
expect(
executeSingleContext.getInputData(inputIndex, connectionType as NodeConnectionType),
).toEqual(expectedData);
expect(executeSingleContext.getInputData(inputIndex, connectionType)).toEqual(expectedData);
});
it('should throw an error if the input index is out of range', () => {
@@ -10,7 +10,7 @@ import type {
Workflow,
WorkflowExecuteMode,
} from 'n8n-workflow';
import { NodeConnectionType } from 'n8n-workflow';
import { NodeConnectionTypes } from 'n8n-workflow';
import { InstanceSettings } from '@/instance-settings';
@@ -178,27 +178,27 @@ describe('NodeExecutionContext', () => {
describe('getNodeInputs', () => {
it('should return static inputs array when inputs is an array', () => {
nodeType.description.inputs = [NodeConnectionType.Main, NodeConnectionType.AiLanguageModel];
nodeType.description.inputs = [NodeConnectionTypes.Main, NodeConnectionTypes.AiLanguageModel];
const result = testContext.getNodeInputs();
expect(result).toEqual([
{ type: NodeConnectionType.Main },
{ type: NodeConnectionType.AiLanguageModel },
{ type: NodeConnectionTypes.Main },
{ type: NodeConnectionTypes.AiLanguageModel },
]);
});
it('should return input objects when inputs contains configurations', () => {
nodeType.description.inputs = [
{ type: NodeConnectionType.Main },
{ type: NodeConnectionType.AiLanguageModel, required: true },
{ type: NodeConnectionTypes.Main },
{ type: NodeConnectionTypes.AiLanguageModel, required: true },
];
const result = testContext.getNodeInputs();
expect(result).toEqual([
{ type: NodeConnectionType.Main },
{ type: NodeConnectionType.AiLanguageModel, required: true },
{ type: NodeConnectionTypes.Main },
{ type: NodeConnectionTypes.AiLanguageModel, required: true },
]);
});
@@ -206,15 +206,15 @@ describe('NodeExecutionContext', () => {
const inputsExpressions = '={{ ["main", "ai_languageModel"] }}';
nodeType.description.inputs = inputsExpressions;
expression.getSimpleParameterValue.mockReturnValue([
NodeConnectionType.Main,
NodeConnectionType.AiLanguageModel,
NodeConnectionTypes.Main,
NodeConnectionTypes.AiLanguageModel,
]);
const result = testContext.getNodeInputs();
expect(result).toEqual([
{ type: NodeConnectionType.Main },
{ type: NodeConnectionType.AiLanguageModel },
{ type: NodeConnectionTypes.Main },
{ type: NodeConnectionTypes.AiLanguageModel },
]);
expect(expression.getSimpleParameterValue).toHaveBeenCalledWith(
node,
@@ -227,27 +227,30 @@ describe('NodeExecutionContext', () => {
describe('getNodeOutputs', () => {
it('should return static outputs array when outputs is an array', () => {
nodeType.description.outputs = [NodeConnectionType.Main, NodeConnectionType.AiLanguageModel];
const result = testContext.getNodeOutputs();
expect(result).toEqual([
{ type: NodeConnectionType.Main },
{ type: NodeConnectionType.AiLanguageModel },
]);
});
it('should return output objects when outputs contains configurations', () => {
nodeType.description.outputs = [
{ type: NodeConnectionType.Main },
{ type: NodeConnectionType.AiLanguageModel, required: true },
NodeConnectionTypes.Main,
NodeConnectionTypes.AiLanguageModel,
];
const result = testContext.getNodeOutputs();
expect(result).toEqual([
{ type: NodeConnectionType.Main },
{ type: NodeConnectionType.AiLanguageModel, required: true },
{ type: NodeConnectionTypes.Main },
{ type: NodeConnectionTypes.AiLanguageModel },
]);
});
it('should return output objects when outputs contains configurations', () => {
nodeType.description.outputs = [
{ type: NodeConnectionTypes.Main },
{ type: NodeConnectionTypes.AiLanguageModel, required: true },
];
const result = testContext.getNodeOutputs();
expect(result).toEqual([
{ type: NodeConnectionTypes.Main },
{ type: NodeConnectionTypes.AiLanguageModel, required: true },
]);
});
@@ -255,15 +258,15 @@ describe('NodeExecutionContext', () => {
const outputsExpressions = '={{ ["main", "ai_languageModel"] }}';
nodeType.description.outputs = outputsExpressions;
expression.getSimpleParameterValue.mockReturnValue([
NodeConnectionType.Main,
NodeConnectionType.AiLanguageModel,
NodeConnectionTypes.Main,
NodeConnectionTypes.AiLanguageModel,
]);
const result = testContext.getNodeOutputs();
expect(result).toEqual([
{ type: NodeConnectionType.Main },
{ type: NodeConnectionType.AiLanguageModel },
{ type: NodeConnectionTypes.Main },
{ type: NodeConnectionTypes.AiLanguageModel },
]);
expect(expression.getSimpleParameterValue).toHaveBeenCalledWith(
node,
@@ -276,13 +279,13 @@ describe('NodeExecutionContext', () => {
it('should add error output when node has continueOnFail error handling', () => {
const nodeWithError = mock<INode>({ onError: 'continueErrorOutput' });
const contextWithError = new TestContext(workflow, nodeWithError, additionalData, mode);
nodeType.description.outputs = [NodeConnectionType.Main];
nodeType.description.outputs = [NodeConnectionTypes.Main];
const result = contextWithError.getNodeOutputs();
expect(result).toEqual([
{ type: NodeConnectionType.Main, displayName: 'Success' },
{ type: NodeConnectionType.Main, displayName: 'Error', category: 'error' },
{ type: NodeConnectionTypes.Main, displayName: 'Success' },
{ type: NodeConnectionTypes.Main, displayName: 'Error', category: 'error' },
]);
});
});
@@ -299,10 +302,10 @@ describe('NodeExecutionContext', () => {
return null;
});
const result = testContext.getConnectedNodes(NodeConnectionType.Main);
const result = testContext.getConnectedNodes(NodeConnectionTypes.Main);
expect(result).toEqual([node1, node2]);
expect(workflow.getParentNodes).toHaveBeenCalledWith(node.name, NodeConnectionType.Main, 1);
expect(workflow.getParentNodes).toHaveBeenCalledWith(node.name, NodeConnectionTypes.Main, 1);
});
it('should filter out disabled nodes', () => {
@@ -316,7 +319,7 @@ describe('NodeExecutionContext', () => {
return null;
});
const result = testContext.getConnectedNodes(NodeConnectionType.Main);
const result = testContext.getConnectedNodes(NodeConnectionTypes.Main);
expect(result).toEqual([node1]);
});
@@ -330,7 +333,7 @@ describe('NodeExecutionContext', () => {
return null;
});
const result = testContext.getConnectedNodes(NodeConnectionType.Main);
const result = testContext.getConnectedNodes(NodeConnectionTypes.Main);
expect(result).toEqual([node1]);
});
@@ -13,8 +13,9 @@ import type {
INodeType,
INodeTypes,
ICredentialDataDecryptedObject,
NodeConnectionType,
} from 'n8n-workflow';
import { ApplicationError, NodeConnectionType } from 'n8n-workflow';
import { ApplicationError, NodeConnectionTypes } from 'n8n-workflow';
import { describeCommonTests } from './shared-tests';
import { SupplyDataContext } from '../supply-data-context';
@@ -58,7 +59,7 @@ describe('SupplyDataContext', () => {
resultData: { runData: {} },
});
const connectionInputData: INodeExecutionData[] = [];
const connectionType = NodeConnectionType.Main;
const connectionType = NodeConnectionTypes.Main;
const inputData: ITaskDataConnections = { [connectionType]: [[{ json: { test: 'data' } }]] };
const executeData = mock<IExecuteData>();
const runIndex = 0;
@@ -20,11 +20,12 @@ import type {
IWorkflowDataProxyData,
ISourceData,
AiEvent,
NodeConnectionType,
} from 'n8n-workflow';
import {
ApplicationError,
NodeHelpers,
NodeConnectionType,
NodeConnectionTypes,
WAIT_INDEFINITELY,
WorkflowDataProxy,
} from 'n8n-workflow';
@@ -159,7 +160,7 @@ export class BaseExecuteContext extends NodeExecutionContext {
return allItems;
}
getInputSourceData(inputIndex = 0, connectionType = NodeConnectionType.Main): ISourceData {
getInputSourceData(inputIndex = 0, connectionType = NodeConnectionTypes.Main): ISourceData {
if (this.executeData?.source === null) {
// Should never happen as n8n sets it automatically
throw new ApplicationError('Source data is missing');
@@ -20,7 +20,7 @@ import {
ApplicationError,
createDeferredPromise,
createEnvProviderState,
NodeConnectionType,
NodeConnectionTypes,
} from 'n8n-workflow';
import { BaseExecuteContext } from './base-execute-context';
@@ -173,7 +173,7 @@ export class ExecuteContext extends BaseExecuteContext implements IExecuteFuncti
);
}
getInputData(inputIndex = 0, connectionType = NodeConnectionType.Main) {
getInputData(inputIndex = 0, connectionType = NodeConnectionTypes.Main) {
if (!this.inputData.hasOwnProperty(connectionType)) {
// Return empty array because else it would throw error when nothing is connected to input
return [];
@@ -11,7 +11,7 @@ import type {
ITaskDataConnections,
IExecuteData,
} from 'n8n-workflow';
import { ApplicationError, createDeferredPromise, NodeConnectionType } from 'n8n-workflow';
import { ApplicationError, createDeferredPromise, NodeConnectionTypes } from 'n8n-workflow';
import { BaseExecuteContext } from './base-execute-context';
import {
@@ -76,7 +76,7 @@ export class ExecuteSingleContext extends BaseExecuteContext implements IExecute
return super.evaluateExpression(expression, itemIndex);
}
getInputData(inputIndex = 0, connectionType = NodeConnectionType.Main) {
getInputData(inputIndex = 0, connectionType = NodeConnectionTypes.Main) {
if (!this.inputData.hasOwnProperty(connectionType)) {
// Return empty array because else it would throw error when nothing is connected to input
return { json: {} };
@@ -15,8 +15,9 @@ import type {
IWorkflowExecuteAdditionalData,
Workflow,
WorkflowExecuteMode,
NodeConnectionType,
} from 'n8n-workflow';
import { createDeferredPromise, NodeConnectionType } from 'n8n-workflow';
import { createDeferredPromise, NodeConnectionTypes } from 'n8n-workflow';
import { BaseExecuteContext } from './base-execute-context';
import {
@@ -126,7 +127,7 @@ export class SupplyDataContext extends BaseExecuteContext implements ISupplyData
this.closeFunctions,
this.abortSignal,
);
context.addInputData(NodeConnectionType.AiTool, replacements.inputData);
context.addInputData(NodeConnectionTypes.AiTool, replacements.inputData);
return context;
}
@@ -11,7 +11,7 @@ import type {
INodeType,
INodeTypes,
} from 'n8n-workflow';
import { NodeConnectionType, NodeOperationError } from 'n8n-workflow';
import { NodeConnectionTypes, NodeOperationError } from 'n8n-workflow';
import { ExecuteContext } from '../../execute-context';
@@ -67,16 +67,16 @@ describe('getInputConnectionData', () => {
});
describe.each([
NodeConnectionType.AiAgent,
NodeConnectionType.AiChain,
NodeConnectionType.AiDocument,
NodeConnectionType.AiEmbedding,
NodeConnectionType.AiLanguageModel,
NodeConnectionType.AiMemory,
NodeConnectionType.AiOutputParser,
NodeConnectionType.AiRetriever,
NodeConnectionType.AiTextSplitter,
NodeConnectionType.AiVectorStore,
NodeConnectionTypes.AiAgent,
NodeConnectionTypes.AiChain,
NodeConnectionTypes.AiDocument,
NodeConnectionTypes.AiEmbedding,
NodeConnectionTypes.AiLanguageModel,
NodeConnectionTypes.AiMemory,
NodeConnectionTypes.AiOutputParser,
NodeConnectionTypes.AiRetriever,
NodeConnectionTypes.AiTextSplitter,
NodeConnectionTypes.AiVectorStore,
] as const)('%s', (connectionType) => {
const response = mock();
const node = mock<INode>({
@@ -231,7 +231,7 @@ describe('getInputConnectionData', () => {
});
});
describe(NodeConnectionType.AiTool, () => {
describe(NodeConnectionTypes.AiTool, () => {
const mockTool = mock<Tool>();
const toolNode = mock<INode>({
name: 'Test Tool',
@@ -252,7 +252,7 @@ describe('getInputConnectionData', () => {
.calledWith(toolNode.type, expect.anything())
.mockReturnValue(toolNodeType);
workflow.getParentNodes
.calledWith(agentNode.name, NodeConnectionType.AiTool)
.calledWith(agentNode.name, NodeConnectionTypes.AiTool)
.mockReturnValue([toolNode.name]);
workflow.getNode.calledWith(toolNode.name).mockReturnValue(toolNode);
workflow.getNode.calledWith(secondToolNode.name).mockReturnValue(secondToolNode);
@@ -261,13 +261,13 @@ describe('getInputConnectionData', () => {
it('should return empty array when no tools are connected and input is not required', async () => {
agentNodeType.description.inputs = [
{
type: NodeConnectionType.AiTool,
type: NodeConnectionTypes.AiTool,
required: false,
},
];
workflow.getParentNodes.mockReturnValueOnce([]);
const result = await executeContext.getInputConnectionData(NodeConnectionType.AiTool, 0);
const result = await executeContext.getInputConnectionData(NodeConnectionTypes.AiTool, 0);
expect(result).toEqual([]);
expect(supplyData).not.toHaveBeenCalled();
});
@@ -275,14 +275,14 @@ describe('getInputConnectionData', () => {
it('should throw when required tool node is not connected', async () => {
agentNodeType.description.inputs = [
{
type: NodeConnectionType.AiTool,
type: NodeConnectionTypes.AiTool,
required: true,
},
];
workflow.getParentNodes.mockReturnValueOnce([]);
await expect(
executeContext.getInputConnectionData(NodeConnectionType.AiTool, 0),
executeContext.getInputConnectionData(NodeConnectionTypes.AiTool, 0),
).rejects.toThrow('must be connected and enabled');
expect(supplyData).not.toHaveBeenCalled();
});
@@ -296,18 +296,18 @@ describe('getInputConnectionData', () => {
agentNodeType.description.inputs = [
{
type: NodeConnectionType.AiTool,
type: NodeConnectionTypes.AiTool,
required: true,
},
];
workflow.getParentNodes
.calledWith(agentNode.name, NodeConnectionType.AiTool)
.calledWith(agentNode.name, NodeConnectionTypes.AiTool)
.mockReturnValue([disabledToolNode.name]);
workflow.getNode.calledWith(disabledToolNode.name).mockReturnValue(disabledToolNode);
await expect(
executeContext.getInputConnectionData(NodeConnectionType.AiTool, 0),
executeContext.getInputConnectionData(NodeConnectionTypes.AiTool, 0),
).rejects.toThrow('must be connected and enabled');
expect(supplyData).not.toHaveBeenCalled();
});
@@ -315,7 +315,7 @@ describe('getInputConnectionData', () => {
it('should handle multiple connected tools', async () => {
agentNodeType.description.inputs = [
{
type: NodeConnectionType.AiTool,
type: NodeConnectionTypes.AiTool,
required: true,
},
];
@@ -325,10 +325,10 @@ describe('getInputConnectionData', () => {
.mockReturnValue(secondToolNodeType);
workflow.getParentNodes
.calledWith(agentNode.name, NodeConnectionType.AiTool)
.calledWith(agentNode.name, NodeConnectionTypes.AiTool)
.mockReturnValue([toolNode.name, secondToolNode.name]);
const result = await executeContext.getInputConnectionData(NodeConnectionType.AiTool, 0);
const result = await executeContext.getInputConnectionData(NodeConnectionTypes.AiTool, 0);
expect(result).toEqual([mockTool, secondMockTool]);
expect(supplyData).toHaveBeenCalled();
expect(secondToolNodeType.supplyData).toHaveBeenCalled();
@@ -339,13 +339,13 @@ describe('getInputConnectionData', () => {
agentNodeType.description.inputs = [
{
type: NodeConnectionType.AiTool,
type: NodeConnectionTypes.AiTool,
required: true,
},
];
await expect(
executeContext.getInputConnectionData(NodeConnectionType.AiTool, 0),
executeContext.getInputConnectionData(NodeConnectionTypes.AiTool, 0),
).rejects.toThrow(`Error in sub-node ${toolNode.name}`);
expect(supplyData).toHaveBeenCalled();
});
@@ -353,12 +353,12 @@ describe('getInputConnectionData', () => {
it('should return the tool when there are no issues', async () => {
agentNodeType.description.inputs = [
{
type: NodeConnectionType.AiTool,
type: NodeConnectionTypes.AiTool,
required: true,
},
];
const result = await executeContext.getInputConnectionData(NodeConnectionType.AiTool, 0);
const result = await executeContext.getInputConnectionData(NodeConnectionTypes.AiTool, 0);
expect(result).toEqual([mockTool]);
expect(supplyData).toHaveBeenCalled();
});
@@ -13,7 +13,7 @@ import type {
AINodeConnectionType,
} from 'n8n-workflow';
import {
NodeConnectionType,
NodeConnectionTypes,
NodeOperationError,
ExecutionBaseError,
ApplicationError,
@@ -92,7 +92,7 @@ export async function getInputConnectionData(
);
if (!connectedNodeType.supplyData) {
if (connectedNodeType.description.outputs.includes(NodeConnectionType.AiTool)) {
if (connectedNodeType.description.outputs.includes(NodeConnectionTypes.AiTool)) {
/**
* This keeps track of how many times this specific AI tool node has been invoked.
* It is incremented on every invocation of the tool to keep the output of each invocation separate from each other.
@@ -104,7 +104,7 @@ export async function getInputConnectionData(
handleToolInvocation: async (toolArgs) => {
const runIndex = toolRunIndex++;
const context = contextFactory(runIndex, {});
context.addInputData(NodeConnectionType.AiTool, [[{ json: toolArgs }]]);
context.addInputData(NodeConnectionTypes.AiTool, [[{ json: toolArgs }]]);
try {
// Execute the sub-node with the proxied context
@@ -116,7 +116,7 @@ export async function getInputConnectionData(
const mappedResults = result?.[0]?.flatMap((item) => item.json);
// Add output data to the context
context.addOutputData(NodeConnectionType.AiTool, runIndex, [
context.addOutputData(NodeConnectionTypes.AiTool, runIndex, [
[{ json: { response: mappedResults } }],
]);
@@ -124,7 +124,7 @@ export async function getInputConnectionData(
return JSON.stringify(mappedResults);
} catch (error) {
const nodeError = new NodeOperationError(connectedNode, error as Error);
context.addOutputData(NodeConnectionType.AiTool, runIndex, nodeError);
context.addOutputData(NodeConnectionTypes.AiTool, runIndex, nodeError);
return 'Error during node execution: ' + nodeError.description;
}
},