From 48ccb36536dc6ae14eb8626b2a2a755e6414d7ba Mon Sep 17 00:00:00 2001 From: Jan Oberhauser Date: Wed, 4 Sep 2019 14:53:39 +0200 Subject: [PATCH] :sparkles: Make special variables like $node, $parameter, ... accessible in Function Nodes --- packages/core/src/NodeExecuteFunctions.ts | 10 ++++++++++ packages/nodes-base/nodes/Function.node.ts | 6 ++++++ packages/nodes-base/nodes/FunctionItem.node.ts | 4 ++++ packages/workflow/src/Interfaces.ts | 10 ++++++++++ packages/workflow/src/WorkflowDataProxy.ts | 13 +++++++------ 5 files changed, 37 insertions(+), 6 deletions(-) diff --git a/packages/core/src/NodeExecuteFunctions.ts b/packages/core/src/NodeExecuteFunctions.ts index 379344c328..675ad36d5f 100644 --- a/packages/core/src/NodeExecuteFunctions.ts +++ b/packages/core/src/NodeExecuteFunctions.ts @@ -23,10 +23,12 @@ import { IWebhookData, IWebhookDescription, IWebhookFunctions, + IWorkflowDataProxyData, IWorkflowExecuteAdditionalData, NodeHelpers, NodeParameterValue, Workflow, + WorkflowDataProxy, WorkflowExecuteMode, } from 'n8n-workflow'; @@ -403,6 +405,10 @@ export function getExecuteFunctions(workflow: Workflow, runExecutionData: IRunEx getTimezone: (): string => { return getTimezone(workflow, additionalData); }, + getWorkflowDataProxy: (itemIndex: number): IWorkflowDataProxyData => { + const dataProxy = new WorkflowDataProxy(workflow, runExecutionData, runIndex, itemIndex, node.name, connectionInputData); + return dataProxy.getDataProxy(); + }, getWorkflowStaticData(type: string): IDataObject { return workflow.getStaticData(type, node); }, @@ -476,6 +482,10 @@ export function getExecuteSingleFunctions(workflow: Workflow, runExecutionData: getNodeParameter: (parameterName: string, fallbackValue?: any): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object => { //tslint:disable-line:no-any return getNodeParameter(workflow, runExecutionData, runIndex, connectionInputData, node, parameterName, itemIndex, fallbackValue); }, + getWorkflowDataProxy: (): IWorkflowDataProxyData => { + const dataProxy = new WorkflowDataProxy(workflow, runExecutionData, runIndex, itemIndex, node.name, connectionInputData); + return dataProxy.getDataProxy(); + }, getWorkflowStaticData(type: string): IDataObject { return workflow.getStaticData(type, node); }, diff --git a/packages/nodes-base/nodes/Function.node.ts b/packages/nodes-base/nodes/Function.node.ts index e26c2f1052..a9d33043b8 100644 --- a/packages/nodes-base/nodes/Function.node.ts +++ b/packages/nodes-base/nodes/Function.node.ts @@ -48,8 +48,14 @@ export class Function implements INodeType { getNodeParameter: this.getNodeParameter, helpers: this.helpers, items, + // To be able to access data of other items + $item: (index: number) => this.getWorkflowDataProxy(index), }; + // Make it possible to access data via $node, $parameter, ... + // By default use data from first item + Object.assign(sandbox, sandbox.$item(0)); + const vm = new NodeVM({ console: 'inherit', sandbox, diff --git a/packages/nodes-base/nodes/FunctionItem.node.ts b/packages/nodes-base/nodes/FunctionItem.node.ts index 0c23625ccd..bd79e47457 100644 --- a/packages/nodes-base/nodes/FunctionItem.node.ts +++ b/packages/nodes-base/nodes/FunctionItem.node.ts @@ -57,6 +57,10 @@ export class FunctionItem implements INodeType { }, }; + // Make it possible to access data via $node, $parameter, ... + const dataProxy = this.getWorkflowDataProxy(); + Object.assign(sandbox, dataProxy); + const vm = new NodeVM({ console: 'inherit', sandbox, diff --git a/packages/workflow/src/Interfaces.ts b/packages/workflow/src/Interfaces.ts index 6d420fb2fb..5faadff4fd 100644 --- a/packages/workflow/src/Interfaces.ts +++ b/packages/workflow/src/Interfaces.ts @@ -154,6 +154,7 @@ export interface IExecuteFunctions { getInputData(inputIndex?: number, inputName?: string): INodeExecutionData[]; getMode(): WorkflowExecuteMode; getNodeParameter(parameterName: string, itemIndex: number, fallbackValue?: any): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object; //tslint:disable-line:no-any + getWorkflowDataProxy(itemIndex: number): IWorkflowDataProxyData; getWorkflowStaticData(type: string): IDataObject; getTimezone(): string; prepareOutputData(outputData: INodeExecutionData[], outputIndex?: number): Promise; @@ -170,6 +171,7 @@ export interface IExecuteSingleFunctions { getMode(): WorkflowExecuteMode; getNodeParameter(parameterName: string, fallbackValue?: any): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object; //tslint:disable-line:no-any getTimezone(): string; + getWorkflowDataProxy(): IWorkflowDataProxyData; getWorkflowStaticData(type: string): IDataObject; helpers: { [key: string]: (...args: any[]) => any //tslint:disable-line:no-any @@ -466,6 +468,14 @@ export interface IWebhookDescription { responseData?: WebhookResponseData | string; } +export interface IWorkflowDataProxyData { + $binary: any; // tslint:disable-line:no-any + $data: any; // tslint:disable-line:no-any + $env: any; // tslint:disable-line:no-any + $node: any; // tslint:disable-line:no-any + $parameter: any; // tslint:disable-line:no-any +} + export type WebhookHttpMethod = 'GET' | 'POST'; export interface IWebhookResonseData { diff --git a/packages/workflow/src/WorkflowDataProxy.ts b/packages/workflow/src/WorkflowDataProxy.ts index 390fb1d549..e7fe72752c 100644 --- a/packages/workflow/src/WorkflowDataProxy.ts +++ b/packages/workflow/src/WorkflowDataProxy.ts @@ -1,8 +1,9 @@ import { IDataObject, INodeExecutionData, - NodeHelpers, IRunExecutionData, + IWorkflowDataProxyData, + NodeHelpers, Workflow, } from './'; @@ -184,12 +185,12 @@ export class WorkflowDataProxy { return executionData[that.itemIndex].json; } else if (name === 'binary') { // Binary-Data - if (!executionData[that.itemIndex].binary) { - throw new Error(`No binary data for node "${nodeName}" has been found!`); - } - const returnData: IDataObject = {}; + if (!executionData[that.itemIndex].binary) { + return returnData; + } + const binaryKeyData = executionData[that.itemIndex].binary!; for (const keyName of Object.keys(binaryKeyData)) { @@ -263,7 +264,7 @@ export class WorkflowDataProxy { * @returns * @memberof WorkflowDataGetter */ - getDataProxy() { + getDataProxy(): IWorkflowDataProxyData { const that = this; const base = {