2021-08-29 11:58:11 -07:00
|
|
|
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
|
|
|
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
|
|
/* eslint-disable no-restricted-syntax */
|
|
|
|
/* eslint-disable no-param-reassign */
|
|
|
|
/* eslint-disable @typescript-eslint/no-this-alias */
|
|
|
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
|
|
|
/* eslint-disable no-prototype-builtins */
|
|
|
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
2022-03-13 01:34:44 -08:00
|
|
|
|
|
|
|
import { DateTime, Duration, Interval } from 'luxon';
|
|
|
|
import * as jmespath from 'jmespath';
|
|
|
|
|
2021-08-29 11:58:11 -07:00
|
|
|
// eslint-disable-next-line import/no-cycle
|
2019-06-23 03:35:23 -07:00
|
|
|
import {
|
|
|
|
IDataObject,
|
|
|
|
INodeExecutionData,
|
2021-05-14 16:16:48 -07:00
|
|
|
INodeParameters,
|
2019-06-23 03:35:23 -07:00
|
|
|
IRunExecutionData,
|
2021-08-21 05:11:32 -07:00
|
|
|
IWorkflowDataProxyAdditionalKeys,
|
2019-09-04 05:53:39 -07:00
|
|
|
IWorkflowDataProxyData,
|
|
|
|
NodeHelpers,
|
2021-05-14 16:16:48 -07:00
|
|
|
NodeParameterValue,
|
2019-06-23 03:35:23 -07:00
|
|
|
Workflow,
|
2021-01-29 00:31:40 -08:00
|
|
|
WorkflowExecuteMode,
|
2021-08-29 11:58:11 -07:00
|
|
|
} from '.';
|
2019-06-23 03:35:23 -07:00
|
|
|
|
|
|
|
export class WorkflowDataProxy {
|
|
|
|
private workflow: Workflow;
|
2021-08-29 11:58:11 -07:00
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
private runExecutionData: IRunExecutionData | null;
|
2021-08-29 11:58:11 -07:00
|
|
|
|
2020-04-13 06:57:01 -07:00
|
|
|
private defaultReturnRunIndex: number;
|
2021-08-29 11:58:11 -07:00
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
private runIndex: number;
|
2021-08-29 11:58:11 -07:00
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
private itemIndex: number;
|
2021-08-29 11:58:11 -07:00
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
private activeNodeName: string;
|
2021-08-29 11:58:11 -07:00
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
private connectionInputData: INodeExecutionData[];
|
2021-08-29 11:58:11 -07:00
|
|
|
|
2021-05-14 16:16:48 -07:00
|
|
|
private siblingParameters: INodeParameters;
|
2021-08-29 11:58:11 -07:00
|
|
|
|
2021-01-29 00:31:40 -08:00
|
|
|
private mode: WorkflowExecuteMode;
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2021-08-29 11:58:11 -07:00
|
|
|
private selfData: IDataObject;
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2021-08-29 11:58:11 -07:00
|
|
|
private additionalKeys: IWorkflowDataProxyAdditionalKeys;
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2021-08-29 11:58:11 -07:00
|
|
|
constructor(
|
|
|
|
workflow: Workflow,
|
|
|
|
runExecutionData: IRunExecutionData | null,
|
|
|
|
runIndex: number,
|
|
|
|
itemIndex: number,
|
|
|
|
activeNodeName: string,
|
|
|
|
connectionInputData: INodeExecutionData[],
|
|
|
|
siblingParameters: INodeParameters,
|
|
|
|
mode: WorkflowExecuteMode,
|
|
|
|
additionalKeys: IWorkflowDataProxyAdditionalKeys,
|
|
|
|
defaultReturnRunIndex = -1,
|
|
|
|
selfData = {},
|
|
|
|
) {
|
2019-06-23 03:35:23 -07:00
|
|
|
this.workflow = workflow;
|
|
|
|
this.runExecutionData = runExecutionData;
|
2020-04-13 06:57:01 -07:00
|
|
|
this.defaultReturnRunIndex = defaultReturnRunIndex;
|
2019-06-23 03:35:23 -07:00
|
|
|
this.runIndex = runIndex;
|
|
|
|
this.itemIndex = itemIndex;
|
|
|
|
this.activeNodeName = activeNodeName;
|
|
|
|
this.connectionInputData = connectionInputData;
|
2021-05-14 16:16:48 -07:00
|
|
|
this.siblingParameters = siblingParameters;
|
2021-01-29 00:31:40 -08:00
|
|
|
this.mode = mode;
|
2021-01-27 00:02:20 -08:00
|
|
|
this.selfData = selfData;
|
2021-08-21 05:11:32 -07:00
|
|
|
this.additionalKeys = additionalKeys;
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a proxy which allows to query context data of a given node
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @param {string} nodeName The name of the node to get the context from
|
|
|
|
* @returns
|
|
|
|
* @memberof WorkflowDataProxy
|
|
|
|
*/
|
|
|
|
private nodeContextGetter(nodeName: string) {
|
|
|
|
const that = this;
|
|
|
|
const node = this.workflow.nodes[nodeName];
|
|
|
|
|
2021-08-29 11:58:11 -07:00
|
|
|
return new Proxy(
|
|
|
|
{},
|
|
|
|
{
|
|
|
|
ownKeys(target) {
|
|
|
|
if (Reflect.ownKeys(target).length === 0) {
|
|
|
|
// Target object did not get set yet
|
|
|
|
Object.assign(target, NodeHelpers.getContext(that.runExecutionData!, 'node', node));
|
|
|
|
}
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2021-08-29 11:58:11 -07:00
|
|
|
return Reflect.ownKeys(target);
|
|
|
|
},
|
2021-12-23 02:41:46 -08:00
|
|
|
getOwnPropertyDescriptor(k) {
|
|
|
|
return {
|
|
|
|
enumerable: true,
|
|
|
|
configurable: true,
|
|
|
|
};
|
|
|
|
},
|
2021-08-29 11:58:11 -07:00
|
|
|
get(target, name, receiver) {
|
|
|
|
// eslint-disable-next-line no-param-reassign
|
|
|
|
name = name.toString();
|
|
|
|
const contextData = NodeHelpers.getContext(that.runExecutionData!, 'node', node);
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2021-08-29 11:58:11 -07:00
|
|
|
if (!contextData.hasOwnProperty(name)) {
|
|
|
|
// Parameter does not exist on node
|
|
|
|
throw new Error(`Could not find parameter "${name}" on context of node "${nodeName}"`);
|
|
|
|
}
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2021-08-29 11:58:11 -07:00
|
|
|
return contextData[name];
|
|
|
|
},
|
2020-10-22 06:46:03 -07:00
|
|
|
},
|
2021-08-29 11:58:11 -07:00
|
|
|
);
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
|
|
|
|
2021-01-27 00:02:20 -08:00
|
|
|
private selfGetter() {
|
|
|
|
const that = this;
|
|
|
|
|
2021-08-29 11:58:11 -07:00
|
|
|
return new Proxy(
|
|
|
|
{},
|
|
|
|
{
|
|
|
|
ownKeys(target) {
|
|
|
|
return Reflect.ownKeys(target);
|
|
|
|
},
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
|
|
get(target, name, receiver) {
|
|
|
|
name = name.toString();
|
|
|
|
return that.selfData[name];
|
|
|
|
},
|
2021-01-27 00:02:20 -08:00
|
|
|
},
|
2021-08-29 11:58:11 -07:00
|
|
|
);
|
2021-01-27 00:02:20 -08:00
|
|
|
}
|
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
/**
|
|
|
|
* Returns a proxy which allows to query parameter data of a given node
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @param {string} nodeName The name of the node to query data from
|
|
|
|
* @returns
|
|
|
|
* @memberof WorkflowDataGetter
|
|
|
|
*/
|
|
|
|
private nodeParameterGetter(nodeName: string) {
|
|
|
|
const that = this;
|
|
|
|
const node = this.workflow.nodes[nodeName];
|
|
|
|
|
|
|
|
return new Proxy(node.parameters, {
|
|
|
|
ownKeys(target) {
|
|
|
|
return Reflect.ownKeys(target);
|
|
|
|
},
|
2021-12-23 02:41:46 -08:00
|
|
|
getOwnPropertyDescriptor(k) {
|
|
|
|
return {
|
|
|
|
enumerable: true,
|
|
|
|
configurable: true,
|
|
|
|
};
|
|
|
|
},
|
2019-06-23 03:35:23 -07:00
|
|
|
get(target, name, receiver) {
|
|
|
|
name = name.toString();
|
|
|
|
|
2021-08-29 11:58:11 -07:00
|
|
|
let returnValue:
|
|
|
|
| INodeParameters
|
|
|
|
| NodeParameterValue
|
|
|
|
| NodeParameterValue[]
|
|
|
|
| INodeParameters[];
|
2021-05-14 16:20:21 -07:00
|
|
|
if (name[0] === '&') {
|
2021-05-14 16:16:48 -07:00
|
|
|
const key = name.slice(1);
|
|
|
|
if (!that.siblingParameters.hasOwnProperty(key)) {
|
|
|
|
throw new Error(`Could not find sibling parameter "${key}" on node "${nodeName}"`);
|
|
|
|
}
|
|
|
|
returnValue = that.siblingParameters[key];
|
|
|
|
} else {
|
|
|
|
if (!node.parameters.hasOwnProperty(name)) {
|
|
|
|
// Parameter does not exist on node
|
2022-02-19 03:38:46 -08:00
|
|
|
return undefined;
|
2021-05-14 16:16:48 -07:00
|
|
|
}
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2021-05-14 16:16:48 -07:00
|
|
|
returnValue = node.parameters[name];
|
|
|
|
}
|
2019-06-23 03:35:23 -07:00
|
|
|
|
|
|
|
if (typeof returnValue === 'string' && returnValue.charAt(0) === '=') {
|
|
|
|
// The found value is an expression so resolve it
|
2021-08-29 11:58:11 -07:00
|
|
|
return that.workflow.expression.getParameterValue(
|
|
|
|
returnValue,
|
|
|
|
that.runExecutionData,
|
|
|
|
that.runIndex,
|
|
|
|
that.itemIndex,
|
|
|
|
that.activeNodeName,
|
|
|
|
that.connectionInputData,
|
|
|
|
that.mode,
|
|
|
|
that.additionalKeys,
|
|
|
|
);
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return returnValue;
|
2020-10-22 06:46:03 -07:00
|
|
|
},
|
2019-06-23 03:35:23 -07:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-04-12 09:42:29 -07:00
|
|
|
/**
|
|
|
|
* Returns the node ExecutionData
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @param {string} nodeName The name of the node query data from
|
|
|
|
* @param {boolean} [shortSyntax=false] If short syntax got used
|
|
|
|
* @param {number} [outputIndex] The index of the output, if not given the first one gets used
|
|
|
|
* @param {number} [runIndex] The index of the run, if not given the current one does get used
|
|
|
|
* @returns {INodeExecutionData[]}
|
|
|
|
* @memberof WorkflowDataProxy
|
|
|
|
*/
|
2021-08-29 11:58:11 -07:00
|
|
|
private getNodeExecutionData(
|
|
|
|
nodeName: string,
|
|
|
|
shortSyntax = false,
|
|
|
|
outputIndex?: number,
|
|
|
|
runIndex?: number,
|
|
|
|
): INodeExecutionData[] {
|
2020-04-12 09:42:29 -07:00
|
|
|
const that = this;
|
|
|
|
|
|
|
|
let executionData: INodeExecutionData[];
|
2021-08-29 11:58:11 -07:00
|
|
|
if (!shortSyntax) {
|
2020-04-12 09:42:29 -07:00
|
|
|
// Long syntax got used to return data from node in path
|
|
|
|
|
|
|
|
if (that.runExecutionData === null) {
|
|
|
|
throw new Error(`Workflow did not run so do not have any execution-data.`);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!that.runExecutionData.resultData.runData.hasOwnProperty(nodeName)) {
|
2022-03-13 01:34:44 -08:00
|
|
|
if (that.workflow.getNode(nodeName)) {
|
|
|
|
throw new Error(
|
|
|
|
`The node "${nodeName}" hasn't been executed yet, so you can't reference its output data`,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
throw new Error(`No node called "${nodeName}" in this workflow`);
|
|
|
|
}
|
2020-04-12 09:42:29 -07:00
|
|
|
}
|
|
|
|
|
2020-04-13 06:57:01 -07:00
|
|
|
runIndex = runIndex === undefined ? that.defaultReturnRunIndex : runIndex;
|
2021-08-29 11:58:11 -07:00
|
|
|
runIndex =
|
|
|
|
runIndex === -1 ? that.runExecutionData.resultData.runData[nodeName].length - 1 : runIndex;
|
2020-04-12 09:42:29 -07:00
|
|
|
|
2022-03-13 01:34:44 -08:00
|
|
|
if (that.runExecutionData.resultData.runData[nodeName].length <= runIndex) {
|
|
|
|
throw new Error(`Run ${runIndex} of node "${nodeName}" not found`);
|
2020-04-12 09:42:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
const taskData = that.runExecutionData.resultData.runData[nodeName][runIndex].data!;
|
|
|
|
|
|
|
|
if (taskData.main === null || !taskData.main.length || taskData.main[0] === null) {
|
|
|
|
// throw new Error(`No data found for item-index: "${itemIndex}"`);
|
|
|
|
throw new Error(`No data found from "main" input.`);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check from which output to read the data.
|
|
|
|
// Depends on how the nodes are connected.
|
|
|
|
// (example "IF" node. If node is connected to "true" or to "false" output)
|
|
|
|
if (outputIndex === undefined) {
|
2021-08-29 11:58:11 -07:00
|
|
|
// eslint-disable-next-line @typescript-eslint/no-shadow
|
|
|
|
const outputIndex = that.workflow.getNodeConnectionOutputIndex(
|
|
|
|
that.activeNodeName,
|
|
|
|
nodeName,
|
|
|
|
'main',
|
|
|
|
);
|
2020-04-12 09:42:29 -07:00
|
|
|
|
|
|
|
if (outputIndex === undefined) {
|
2021-08-29 11:58:11 -07:00
|
|
|
throw new Error(
|
|
|
|
`The node "${that.activeNodeName}" is not connected with node "${nodeName}" so no data can get returned from it.`,
|
|
|
|
);
|
2020-04-12 09:42:29 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (outputIndex === undefined) {
|
|
|
|
outputIndex = 0;
|
|
|
|
}
|
|
|
|
|
2022-03-13 01:34:44 -08:00
|
|
|
if (taskData.main.length <= outputIndex) {
|
|
|
|
throw new Error(`Node "${nodeName}" has no branch with index ${outputIndex}.`);
|
2020-04-12 09:42:29 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
executionData = taskData.main[outputIndex] as INodeExecutionData[];
|
|
|
|
} else {
|
|
|
|
// Short syntax got used to return data from active node
|
|
|
|
|
|
|
|
// TODO: Here have to generate connection Input data for the current node by itself
|
|
|
|
// Data needed:
|
|
|
|
// #- the run-index
|
|
|
|
// - node which did send data (has to be the one from last recent execution)
|
|
|
|
// - later also the name of the input and its index (currently not needed as it is always "main" and index "0")
|
|
|
|
executionData = that.connectionInputData;
|
|
|
|
}
|
|
|
|
|
|
|
|
return executionData;
|
|
|
|
}
|
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
/**
|
|
|
|
* Returns a proxy which allows to query data of a given node
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @param {string} nodeName The name of the node query data from
|
|
|
|
* @param {boolean} [shortSyntax=false] If short syntax got used
|
|
|
|
* @returns
|
|
|
|
* @memberof WorkflowDataGetter
|
|
|
|
*/
|
|
|
|
private nodeDataGetter(nodeName: string, shortSyntax = false) {
|
|
|
|
const that = this;
|
|
|
|
const node = this.workflow.nodes[nodeName];
|
|
|
|
|
|
|
|
if (!node) {
|
2022-02-19 03:38:46 -08:00
|
|
|
return undefined;
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
|
|
|
|
2021-08-29 11:58:11 -07:00
|
|
|
return new Proxy(
|
|
|
|
{},
|
|
|
|
{
|
|
|
|
get(target, name, receiver) {
|
|
|
|
name = name.toString();
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2021-08-29 11:58:11 -07:00
|
|
|
if (['binary', 'data', 'json'].includes(name)) {
|
|
|
|
const executionData = that.getNodeExecutionData(nodeName, shortSyntax, undefined);
|
2019-09-04 05:53:39 -07:00
|
|
|
|
2021-08-29 11:58:11 -07:00
|
|
|
if (executionData.length <= that.itemIndex) {
|
|
|
|
throw new Error(`No data found for item-index: "${that.itemIndex}"`);
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
|
|
|
|
2021-08-29 11:58:11 -07:00
|
|
|
if (['data', 'json'].includes(name)) {
|
|
|
|
// JSON-Data
|
|
|
|
return executionData[that.itemIndex].json;
|
|
|
|
}
|
|
|
|
if (name === 'binary') {
|
|
|
|
// Binary-Data
|
|
|
|
const returnData: IDataObject = {};
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2021-08-29 11:58:11 -07:00
|
|
|
if (!executionData[that.itemIndex].binary) {
|
|
|
|
return returnData;
|
|
|
|
}
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2021-08-29 11:58:11 -07:00
|
|
|
const binaryKeyData = executionData[that.itemIndex].binary!;
|
|
|
|
for (const keyName of Object.keys(binaryKeyData)) {
|
|
|
|
returnData[keyName] = {};
|
|
|
|
|
|
|
|
const binaryData = binaryKeyData[keyName];
|
|
|
|
for (const propertyName in binaryData) {
|
|
|
|
if (propertyName === 'data') {
|
|
|
|
// Skip the data property
|
|
|
|
// eslint-disable-next-line no-continue
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
(returnData[keyName] as IDataObject)[propertyName] = binaryData[propertyName];
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-29 11:58:11 -07:00
|
|
|
return returnData;
|
|
|
|
}
|
|
|
|
} else if (name === 'context') {
|
|
|
|
return that.nodeContextGetter(nodeName);
|
|
|
|
} else if (name === 'parameter') {
|
|
|
|
// Get node parameter data
|
|
|
|
return that.nodeParameterGetter(nodeName);
|
|
|
|
} else if (name === 'runIndex') {
|
|
|
|
if (
|
|
|
|
that.runExecutionData === null ||
|
|
|
|
!that.runExecutionData.resultData.runData[nodeName]
|
|
|
|
) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return that.runExecutionData.resultData.runData[nodeName].length - 1;
|
2020-04-13 06:57:01 -07:00
|
|
|
}
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2021-08-29 11:58:11 -07:00
|
|
|
return Reflect.get(target, name, receiver);
|
|
|
|
},
|
2020-10-22 06:46:03 -07:00
|
|
|
},
|
2021-08-29 11:58:11 -07:00
|
|
|
);
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a proxy to query data from the environment
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @returns
|
|
|
|
* @memberof WorkflowDataGetter
|
|
|
|
*/
|
|
|
|
private envGetter() {
|
2021-08-29 11:58:11 -07:00
|
|
|
return new Proxy(
|
|
|
|
{},
|
|
|
|
{
|
|
|
|
get(target, name, receiver) {
|
|
|
|
return process.env[name.toString()];
|
|
|
|
},
|
2020-10-22 06:46:03 -07:00
|
|
|
},
|
2021-08-29 11:58:11 -07:00
|
|
|
);
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
|
|
|
|
2020-02-15 17:07:01 -08:00
|
|
|
/**
|
|
|
|
* Returns a proxt to query data from the workflow
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @returns
|
|
|
|
* @memberof WorkflowDataProxy
|
|
|
|
*/
|
|
|
|
private workflowGetter() {
|
2021-08-29 11:58:11 -07:00
|
|
|
const allowedValues = ['active', 'id', 'name'];
|
2020-02-15 17:07:01 -08:00
|
|
|
const that = this;
|
|
|
|
|
2021-08-29 11:58:11 -07:00
|
|
|
return new Proxy(
|
|
|
|
{},
|
|
|
|
{
|
2021-12-23 02:41:46 -08:00
|
|
|
ownKeys(target) {
|
|
|
|
return allowedValues;
|
|
|
|
},
|
|
|
|
getOwnPropertyDescriptor(k) {
|
|
|
|
return {
|
|
|
|
enumerable: true,
|
|
|
|
configurable: true,
|
|
|
|
};
|
|
|
|
},
|
2021-08-29 11:58:11 -07:00
|
|
|
get(target, name, receiver) {
|
|
|
|
if (!allowedValues.includes(name.toString())) {
|
|
|
|
throw new Error(`The key "${name.toString()}" is not supported!`);
|
|
|
|
}
|
2020-02-15 17:07:01 -08:00
|
|
|
|
2021-08-29 11:58:11 -07:00
|
|
|
// @ts-ignore
|
|
|
|
return that.workflow[name.toString()];
|
|
|
|
},
|
2020-10-22 06:46:03 -07:00
|
|
|
},
|
2021-08-29 11:58:11 -07:00
|
|
|
);
|
2020-02-15 17:07:01 -08:00
|
|
|
}
|
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
/**
|
|
|
|
* Returns a proxy to query data of all nodes
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @returns
|
|
|
|
* @memberof WorkflowDataGetter
|
|
|
|
*/
|
|
|
|
private nodeGetter() {
|
|
|
|
const that = this;
|
2021-08-29 11:58:11 -07:00
|
|
|
return new Proxy(
|
|
|
|
{},
|
|
|
|
{
|
|
|
|
get(target, name, receiver) {
|
|
|
|
return that.nodeDataGetter(name.toString());
|
|
|
|
},
|
2020-10-22 06:46:03 -07:00
|
|
|
},
|
2021-08-29 11:58:11 -07:00
|
|
|
);
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the data proxy object which allows to query data from current run
|
|
|
|
*
|
|
|
|
* @returns
|
|
|
|
* @memberof WorkflowDataGetter
|
|
|
|
*/
|
2019-09-04 05:53:39 -07:00
|
|
|
getDataProxy(): IWorkflowDataProxyData {
|
2019-06-23 03:35:23 -07:00
|
|
|
const that = this;
|
|
|
|
|
2022-03-13 01:34:44 -08:00
|
|
|
const getNodeOutput = (nodeName?: string, branchIndex?: number, runIndex?: number) => {
|
|
|
|
let executionData: INodeExecutionData[];
|
|
|
|
|
|
|
|
if (nodeName === undefined) {
|
|
|
|
executionData = that.connectionInputData;
|
|
|
|
} else {
|
|
|
|
branchIndex = branchIndex || 0;
|
|
|
|
runIndex = runIndex === undefined ? -1 : runIndex;
|
|
|
|
executionData = that.getNodeExecutionData(nodeName, false, branchIndex, runIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
return executionData;
|
|
|
|
};
|
|
|
|
|
|
|
|
// replacing proxies with the actual data.
|
|
|
|
const jmespathWrapper = (data: IDataObject | IDataObject[], query: string) => {
|
|
|
|
if (!Array.isArray(data) && typeof data === 'object') {
|
|
|
|
return jmespath.search({ ...data }, query);
|
|
|
|
}
|
|
|
|
return jmespath.search(data, query);
|
|
|
|
};
|
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
const base = {
|
2022-03-13 01:34:44 -08:00
|
|
|
$: (nodeName: string) => {
|
|
|
|
if (!nodeName) {
|
|
|
|
throw new Error(`When calling $(), please specify a node`);
|
|
|
|
}
|
|
|
|
|
|
|
|
return new Proxy(
|
|
|
|
{},
|
|
|
|
{
|
|
|
|
get(target, property, receiver) {
|
|
|
|
if (property === 'pairedItem') {
|
|
|
|
return () => {
|
|
|
|
const executionData = getNodeOutput(nodeName, 0, that.runIndex);
|
|
|
|
if (executionData[that.itemIndex]) {
|
|
|
|
return executionData[that.itemIndex];
|
|
|
|
}
|
|
|
|
return undefined;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
if (property === 'item') {
|
|
|
|
return (itemIndex?: number, branchIndex?: number, runIndex?: number) => {
|
|
|
|
if (itemIndex === undefined) {
|
|
|
|
itemIndex = that.itemIndex;
|
|
|
|
branchIndex = 0;
|
|
|
|
runIndex = that.runIndex;
|
|
|
|
}
|
|
|
|
const executionData = getNodeOutput(nodeName, branchIndex, runIndex);
|
|
|
|
if (executionData[itemIndex]) {
|
|
|
|
return executionData[itemIndex];
|
|
|
|
}
|
|
|
|
let errorMessage = '';
|
|
|
|
|
|
|
|
if (branchIndex === undefined && runIndex === undefined) {
|
|
|
|
errorMessage = `
|
|
|
|
No item found at index ${itemIndex}
|
|
|
|
(for node "${nodeName}")`;
|
|
|
|
throw new Error(errorMessage);
|
|
|
|
}
|
|
|
|
if (branchIndex === undefined) {
|
|
|
|
errorMessage = `
|
|
|
|
No item found at index ${itemIndex}
|
|
|
|
in run ${runIndex || that.runIndex}
|
|
|
|
(for node "${nodeName}")`;
|
|
|
|
throw new Error(errorMessage);
|
|
|
|
}
|
|
|
|
if (runIndex === undefined) {
|
|
|
|
errorMessage = `
|
|
|
|
No item found at index ${itemIndex}
|
|
|
|
of branch ${branchIndex || 0}
|
|
|
|
(for node "${nodeName}")`;
|
|
|
|
throw new Error(errorMessage);
|
|
|
|
}
|
|
|
|
|
|
|
|
errorMessage = `
|
|
|
|
No item found at index ${itemIndex}
|
|
|
|
of branch ${branchIndex || 0}
|
|
|
|
in run ${runIndex || that.runIndex}
|
|
|
|
(for node "${nodeName}")`;
|
|
|
|
throw new Error(errorMessage);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
if (property === 'first') {
|
|
|
|
return (branchIndex?: number, runIndex?: number) => {
|
|
|
|
const executionData = getNodeOutput(nodeName, branchIndex, runIndex);
|
|
|
|
if (executionData[0]) return executionData[0];
|
|
|
|
return undefined;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
if (property === 'last') {
|
|
|
|
return (branchIndex?: number, runIndex?: number) => {
|
|
|
|
const executionData = getNodeOutput(nodeName, branchIndex, runIndex);
|
|
|
|
if (!executionData.length) return undefined;
|
|
|
|
if (executionData[executionData.length - 1]) {
|
|
|
|
return executionData[executionData.length - 1];
|
|
|
|
}
|
|
|
|
return undefined;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
if (property === 'all') {
|
|
|
|
return (branchIndex?: number, runIndex?: number) =>
|
|
|
|
getNodeOutput(nodeName, branchIndex, runIndex);
|
|
|
|
}
|
|
|
|
if (property === 'context') {
|
|
|
|
return that.nodeContextGetter(nodeName);
|
|
|
|
}
|
|
|
|
if (property === 'params') {
|
|
|
|
return that.workflow.getNode(nodeName)?.parameters;
|
|
|
|
}
|
|
|
|
return Reflect.get(target, property, receiver);
|
|
|
|
},
|
|
|
|
},
|
|
|
|
);
|
|
|
|
},
|
|
|
|
|
|
|
|
$input: new Proxy(
|
|
|
|
{},
|
|
|
|
{
|
|
|
|
get(target, property, receiver) {
|
|
|
|
if (property === 'thisItem') {
|
|
|
|
return that.connectionInputData[that.itemIndex];
|
|
|
|
}
|
|
|
|
if (property === 'item') {
|
|
|
|
return (itemIndex?: number) => {
|
|
|
|
if (itemIndex === undefined) itemIndex = that.itemIndex;
|
|
|
|
const result = that.connectionInputData;
|
|
|
|
if (result[itemIndex]) {
|
|
|
|
return result[itemIndex];
|
|
|
|
}
|
|
|
|
return undefined;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
if (property === 'first') {
|
|
|
|
return () => {
|
|
|
|
const result = that.connectionInputData;
|
|
|
|
if (result[0]) {
|
|
|
|
return result[0];
|
|
|
|
}
|
|
|
|
return undefined;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
if (property === 'last') {
|
|
|
|
return () => {
|
|
|
|
const result = that.connectionInputData;
|
|
|
|
if (result.length && result[result.length - 1]) {
|
|
|
|
return result[result.length - 1];
|
|
|
|
}
|
|
|
|
return undefined;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
if (property === 'all') {
|
|
|
|
return () => {
|
|
|
|
const result = that.connectionInputData;
|
|
|
|
if (result.length) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
return [];
|
|
|
|
};
|
|
|
|
}
|
|
|
|
return Reflect.get(target, property, receiver);
|
|
|
|
},
|
|
|
|
},
|
|
|
|
),
|
|
|
|
|
|
|
|
$thisItem: that.connectionInputData[that.itemIndex],
|
2019-06-23 03:35:23 -07:00
|
|
|
$binary: {}, // Placeholder
|
|
|
|
$data: {}, // Placeholder
|
|
|
|
$env: this.envGetter(),
|
2020-04-13 07:51:04 -07:00
|
|
|
$evaluateExpression: (expression: string, itemIndex?: number) => {
|
|
|
|
itemIndex = itemIndex || that.itemIndex;
|
2021-08-29 11:58:11 -07:00
|
|
|
return that.workflow.expression.getParameterValue(
|
|
|
|
`=${expression}`,
|
|
|
|
that.runExecutionData,
|
|
|
|
that.runIndex,
|
|
|
|
itemIndex,
|
|
|
|
that.activeNodeName,
|
|
|
|
that.connectionInputData,
|
|
|
|
that.mode,
|
|
|
|
that.additionalKeys,
|
|
|
|
);
|
2020-04-13 07:51:04 -07:00
|
|
|
},
|
2020-04-13 06:57:01 -07:00
|
|
|
$item: (itemIndex: number, runIndex?: number) => {
|
|
|
|
const defaultReturnRunIndex = runIndex === undefined ? -1 : runIndex;
|
2021-08-29 11:58:11 -07:00
|
|
|
const dataProxy = new WorkflowDataProxy(
|
|
|
|
this.workflow,
|
|
|
|
this.runExecutionData,
|
|
|
|
this.runIndex,
|
|
|
|
itemIndex,
|
|
|
|
this.activeNodeName,
|
|
|
|
this.connectionInputData,
|
|
|
|
that.siblingParameters,
|
|
|
|
that.mode,
|
|
|
|
that.additionalKeys,
|
|
|
|
defaultReturnRunIndex,
|
|
|
|
);
|
2020-01-03 14:37:13 -08:00
|
|
|
return dataProxy.getDataProxy();
|
|
|
|
},
|
2020-04-12 09:42:29 -07:00
|
|
|
$items: (nodeName?: string, outputIndex?: number, runIndex?: number) => {
|
|
|
|
let executionData: INodeExecutionData[];
|
|
|
|
|
|
|
|
if (nodeName === undefined) {
|
|
|
|
executionData = that.connectionInputData;
|
|
|
|
} else {
|
|
|
|
outputIndex = outputIndex || 0;
|
2020-04-13 06:57:01 -07:00
|
|
|
runIndex = runIndex === undefined ? -1 : runIndex;
|
2020-04-12 09:42:29 -07:00
|
|
|
executionData = that.getNodeExecutionData(nodeName, false, outputIndex, runIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
return executionData;
|
|
|
|
},
|
2020-02-15 16:01:00 -08:00
|
|
|
$json: {}, // Placeholder
|
2019-06-23 03:35:23 -07:00
|
|
|
$node: this.nodeGetter(),
|
2021-01-27 00:02:20 -08:00
|
|
|
$self: this.selfGetter(),
|
2019-06-23 03:35:23 -07:00
|
|
|
$parameter: this.nodeParameterGetter(this.activeNodeName),
|
2021-07-23 09:03:42 -07:00
|
|
|
$position: this.itemIndex,
|
2020-04-13 06:57:01 -07:00
|
|
|
$runIndex: this.runIndex,
|
2021-01-29 00:31:40 -08:00
|
|
|
$mode: this.mode,
|
2020-02-15 16:01:00 -08:00
|
|
|
$workflow: this.workflowGetter(),
|
2022-03-13 01:34:44 -08:00
|
|
|
$thisRunIndex: this.runIndex,
|
|
|
|
$thisItemIndex: this.itemIndex,
|
|
|
|
$now: DateTime.now(),
|
|
|
|
$today: DateTime.now().set({ hour: 0, minute: 0, second: 0, millisecond: 0 }),
|
|
|
|
$jmespath: jmespathWrapper,
|
|
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
|
|
DateTime,
|
|
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
|
|
Interval,
|
|
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
|
|
Duration,
|
2021-08-21 05:11:32 -07:00
|
|
|
...that.additionalKeys,
|
2019-06-23 03:35:23 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
return new Proxy(base, {
|
|
|
|
get(target, name, receiver) {
|
2020-02-15 16:01:00 -08:00
|
|
|
if (['$data', '$json'].includes(name as string)) {
|
2019-06-23 03:35:23 -07:00
|
|
|
// @ts-ignore
|
2020-02-15 16:01:00 -08:00
|
|
|
return that.nodeDataGetter(that.activeNodeName, true).json;
|
2021-08-29 11:58:11 -07:00
|
|
|
}
|
|
|
|
if (name === '$binary') {
|
2019-06-23 03:35:23 -07:00
|
|
|
// @ts-ignore
|
|
|
|
return that.nodeDataGetter(that.activeNodeName, true).binary;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Reflect.get(target, name, receiver);
|
2020-10-22 06:46:03 -07:00
|
|
|
},
|
2019-06-23 03:35:23 -07:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|