Add functionality to evaluate expression

This commit is contained in:
Jan Oberhauser 2020-03-21 17:25:29 +01:00
parent e9c6c64290
commit c1853a6ff5
8 changed files with 43 additions and 2 deletions

View file

@ -49,6 +49,7 @@ The following special variables are available:
- **$binary**: Incoming binary data of a node
- **$data**: Incoming JSON data of a node
- **$evaluateExpression**: Evaluates a string as expression
- **$env**: Environment variables
- **$node**: Data of other nodes (output-data, parameters)
- **$parameters**: Parameters of the current node

View file

@ -99,6 +99,22 @@ const channel = $node["Slack"].parameter["channel"];
```
#### Method: evaluateExpression(expression: string, itemIndex: number)
Evaluates a given string as expression.
If no `itemIndex` is provided it uses by default in the Function-Node the data of item 0 and
in the Function Item-Node the data of the current item.
Example:
```javascript
items[0].json.variable1 = evaluateExpression('{{1+2}}');
items[0].json.variable2 = evaluateExpression($node["Set"].json["myExpression"], 1);
return items;
```
#### Method: getWorkflowStaticData(type)
Gives access to the static workflow data.
@ -114,7 +130,7 @@ same in the whole workflow. And every node in the workflow can access it. The no
Example:
```typescript
```javascript
// Get the global workflow static data
const staticData = getWorkflowStaticData('global');
// Get the static data of the node

View file

@ -490,6 +490,9 @@ export function getExecuteFunctions(workflow: Workflow, runExecutionData: IRunEx
continueOnFail: () => {
return continueOnFail(node);
},
evaluateExpression: (expression: string, itemIndex: number) => {
return workflow.resolveSimpleParameterValue('=' + expression, runExecutionData, runIndex, itemIndex, node.name, connectionInputData);
},
async executeWorkflow(workflowInfo: IExecuteWorkflowInfo, inputData?: INodeExecutionData[]): Promise<any> { // tslint:disable-line:no-any
return additionalData.executeWorkflow(workflowInfo, additionalData, inputData);
},
@ -578,6 +581,10 @@ export function getExecuteSingleFunctions(workflow: Workflow, runExecutionData:
continueOnFail: () => {
return continueOnFail(node);
},
evaluateExpression: (expression: string, evaluateItemIndex: number | undefined) => {
evaluateItemIndex = evaluateItemIndex === undefined ? itemIndex : evaluateItemIndex;
return workflow.resolveSimpleParameterValue('=' + expression, runExecutionData, runIndex, evaluateItemIndex, node.name, connectionInputData);
},
getContext(type: string): IContextObject {
return NodeHelpers.getContext(runExecutionData, type, node);
},

View file

@ -47,6 +47,9 @@ export class Function implements INodeType {
// Define the global objects for the custom function
const sandbox = {
evaluateExpression: (expression: string, itemIndex = 0) => {
return this.evaluateExpression(expression, itemIndex);
},
getNodeParameter: this.getNodeParameter,
getWorkflowStaticData: this.getWorkflowStaticData,
helpers: this.helpers,

View file

@ -48,6 +48,9 @@ export class FunctionItem implements INodeType {
// Define the global objects for the custom function
const sandbox = {
evaluateExpression: (expression: string, itemIndex: number | undefined) => {
return this.evaluateExpression(expression, itemIndex);
},
getBinaryData: (): IBinaryKeyData | undefined => {
return item.binary;
},

View file

@ -155,6 +155,7 @@ export interface IExecuteContextData {
export interface IExecuteFunctions {
continueOnFail(): boolean;
evaluateExpression(expression: string, itemIndex: number): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[];
executeWorkflow(workflowInfo: IExecuteWorkflowInfo, inputData?: INodeExecutionData[]): Promise<any>; // tslint:disable-line:no-any
getContext(type: string): IContextObject;
getCredentials(type: string): ICredentialDataDecryptedObject | undefined;
@ -176,6 +177,7 @@ export interface IExecuteFunctions {
export interface IExecuteSingleFunctions {
continueOnFail(): boolean;
evaluateExpression(expression: string, itemIndex: number | undefined): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[];
getContext(type: string): IContextObject;
getCredentials(type: string): ICredentialDataDecryptedObject | undefined;
getInputData(inputIndex?: number, inputName?: string): INodeExecutionData;
@ -530,8 +532,12 @@ export interface IWorkflowDataProxyData {
$binary: any; // tslint:disable-line:no-any
$data: any; // tslint:disable-line:no-any
$env: any; // tslint:disable-line:no-any
$evaluateExpression: any; // tslint:disable-line:no-any
$item: any; // tslint:disable-line:no-any
$json: any; // tslint:disable-line:no-any
$node: any; // tslint:disable-line:no-any
$parameter: any; // tslint:disable-line:no-any
$workflow: any; // tslint:disable-line:no-any
}
export interface IWorkflowMetadata {

View file

@ -897,10 +897,14 @@ export class Workflow {
// Generate a data proxy which allows to query workflow data
const dataProxy = new WorkflowDataProxy(this, runExecutionData, runIndex, itemIndex, activeNodeName, connectionInputData);
const data = dataProxy.getDataProxy();
data.$evaluateExpression = (expression: string) => {
return this.resolveSimpleParameterValue('=' + expression, runExecutionData, runIndex, itemIndex, activeNodeName, connectionInputData, returnObjectAsString);
};
// Execute the expression
try {
const returnValue = tmpl.tmpl(parameterValue, dataProxy.getDataProxy());
const returnValue = tmpl.tmpl(parameterValue, data);
if (returnValue !== null && typeof returnValue === 'object') {
if (Object.keys(returnValue).length === 0) {
// When expression is incomplete it returns a Proxy which causes problems.

View file

@ -300,6 +300,7 @@ export class WorkflowDataProxy {
$binary: {}, // Placeholder
$data: {}, // Placeholder
$env: this.envGetter(),
$evaluateExpression: (expression: string) => { }, // Placeholder
$item: (itemIndex: number) => {
const dataProxy = new WorkflowDataProxy(this.workflow, this.runExecutionData, this.runIndex, itemIndex, this.activeNodeName, this.connectionInputData);
return dataProxy.getDataProxy();