mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
🎨 Set up linting and formatting (#2120)
* ⬆️ Upgrade TS to 4.3.5 * 👕 Add ESLint configs * 🎨 Add Prettier config * 📦 Add deps and commands * ⚡ Adjust global .editorconfig to new ruleset * 🔥 Remove unneeded local .editorconfig * 📦 Update deps in editor-ui * 🔨 Limit Prettier to only TS files * ⚡ Add recommended VSCode extensions * 👕 Fix build * 🔥 Remove Vue setting from global config * ⚡ Disable prefer-default-export per feedback * ✏️ Add forgotten divider * 👕 Disable no-plusplus * 👕 Disable class-methods-use-this * ✏️ Alphabetize overrides * 👕 Add one-var consecutive override * ⏪ Revert one-var consecutive override This reverts commit b9252cf935659ba6d76727ad484a1d3c00008fcc. * 🎨 👕 Lint and format workflow package (#2121) * 🎨 Format /workflow package * 👕 Lint /workflow package * 🎨 Re-format /workflow package * 👕 Re-lint /workflow package * ✏️ Fix typo * ⚡ Consolidate if-checks * 🔥 Remove prefer-default-export exceptions * 🔥 Remove no-plusplus exceptions * 🔥 Remove class-methods-use-this exceptions * 🎨 👕 Lint and format node-dev package (#2122) * 🎨 Format /node-dev package * ⚡ Exclude templates from ESLint config This keeps the templates consistent with the codebase while preventing lint exceptions from being made part of the templates. * 👕 Lint /node-dev package * 🔥 Remove prefer-default-export exceptions * 🔥 Remove no-plusplus exceptions * 🎨 👕 Lint and format core package (#2123) * 🎨 Format /core package * 👕 Lint /core package * 🎨 Re-format /core package * 👕 Re-lint /core package * 🔥 Remove prefer-default-export exceptions * 🔥 Remove no-plusplus exceptions * 🔥 Remove class-methods-use-this exceptions * 🎨 👕 Lint and format cli package (#2124) * 🎨 Format /cli package * 👕 Exclude migrations from linting * 👕 Lint /cli package * 🎨 Re-format /cli package * 👕 Re-lint /cli package * 👕 Fix build * 🔥 Remove prefer-default-export exceptions * ⚡ Update exceptions in ActiveExecutions * 🔥 Remove no-plusplus exceptions * 🔥 Remove class-methods-use-this exceptions * 👕 fix lint issues * 🔧 use package specific linter, remove tslint command * 🔨 resolve build issue, sync dependencies * 🔧 change lint command Co-authored-by: Ben Hesseldieck <b.hesseldieck@gmail.com>
This commit is contained in:
@@ -17,8 +17,9 @@
|
||||
"scripts": {
|
||||
"dev": "npm run watch",
|
||||
"build": "tsc",
|
||||
"tslint": "tslint -p tsconfig.json -c tslint.json",
|
||||
"tslintfix": "tslint --fix -p tsconfig.json -c tslint.json",
|
||||
"format": "cd ../.. && node_modules/prettier/bin-prettier.js packages/workflow/**/**.ts --write",
|
||||
"lint": "cd ../.. && node_modules/eslint/bin/eslint.js packages/workflow",
|
||||
"lintfix": "cd ../.. && node_modules/eslint/bin/eslint.js packages/workflow --fix",
|
||||
"watch": "tsc --watch",
|
||||
"test": "jest"
|
||||
},
|
||||
@@ -31,10 +32,18 @@
|
||||
"@types/lodash.get": "^4.4.6",
|
||||
"@types/node": "^14.14.40",
|
||||
"@types/xml2js": "^0.4.3",
|
||||
"@typescript-eslint/eslint-plugin": "^4.29.0",
|
||||
"@typescript-eslint/parser": "^4.29.0",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-airbnb-typescript": "^12.3.1",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-import": "^2.23.4",
|
||||
"eslint-plugin-prettier": "^3.4.0",
|
||||
"jest": "^26.4.2",
|
||||
"prettier": "^2.3.2",
|
||||
"ts-jest": "^26.3.0",
|
||||
"tslint": "^6.1.2",
|
||||
"typescript": "~3.9.7"
|
||||
"typescript": "~4.3.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"lodash.get": "^4.4.2",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
|
||||
// @ts-ignore
|
||||
import * as tmpl from 'riot-tmpl';
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
import {
|
||||
INode,
|
||||
INodeExecutionData,
|
||||
@@ -9,28 +11,26 @@ import {
|
||||
Workflow,
|
||||
WorkflowDataProxy,
|
||||
WorkflowExecuteMode,
|
||||
} from './';
|
||||
} from '.';
|
||||
|
||||
// @ts-ignore
|
||||
import * as tmpl from 'riot-tmpl';
|
||||
|
||||
// Set it to use double curly brackets instead of single ones
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
|
||||
tmpl.brackets.set('{{ }}');
|
||||
|
||||
// Make sure that it does not always print an error when it could not resolve
|
||||
// a variable
|
||||
tmpl.tmpl.errorHandler = () => { };
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
tmpl.tmpl.errorHandler = () => {};
|
||||
|
||||
export class Expression {
|
||||
|
||||
workflow: Workflow;
|
||||
|
||||
constructor(workflow: Workflow) {
|
||||
this.workflow = workflow;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts an object to a string in a way to make it clear that
|
||||
* the value comes from an object
|
||||
@@ -44,8 +44,6 @@ export class Expression {
|
||||
return `[${typeName}: ${JSON.stringify(value)}]`;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Resolves the paramter value. If it is an expression it will execute it and
|
||||
* return the result. For everything simply the supplied value will be returned.
|
||||
@@ -60,7 +58,19 @@ export class Expression {
|
||||
* @returns {(NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[])}
|
||||
* @memberof Workflow
|
||||
*/
|
||||
resolveSimpleParameterValue(parameterValue: NodeParameterValue, siblingParameters: INodeParameters, runExecutionData: IRunExecutionData | null, runIndex: number, itemIndex: number, activeNodeName: string, connectionInputData: INodeExecutionData[], mode: WorkflowExecuteMode, additionalKeys: IWorkflowDataProxyAdditionalKeys, returnObjectAsString = false, selfData = {}): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] {
|
||||
resolveSimpleParameterValue(
|
||||
parameterValue: NodeParameterValue,
|
||||
siblingParameters: INodeParameters,
|
||||
runExecutionData: IRunExecutionData | null,
|
||||
runIndex: number,
|
||||
itemIndex: number,
|
||||
activeNodeName: string,
|
||||
connectionInputData: INodeExecutionData[],
|
||||
mode: WorkflowExecuteMode,
|
||||
additionalKeys: IWorkflowDataProxyAdditionalKeys,
|
||||
returnObjectAsString = false,
|
||||
selfData = {},
|
||||
): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] {
|
||||
// Check if it is an expression
|
||||
if (typeof parameterValue !== 'string' || parameterValue.charAt(0) !== '=') {
|
||||
// Is no expression so return value
|
||||
@@ -70,30 +80,44 @@ export class Expression {
|
||||
// Is an expression
|
||||
|
||||
// Remove the equal sign
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
parameterValue = parameterValue.substr(1);
|
||||
|
||||
// Generate a data proxy which allows to query workflow data
|
||||
const dataProxy = new WorkflowDataProxy(this.workflow, runExecutionData, runIndex, itemIndex, activeNodeName, connectionInputData, siblingParameters, mode, additionalKeys, -1, selfData);
|
||||
const dataProxy = new WorkflowDataProxy(
|
||||
this.workflow,
|
||||
runExecutionData,
|
||||
runIndex,
|
||||
itemIndex,
|
||||
activeNodeName,
|
||||
connectionInputData,
|
||||
siblingParameters,
|
||||
mode,
|
||||
additionalKeys,
|
||||
-1,
|
||||
selfData,
|
||||
);
|
||||
const data = dataProxy.getDataProxy();
|
||||
|
||||
// Execute the expression
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
|
||||
const returnValue = tmpl.tmpl(parameterValue, data);
|
||||
if (typeof returnValue === 'function') {
|
||||
throw new Error('Expression resolved to a function. Please add "()"');
|
||||
} else if (returnValue !== null && typeof returnValue === 'object') {
|
||||
if (returnObjectAsString === true) {
|
||||
if (returnObjectAsString) {
|
||||
return this.convertObjectValueToString(returnValue);
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return returnValue;
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-unsafe-member-access
|
||||
throw new Error(`Expression is not valid: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Resolves value of parameter. But does not work for workflow-data.
|
||||
*
|
||||
@@ -103,7 +127,13 @@ export class Expression {
|
||||
* @returns {(string | undefined)}
|
||||
* @memberof Workflow
|
||||
*/
|
||||
getSimpleParameterValue(node: INode, parameterValue: string | boolean | undefined, mode: WorkflowExecuteMode, additionalKeys: IWorkflowDataProxyAdditionalKeys, defaultValue?: boolean | number | string): boolean | number | string | undefined {
|
||||
getSimpleParameterValue(
|
||||
node: INode,
|
||||
parameterValue: string | boolean | undefined,
|
||||
mode: WorkflowExecuteMode,
|
||||
additionalKeys: IWorkflowDataProxyAdditionalKeys,
|
||||
defaultValue?: boolean | number | string,
|
||||
): boolean | number | string | undefined {
|
||||
if (parameterValue === undefined) {
|
||||
// Value is not set so return the default
|
||||
return defaultValue;
|
||||
@@ -119,11 +149,18 @@ export class Expression {
|
||||
},
|
||||
};
|
||||
|
||||
return this.getParameterValue(parameterValue, runData, runIndex, itemIndex, node.name, connectionInputData, mode, additionalKeys) as boolean | number | string | undefined;
|
||||
return this.getParameterValue(
|
||||
parameterValue,
|
||||
runData,
|
||||
runIndex,
|
||||
itemIndex,
|
||||
node.name,
|
||||
connectionInputData,
|
||||
mode,
|
||||
additionalKeys,
|
||||
) as boolean | number | string | undefined;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Resolves value of complex parameter. But does not work for workflow-data.
|
||||
*
|
||||
@@ -133,7 +170,19 @@ export class Expression {
|
||||
* @returns {(NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | undefined)}
|
||||
* @memberof Workflow
|
||||
*/
|
||||
getComplexParameterValue(node: INode, parameterValue: NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[], mode: WorkflowExecuteMode, additionalKeys: IWorkflowDataProxyAdditionalKeys, defaultValue: NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | undefined = undefined, selfData = {}): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | undefined {
|
||||
getComplexParameterValue(
|
||||
node: INode,
|
||||
parameterValue: NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[],
|
||||
mode: WorkflowExecuteMode,
|
||||
additionalKeys: IWorkflowDataProxyAdditionalKeys,
|
||||
defaultValue:
|
||||
| NodeParameterValue
|
||||
| INodeParameters
|
||||
| NodeParameterValue[]
|
||||
| INodeParameters[]
|
||||
| undefined = undefined,
|
||||
selfData = {},
|
||||
): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | undefined {
|
||||
if (parameterValue === undefined) {
|
||||
// Value is not set so return the default
|
||||
return defaultValue;
|
||||
@@ -150,14 +199,34 @@ export class Expression {
|
||||
};
|
||||
|
||||
// Resolve the "outer" main values
|
||||
const returnData = this.getParameterValue(parameterValue, runData, runIndex, itemIndex, node.name, connectionInputData, mode, additionalKeys, false, selfData);
|
||||
const returnData = this.getParameterValue(
|
||||
parameterValue,
|
||||
runData,
|
||||
runIndex,
|
||||
itemIndex,
|
||||
node.name,
|
||||
connectionInputData,
|
||||
mode,
|
||||
additionalKeys,
|
||||
false,
|
||||
selfData,
|
||||
);
|
||||
|
||||
// Resolve the "inner" values
|
||||
return this.getParameterValue(returnData, runData, runIndex, itemIndex, node.name, connectionInputData, mode, additionalKeys, false, selfData);
|
||||
return this.getParameterValue(
|
||||
returnData,
|
||||
runData,
|
||||
runIndex,
|
||||
itemIndex,
|
||||
node.name,
|
||||
connectionInputData,
|
||||
mode,
|
||||
additionalKeys,
|
||||
false,
|
||||
selfData,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the resolved node parameter value. If it is an expression it will execute it and
|
||||
* return the result. If the value to resolve is an array or object it will do the same
|
||||
@@ -173,24 +242,74 @@ export class Expression {
|
||||
* @returns {(NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[])}
|
||||
* @memberof Workflow
|
||||
*/
|
||||
getParameterValue(parameterValue: NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[], runExecutionData: IRunExecutionData | null, runIndex: number, itemIndex: number, activeNodeName: string, connectionInputData: INodeExecutionData[], mode: WorkflowExecuteMode, additionalKeys: IWorkflowDataProxyAdditionalKeys, returnObjectAsString = false, selfData = {}): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] {
|
||||
getParameterValue(
|
||||
parameterValue: NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[],
|
||||
runExecutionData: IRunExecutionData | null,
|
||||
runIndex: number,
|
||||
itemIndex: number,
|
||||
activeNodeName: string,
|
||||
connectionInputData: INodeExecutionData[],
|
||||
mode: WorkflowExecuteMode,
|
||||
additionalKeys: IWorkflowDataProxyAdditionalKeys,
|
||||
returnObjectAsString = false,
|
||||
selfData = {},
|
||||
): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] {
|
||||
// Helper function which returns true when the parameter is a complex one or array
|
||||
const isComplexParameter = (value: NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[]) => {
|
||||
const isComplexParameter = (
|
||||
value: NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[],
|
||||
) => {
|
||||
return typeof value === 'object';
|
||||
};
|
||||
|
||||
// Helper function which resolves a parameter value depending on if it is simply or not
|
||||
const resolveParameterValue = (value: NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[], siblingParameters: INodeParameters) => {
|
||||
const resolveParameterValue = (
|
||||
value: NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[],
|
||||
siblingParameters: INodeParameters,
|
||||
) => {
|
||||
if (isComplexParameter(value)) {
|
||||
return this.getParameterValue(value, runExecutionData, runIndex, itemIndex, activeNodeName, connectionInputData, mode, additionalKeys, returnObjectAsString, selfData);
|
||||
} else {
|
||||
return this.resolveSimpleParameterValue(value as NodeParameterValue, siblingParameters, runExecutionData, runIndex, itemIndex, activeNodeName, connectionInputData, mode, additionalKeys, returnObjectAsString, selfData);
|
||||
return this.getParameterValue(
|
||||
value,
|
||||
runExecutionData,
|
||||
runIndex,
|
||||
itemIndex,
|
||||
activeNodeName,
|
||||
connectionInputData,
|
||||
mode,
|
||||
additionalKeys,
|
||||
returnObjectAsString,
|
||||
selfData,
|
||||
);
|
||||
}
|
||||
return this.resolveSimpleParameterValue(
|
||||
value as NodeParameterValue,
|
||||
siblingParameters,
|
||||
runExecutionData,
|
||||
runIndex,
|
||||
itemIndex,
|
||||
activeNodeName,
|
||||
connectionInputData,
|
||||
mode,
|
||||
additionalKeys,
|
||||
returnObjectAsString,
|
||||
selfData,
|
||||
);
|
||||
};
|
||||
|
||||
// Check if it value is a simple one that we can get it resolved directly
|
||||
if (!isComplexParameter(parameterValue)) {
|
||||
return this.resolveSimpleParameterValue(parameterValue as NodeParameterValue, {}, runExecutionData, runIndex, itemIndex, activeNodeName, connectionInputData, mode, additionalKeys, returnObjectAsString, selfData);
|
||||
return this.resolveSimpleParameterValue(
|
||||
parameterValue as NodeParameterValue,
|
||||
{},
|
||||
runExecutionData,
|
||||
runIndex,
|
||||
itemIndex,
|
||||
activeNodeName,
|
||||
connectionInputData,
|
||||
mode,
|
||||
additionalKeys,
|
||||
returnObjectAsString,
|
||||
selfData,
|
||||
);
|
||||
}
|
||||
|
||||
// The parameter value is complex so resolve depending on type
|
||||
@@ -198,28 +317,33 @@ export class Expression {
|
||||
if (Array.isArray(parameterValue)) {
|
||||
// Data is an array
|
||||
const returnData = [];
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const item of parameterValue) {
|
||||
returnData.push(resolveParameterValue(item, {}));
|
||||
}
|
||||
|
||||
if (returnObjectAsString === true && typeof returnData === 'object') {
|
||||
if (returnObjectAsString && typeof returnData === 'object') {
|
||||
return this.convertObjectValueToString(returnData);
|
||||
}
|
||||
|
||||
return returnData as NodeParameterValue[] | INodeParameters[];
|
||||
} else if (parameterValue === null || parameterValue === undefined) {
|
||||
return parameterValue;
|
||||
} else {
|
||||
// Data is an object
|
||||
const returnData: INodeParameters = {};
|
||||
for (const key of Object.keys(parameterValue)) {
|
||||
returnData[key] = resolveParameterValue((parameterValue as INodeParameters)[key], parameterValue as INodeParameters);
|
||||
}
|
||||
|
||||
if (returnObjectAsString === true && typeof returnData === 'object') {
|
||||
return this.convertObjectValueToString(returnData);
|
||||
}
|
||||
return returnData;
|
||||
}
|
||||
if (parameterValue === null || parameterValue === undefined) {
|
||||
return parameterValue;
|
||||
}
|
||||
// Data is an object
|
||||
const returnData: INodeParameters = {};
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const key of Object.keys(parameterValue)) {
|
||||
returnData[key] = resolveParameterValue(
|
||||
(parameterValue as INodeParameters)[key],
|
||||
parameterValue as INodeParameters,
|
||||
);
|
||||
}
|
||||
|
||||
if (returnObjectAsString && typeof returnData === 'object') {
|
||||
return this.convertObjectValueToString(returnData);
|
||||
}
|
||||
return returnData;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,22 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
/* eslint-disable import/no-cycle */
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
// eslint-disable-next-line max-classes-per-file
|
||||
import * as express from 'express';
|
||||
import { Workflow } from './Workflow';
|
||||
import { WorkflowHooks } from './WorkflowHooks';
|
||||
import { WorkflowOperationError } from './WorkflowErrors';
|
||||
import { NodeApiError, NodeOperationError } from './NodeErrors';
|
||||
import * as express from 'express';
|
||||
|
||||
export type IAllExecuteFunctions = IExecuteFunctions | IExecuteSingleFunctions | IHookFunctions | ILoadOptionsFunctions | IPollFunctions | ITriggerFunctions | IWebhookFunctions;
|
||||
export type IAllExecuteFunctions =
|
||||
| IExecuteFunctions
|
||||
| IExecuteSingleFunctions
|
||||
| IHookFunctions
|
||||
| ILoadOptionsFunctions
|
||||
| IPollFunctions
|
||||
| ITriggerFunctions
|
||||
| IWebhookFunctions;
|
||||
|
||||
export interface IBinaryData {
|
||||
[key: string]: string | undefined;
|
||||
@@ -43,8 +55,11 @@ export interface IGetCredentials {
|
||||
|
||||
export abstract class ICredentials {
|
||||
name: string;
|
||||
|
||||
type: string;
|
||||
|
||||
data: string | undefined;
|
||||
|
||||
nodesAccess: ICredentialNodeAccess[];
|
||||
|
||||
constructor(name: string, type: string, nodesAccess: ICredentialNodeAccess[], data?: string) {
|
||||
@@ -55,10 +70,15 @@ export abstract class ICredentials {
|
||||
}
|
||||
|
||||
abstract getData(encryptionKey: string, nodeType?: string): ICredentialDataDecryptedObject;
|
||||
|
||||
abstract getDataKey(key: string, encryptionKey: string, nodeType?: string): CredentialInformation;
|
||||
|
||||
abstract getDataToSave(): ICredentialsEncrypted;
|
||||
|
||||
abstract hasNodeAccess(nodeType: string): boolean;
|
||||
|
||||
abstract setData(data: ICredentialDataDecryptedObject, encryptionKey: string): void;
|
||||
|
||||
abstract setDataKey(key: string, data: CredentialInformation, encryptionKey: string): void;
|
||||
}
|
||||
|
||||
@@ -101,8 +121,20 @@ export abstract class ICredentialsHelper {
|
||||
}
|
||||
|
||||
abstract getCredentials(name: string, type: string): Promise<ICredentials>;
|
||||
abstract getDecrypted(name: string, type: string, mode: WorkflowExecuteMode, raw?: boolean, expressionResolveValues?: ICredentialsExpressionResolveValues): Promise<ICredentialDataDecryptedObject>;
|
||||
abstract updateCredentials(name: string, type: string, data: ICredentialDataDecryptedObject): Promise<void>;
|
||||
|
||||
abstract getDecrypted(
|
||||
name: string,
|
||||
type: string,
|
||||
mode: WorkflowExecuteMode,
|
||||
raw?: boolean,
|
||||
expressionResolveValues?: ICredentialsExpressionResolveValues,
|
||||
): Promise<ICredentialDataDecryptedObject>;
|
||||
|
||||
abstract updateCredentials(
|
||||
name: string,
|
||||
type: string,
|
||||
data: ICredentialDataDecryptedObject,
|
||||
): Promise<void>;
|
||||
}
|
||||
|
||||
export interface ICredentialType {
|
||||
@@ -116,7 +148,7 @@ export interface ICredentialType {
|
||||
|
||||
export interface ICredentialTypes {
|
||||
credentialTypes?: {
|
||||
[key: string]: ICredentialType
|
||||
[key: string]: ICredentialType;
|
||||
};
|
||||
init(credentialTypes?: { [key: string]: ICredentialType }): Promise<void>;
|
||||
getAll(): ICredentialType[];
|
||||
@@ -133,7 +165,6 @@ export interface ICredentialData {
|
||||
// The encrypted credentials which the nodes can access
|
||||
export type CredentialInformation = string | number | boolean | IDataObject;
|
||||
|
||||
|
||||
// The encrypted credentials which the nodes can access
|
||||
export interface ICredentialDataDecryptedObject {
|
||||
[key: string]: CredentialInformation;
|
||||
@@ -159,92 +190,150 @@ export interface IDataObject {
|
||||
[key: string]: GenericValue | IDataObject | GenericValue[] | IDataObject[];
|
||||
}
|
||||
|
||||
|
||||
export interface IGetExecutePollFunctions {
|
||||
(workflow: Workflow, node: INode, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode, activation: WorkflowActivateMode): IPollFunctions;
|
||||
(
|
||||
workflow: Workflow,
|
||||
node: INode,
|
||||
additionalData: IWorkflowExecuteAdditionalData,
|
||||
mode: WorkflowExecuteMode,
|
||||
activation: WorkflowActivateMode,
|
||||
): IPollFunctions;
|
||||
}
|
||||
|
||||
export interface IGetExecuteTriggerFunctions {
|
||||
(workflow: Workflow, node: INode, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode, activation: WorkflowActivateMode): ITriggerFunctions;
|
||||
(
|
||||
workflow: Workflow,
|
||||
node: INode,
|
||||
additionalData: IWorkflowExecuteAdditionalData,
|
||||
mode: WorkflowExecuteMode,
|
||||
activation: WorkflowActivateMode,
|
||||
): ITriggerFunctions;
|
||||
}
|
||||
|
||||
|
||||
export interface IGetExecuteFunctions {
|
||||
(workflow: Workflow, runExecutionData: IRunExecutionData, runIndex: number, connectionInputData: INodeExecutionData[], inputData: ITaskDataConnections, node: INode, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode): IExecuteFunctions;
|
||||
(
|
||||
workflow: Workflow,
|
||||
runExecutionData: IRunExecutionData,
|
||||
runIndex: number,
|
||||
connectionInputData: INodeExecutionData[],
|
||||
inputData: ITaskDataConnections,
|
||||
node: INode,
|
||||
additionalData: IWorkflowExecuteAdditionalData,
|
||||
mode: WorkflowExecuteMode,
|
||||
): IExecuteFunctions;
|
||||
}
|
||||
|
||||
|
||||
export interface IGetExecuteSingleFunctions {
|
||||
(workflow: Workflow, runExecutionData: IRunExecutionData, runIndex: number, connectionInputData: INodeExecutionData[], inputData: ITaskDataConnections, node: INode, itemIndex: number, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode): IExecuteSingleFunctions;
|
||||
(
|
||||
workflow: Workflow,
|
||||
runExecutionData: IRunExecutionData,
|
||||
runIndex: number,
|
||||
connectionInputData: INodeExecutionData[],
|
||||
inputData: ITaskDataConnections,
|
||||
node: INode,
|
||||
itemIndex: number,
|
||||
additionalData: IWorkflowExecuteAdditionalData,
|
||||
mode: WorkflowExecuteMode,
|
||||
): IExecuteSingleFunctions;
|
||||
}
|
||||
|
||||
|
||||
export interface IGetExecuteHookFunctions {
|
||||
(workflow: Workflow, node: INode, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode, activation: WorkflowActivateMode, isTest?: boolean, webhookData?: IWebhookData): IHookFunctions;
|
||||
(
|
||||
workflow: Workflow,
|
||||
node: INode,
|
||||
additionalData: IWorkflowExecuteAdditionalData,
|
||||
mode: WorkflowExecuteMode,
|
||||
activation: WorkflowActivateMode,
|
||||
isTest?: boolean,
|
||||
webhookData?: IWebhookData,
|
||||
): IHookFunctions;
|
||||
}
|
||||
|
||||
|
||||
export interface IGetExecuteWebhookFunctions {
|
||||
(workflow: Workflow, node: INode, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode, webhookData: IWebhookData): IWebhookFunctions;
|
||||
(
|
||||
workflow: Workflow,
|
||||
node: INode,
|
||||
additionalData: IWorkflowExecuteAdditionalData,
|
||||
mode: WorkflowExecuteMode,
|
||||
webhookData: IWebhookData,
|
||||
): IWebhookFunctions;
|
||||
}
|
||||
|
||||
|
||||
export interface IExecuteData {
|
||||
data: ITaskDataConnections;
|
||||
node: INode;
|
||||
}
|
||||
|
||||
export type IContextObject = {
|
||||
[key: string]: any; // tslint:disable-line:no-any
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
|
||||
export interface IExecuteContextData {
|
||||
// Keys are: "flow" | "node:<NODE_NAME>"
|
||||
[key: string]: IContextObject;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
evaluateExpression(
|
||||
expression: string,
|
||||
itemIndex: number,
|
||||
): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[];
|
||||
executeWorkflow(
|
||||
workflowInfo: IExecuteWorkflowInfo,
|
||||
inputData?: INodeExecutionData[],
|
||||
): Promise<any>;
|
||||
getContext(type: string): IContextObject;
|
||||
getCredentials(type: string, itemIndex?: number): Promise<ICredentialDataDecryptedObject | undefined>;
|
||||
getCredentials(
|
||||
type: string,
|
||||
itemIndex?: number,
|
||||
): Promise<ICredentialDataDecryptedObject | undefined>;
|
||||
getInputData(inputIndex?: number, inputName?: string): INodeExecutionData[];
|
||||
getMode(): WorkflowExecuteMode;
|
||||
getNode(): INode;
|
||||
getNodeParameter(parameterName: string, itemIndex: number, fallbackValue?: any): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object; //tslint:disable-line:no-any
|
||||
getNodeParameter(
|
||||
parameterName: string,
|
||||
itemIndex: number,
|
||||
fallbackValue?: any,
|
||||
): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object;
|
||||
getWorkflowDataProxy(itemIndex: number): IWorkflowDataProxyData;
|
||||
getWorkflowStaticData(type: string): IDataObject;
|
||||
getRestApiUrl(): string;
|
||||
getTimezone(): string;
|
||||
getWorkflow(): IWorkflowMetadata;
|
||||
prepareOutputData(outputData: INodeExecutionData[], outputIndex?: number): Promise<INodeExecutionData[][]>;
|
||||
prepareOutputData(
|
||||
outputData: INodeExecutionData[],
|
||||
outputIndex?: number,
|
||||
): Promise<INodeExecutionData[][]>;
|
||||
putExecutionToWait(waitTill: Date): Promise<void>;
|
||||
sendMessageToUI(message: any): void; // tslint:disable-line:no-any
|
||||
helpers: {
|
||||
[key: string]: (...args: any[]) => any //tslint:disable-line:no-any
|
||||
[key: string]: (...args: any[]) => any;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export interface IExecuteSingleFunctions {
|
||||
continueOnFail(): boolean;
|
||||
evaluateExpression(expression: string, itemIndex: number | undefined): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[];
|
||||
evaluateExpression(
|
||||
expression: string,
|
||||
itemIndex: number | undefined,
|
||||
): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[];
|
||||
getContext(type: string): IContextObject;
|
||||
getCredentials(type: string): Promise<ICredentialDataDecryptedObject | undefined>;
|
||||
getInputData(inputIndex?: number, inputName?: string): INodeExecutionData;
|
||||
getMode(): WorkflowExecuteMode;
|
||||
getNode(): INode;
|
||||
getNodeParameter(parameterName: string, fallbackValue?: any): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object; //tslint:disable-line:no-any
|
||||
getNodeParameter(
|
||||
parameterName: string,
|
||||
fallbackValue?: any,
|
||||
): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object;
|
||||
getRestApiUrl(): string;
|
||||
getTimezone(): string;
|
||||
getWorkflow(): IWorkflowMetadata;
|
||||
getWorkflowDataProxy(): IWorkflowDataProxyData;
|
||||
getWorkflowStaticData(type: string): IDataObject;
|
||||
helpers: {
|
||||
[key: string]: (...args: any[]) => any //tslint:disable-line:no-any
|
||||
[key: string]: (...args: any[]) => any;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -256,13 +345,24 @@ export interface IExecuteWorkflowInfo {
|
||||
export interface ILoadOptionsFunctions {
|
||||
getCredentials(type: string): Promise<ICredentialDataDecryptedObject | undefined>;
|
||||
getNode(): INode;
|
||||
getNodeParameter(parameterName: string, fallbackValue?: any): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object; //tslint:disable-line:no-any
|
||||
getCurrentNodeParameter(parameterName: string): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object | undefined;
|
||||
getNodeParameter(
|
||||
parameterName: string,
|
||||
fallbackValue?: any,
|
||||
): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object;
|
||||
getCurrentNodeParameter(
|
||||
parameterName: string,
|
||||
):
|
||||
| NodeParameterValue
|
||||
| INodeParameters
|
||||
| NodeParameterValue[]
|
||||
| INodeParameters[]
|
||||
| object
|
||||
| undefined;
|
||||
getCurrentNodeParameters(): INodeParameters | undefined;
|
||||
getTimezone(): string;
|
||||
getRestApiUrl(): string;
|
||||
helpers: {
|
||||
[key: string]: ((...args: any[]) => any) | undefined; //tslint:disable-line:no-any
|
||||
[key: string]: ((...args: any[]) => any) | undefined;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -272,14 +372,17 @@ export interface IHookFunctions {
|
||||
getActivationMode(): WorkflowActivateMode;
|
||||
getNode(): INode;
|
||||
getNodeWebhookUrl: (name: string) => string | undefined;
|
||||
getNodeParameter(parameterName: string, fallbackValue?: any): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object; //tslint:disable-line:no-any
|
||||
getNodeParameter(
|
||||
parameterName: string,
|
||||
fallbackValue?: any,
|
||||
): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object;
|
||||
getTimezone(): string;
|
||||
getWebhookDescription(name: string): IWebhookDescription | undefined;
|
||||
getWebhookName(): string;
|
||||
getWorkflow(): IWorkflowMetadata;
|
||||
getWorkflowStaticData(type: string): IDataObject;
|
||||
helpers: {
|
||||
[key: string]: (...args: any[]) => any //tslint:disable-line:no-any
|
||||
[key: string]: (...args: any[]) => any;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -289,13 +392,16 @@ export interface IPollFunctions {
|
||||
getMode(): WorkflowExecuteMode;
|
||||
getActivationMode(): WorkflowActivateMode;
|
||||
getNode(): INode;
|
||||
getNodeParameter(parameterName: string, fallbackValue?: any): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object; //tslint:disable-line:no-any
|
||||
getNodeParameter(
|
||||
parameterName: string,
|
||||
fallbackValue?: any,
|
||||
): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object;
|
||||
getRestApiUrl(): string;
|
||||
getTimezone(): string;
|
||||
getWorkflow(): IWorkflowMetadata;
|
||||
getWorkflowStaticData(type: string): IDataObject;
|
||||
helpers: {
|
||||
[key: string]: (...args: any[]) => any //tslint:disable-line:no-any
|
||||
[key: string]: (...args: any[]) => any;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -305,13 +411,16 @@ export interface ITriggerFunctions {
|
||||
getMode(): WorkflowExecuteMode;
|
||||
getActivationMode(): WorkflowActivateMode;
|
||||
getNode(): INode;
|
||||
getNodeParameter(parameterName: string, fallbackValue?: any): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object; //tslint:disable-line:no-any
|
||||
getNodeParameter(
|
||||
parameterName: string,
|
||||
fallbackValue?: any,
|
||||
): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object;
|
||||
getRestApiUrl(): string;
|
||||
getTimezone(): string;
|
||||
getWorkflow(): IWorkflowMetadata;
|
||||
getWorkflowStaticData(type: string): IDataObject;
|
||||
helpers: {
|
||||
[key: string]: (...args: any[]) => any //tslint:disable-line:no-any
|
||||
[key: string]: (...args: any[]) => any;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -321,7 +430,10 @@ export interface IWebhookFunctions {
|
||||
getHeaderData(): object;
|
||||
getMode(): WorkflowExecuteMode;
|
||||
getNode(): INode;
|
||||
getNodeParameter(parameterName: string, fallbackValue?: any): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object; //tslint:disable-line:no-any
|
||||
getNodeParameter(
|
||||
parameterName: string,
|
||||
fallbackValue?: any,
|
||||
): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] | object;
|
||||
getNodeWebhookUrl: (name: string) => string | undefined;
|
||||
getParamsData(): object;
|
||||
getQueryData(): object;
|
||||
@@ -331,9 +443,12 @@ export interface IWebhookFunctions {
|
||||
getWebhookName(): string;
|
||||
getWorkflowStaticData(type: string): IDataObject;
|
||||
getWorkflow(): IWorkflowMetadata;
|
||||
prepareOutputData(outputData: INodeExecutionData[], outputIndex?: number): Promise<INodeExecutionData[][]>;
|
||||
prepareOutputData(
|
||||
outputData: INodeExecutionData[],
|
||||
outputIndex?: number,
|
||||
): Promise<INodeExecutionData[][]>;
|
||||
helpers: {
|
||||
[key: string]: (...args: any[]) => any //tslint:disable-line:no-any
|
||||
[key: string]: (...args: any[]) => any;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -360,18 +475,15 @@ export interface INode {
|
||||
webhookId?: string;
|
||||
}
|
||||
|
||||
|
||||
export interface INodes {
|
||||
[key: string]: INode;
|
||||
}
|
||||
|
||||
|
||||
export interface IObservableObject {
|
||||
[key: string]: any; // tslint:disable-line:no-any
|
||||
[key: string]: any;
|
||||
__dataChanged: boolean;
|
||||
}
|
||||
|
||||
|
||||
export interface IBinaryKeyData {
|
||||
[key: string]: IBinaryData;
|
||||
}
|
||||
@@ -385,7 +497,6 @@ export interface INodeExecutionData {
|
||||
binary?: IBinaryKeyData;
|
||||
}
|
||||
|
||||
|
||||
export interface INodeExecuteFunctions {
|
||||
getExecutePollFunctions: IGetExecutePollFunctions;
|
||||
getExecuteTriggerFunctions: IGetExecuteTriggerFunctions;
|
||||
@@ -395,7 +506,6 @@ export interface INodeExecuteFunctions {
|
||||
getExecuteWebhookFunctions: IGetExecuteWebhookFunctions;
|
||||
}
|
||||
|
||||
|
||||
// The values a node property can have
|
||||
export type NodeParameterValue = string | number | boolean | undefined | null;
|
||||
|
||||
@@ -404,25 +514,37 @@ export interface INodeParameters {
|
||||
[key: string]: NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[];
|
||||
}
|
||||
|
||||
export type NodePropertyTypes = 'boolean' | 'collection' | 'color' | 'dateTime' | 'fixedCollection' | 'hidden' | 'json' | 'notice' | 'multiOptions' | 'number' | 'options' | 'string';
|
||||
export type NodePropertyTypes =
|
||||
| 'boolean'
|
||||
| 'collection'
|
||||
| 'color'
|
||||
| 'dateTime'
|
||||
| 'fixedCollection'
|
||||
| 'hidden'
|
||||
| 'json'
|
||||
| 'notice'
|
||||
| 'multiOptions'
|
||||
| 'number'
|
||||
| 'options'
|
||||
| 'string';
|
||||
|
||||
export type EditorTypes = 'code';
|
||||
|
||||
export interface INodePropertyTypeOptions {
|
||||
alwaysOpenEditWindow?: boolean; // Supported by: string
|
||||
editor?: EditorTypes; // Supported by: string
|
||||
loadOptionsDependsOn?: string[]; // Supported by: options
|
||||
loadOptionsMethod?: string; // Supported by: options
|
||||
maxValue?: number; // Supported by: number
|
||||
minValue?: number; // Supported by: number
|
||||
multipleValues?: boolean; // Supported by: <All>
|
||||
multipleValueButtonText?: string; // Supported when "multipleValues" set to true
|
||||
numberPrecision?: number; // Supported by: number
|
||||
numberStepSize?: number; // Supported by: number
|
||||
password?: boolean; // Supported by: string
|
||||
rows?: number; // Supported by: string
|
||||
showAlpha?: boolean; // Supported by: color
|
||||
sortable?: boolean; // Supported when "multipleValues" set to true
|
||||
editor?: EditorTypes; // Supported by: string
|
||||
loadOptionsDependsOn?: string[]; // Supported by: options
|
||||
loadOptionsMethod?: string; // Supported by: options
|
||||
maxValue?: number; // Supported by: number
|
||||
minValue?: number; // Supported by: number
|
||||
multipleValues?: boolean; // Supported by: <All>
|
||||
multipleValueButtonText?: string; // Supported when "multipleValues" set to true
|
||||
numberPrecision?: number; // Supported by: number
|
||||
numberStepSize?: number; // Supported by: number
|
||||
password?: boolean; // Supported by: string
|
||||
rows?: number; // Supported by: string
|
||||
showAlpha?: boolean; // Supported by: color
|
||||
sortable?: boolean; // Supported when "multipleValues" set to true
|
||||
[key: string]: boolean | number | string | EditorTypes | undefined | string[];
|
||||
}
|
||||
|
||||
@@ -435,7 +557,6 @@ export interface IDisplayOptions {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export interface INodeProperties {
|
||||
displayName: string;
|
||||
name: string;
|
||||
@@ -492,7 +613,7 @@ export interface INodeType {
|
||||
methods?: {
|
||||
loadOptions?: {
|
||||
[key: string]: (this: ILoadOptionsFunctions) => Promise<INodePropertyOptions[]>;
|
||||
}
|
||||
};
|
||||
};
|
||||
webhookMethods?: {
|
||||
[key: string]: IWebhookSetupMethods;
|
||||
@@ -501,7 +622,6 @@ export interface INodeType {
|
||||
|
||||
export type WebhookSetupMethodNames = 'checkExists' | 'create' | 'delete';
|
||||
|
||||
|
||||
export interface IWebhookSetupMethods {
|
||||
[key: string]: ((this: IHookFunctions) => Promise<boolean>) | undefined;
|
||||
checkExists?: (this: IHookFunctions) => Promise<boolean>;
|
||||
@@ -509,7 +629,6 @@ export interface IWebhookSetupMethods {
|
||||
delete?: (this: IHookFunctions) => Promise<boolean>;
|
||||
}
|
||||
|
||||
|
||||
export interface INodeCredentialDescription {
|
||||
name: string;
|
||||
required?: boolean;
|
||||
@@ -596,17 +715,17 @@ export interface IWebhookDescription {
|
||||
}
|
||||
|
||||
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
|
||||
$items: 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
|
||||
$position: any; // tslint:disable-line:no-any
|
||||
$workflow: any; // tslint:disable-line:no-any
|
||||
$binary: any;
|
||||
$data: any;
|
||||
$env: any;
|
||||
$evaluateExpression: any;
|
||||
$item: any;
|
||||
$items: any;
|
||||
$json: any;
|
||||
$node: any;
|
||||
$parameter: any;
|
||||
$position: any;
|
||||
$workflow: any;
|
||||
}
|
||||
|
||||
export interface IWorkflowDataProxyAdditionalKeys {
|
||||
@@ -623,7 +742,7 @@ export type WebhookHttpMethod = 'GET' | 'POST' | 'HEAD' | 'OPTIONS';
|
||||
|
||||
export interface IWebhookResponseData {
|
||||
workflowData?: INodeExecutionData[][];
|
||||
webhookResponse?: any; // tslint:disable-line:no-any
|
||||
webhookResponse?: any;
|
||||
noWebhookResponse?: boolean;
|
||||
}
|
||||
|
||||
@@ -637,7 +756,6 @@ export interface INodeTypes {
|
||||
getByName(nodeType: string): INodeType | undefined;
|
||||
}
|
||||
|
||||
|
||||
export interface INodeTypeData {
|
||||
[key: string]: {
|
||||
type: INodeType;
|
||||
@@ -654,7 +772,6 @@ export interface IRun {
|
||||
stoppedAt?: Date;
|
||||
}
|
||||
|
||||
|
||||
// Contains all the data which is needed to execute a workflow and so also to
|
||||
// start restart it again after it did fail.
|
||||
// The RunData, ExecuteData and WaitForExecution contain often the same data.
|
||||
@@ -676,13 +793,11 @@ export interface IRunExecutionData {
|
||||
waitTill?: Date;
|
||||
}
|
||||
|
||||
|
||||
export interface IRunData {
|
||||
// node-name: result-data
|
||||
[key: string]: ITaskData[];
|
||||
}
|
||||
|
||||
|
||||
// The data that gets returned when a node runs
|
||||
export interface ITaskData {
|
||||
startTime: number;
|
||||
@@ -691,7 +806,6 @@ export interface ITaskData {
|
||||
error?: ExecutionError;
|
||||
}
|
||||
|
||||
|
||||
// The data for al the different kind of connectons (like main) and all the indexes
|
||||
export interface ITaskDataConnections {
|
||||
// Key for each input type and because there can be multiple inputs of the same type it is an array
|
||||
@@ -700,20 +814,17 @@ export interface ITaskDataConnections {
|
||||
[key: string]: Array<INodeExecutionData[] | null>;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Keeps data while workflow gets executed and allows when provided to restart execution
|
||||
export interface IWaitingForExecution {
|
||||
// Node name
|
||||
[key: string]: {
|
||||
// Run index
|
||||
[key: number]: ITaskDataConnections
|
||||
[key: number]: ITaskDataConnections;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export interface IWorkflowBase {
|
||||
id?: number | string | any; // tslint:disable-line:no-any
|
||||
id?: number | string | any;
|
||||
name: string;
|
||||
active: boolean;
|
||||
createdAt: Date;
|
||||
@@ -732,26 +843,34 @@ export interface IWorkflowCredentials {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export interface IWorkflowExecuteHooks {
|
||||
[key: string]: Array<((...args: any[]) => Promise<void>)> | undefined; // tslint:disable-line:no-any
|
||||
nodeExecuteAfter?: Array<((nodeName: string, data: ITaskData, executionData: IRunExecutionData) => Promise<void>)>;
|
||||
nodeExecuteBefore?: Array<((nodeName: string) => Promise<void>)>;
|
||||
workflowExecuteAfter?: Array<((data: IRun, newStaticData: IDataObject) => Promise<void>)>;
|
||||
workflowExecuteBefore?: Array<((workflow: Workflow, data: IRunExecutionData) => Promise<void>)>;
|
||||
[key: string]: Array<(...args: any[]) => Promise<void>> | undefined;
|
||||
nodeExecuteAfter?: Array<
|
||||
(nodeName: string, data: ITaskData, executionData: IRunExecutionData) => Promise<void>
|
||||
>;
|
||||
nodeExecuteBefore?: Array<(nodeName: string) => Promise<void>>;
|
||||
workflowExecuteAfter?: Array<(data: IRun, newStaticData: IDataObject) => Promise<void>>;
|
||||
workflowExecuteBefore?: Array<(workflow: Workflow, data: IRunExecutionData) => Promise<void>>;
|
||||
}
|
||||
|
||||
export interface IWorkflowExecuteAdditionalData {
|
||||
credentialsHelper: ICredentialsHelper;
|
||||
encryptionKey: string;
|
||||
executeWorkflow: (workflowInfo: IExecuteWorkflowInfo, additionalData: IWorkflowExecuteAdditionalData, inputData?: INodeExecutionData[], parentExecutionId?: string, loadedWorkflowData?: IWorkflowBase, loadedRunData?: any) => Promise<any>; // tslint:disable-line:no-any
|
||||
executeWorkflow: (
|
||||
workflowInfo: IExecuteWorkflowInfo,
|
||||
additionalData: IWorkflowExecuteAdditionalData,
|
||||
inputData?: INodeExecutionData[],
|
||||
parentExecutionId?: string,
|
||||
loadedWorkflowData?: IWorkflowBase,
|
||||
loadedRunData?: any,
|
||||
) => Promise<any>;
|
||||
// hooks?: IWorkflowExecuteHooks;
|
||||
executionId?: string;
|
||||
hooks?: WorkflowHooks;
|
||||
httpResponse?: express.Response;
|
||||
httpRequest?: express.Request;
|
||||
restApiUrl: string;
|
||||
sendMessageToUI?: (source: string, message: any) => void; // tslint:disable-line:no-any
|
||||
sendMessageToUI?: (source: string, message: any) => void;
|
||||
timezone: string;
|
||||
webhookBaseUrl: string;
|
||||
webhookWaitingBaseUrl: string;
|
||||
@@ -760,7 +879,15 @@ export interface IWorkflowExecuteAdditionalData {
|
||||
executionTimeoutTimestamp?: number;
|
||||
}
|
||||
|
||||
export type WorkflowExecuteMode = 'cli' | 'error' | 'integrated' | 'internal' | 'manual' | 'retry' | 'trigger' | 'webhook';
|
||||
export type WorkflowExecuteMode =
|
||||
| 'cli'
|
||||
| 'error'
|
||||
| 'integrated'
|
||||
| 'internal'
|
||||
| 'manual'
|
||||
| 'retry'
|
||||
| 'trigger'
|
||||
| 'webhook';
|
||||
export type WorkflowActivateMode = 'init' | 'create' | 'update' | 'activate' | 'manual';
|
||||
|
||||
export interface IWorkflowHooksOptionalParameters {
|
||||
@@ -790,7 +917,7 @@ export interface IStatusCodeMessages {
|
||||
|
||||
export type CodexData = {
|
||||
categories?: string[];
|
||||
subcategories?: {[category: string]: string[]};
|
||||
subcategories?: { [category: string]: string[] };
|
||||
alias?: string[];
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import {
|
||||
ILogger,
|
||||
LogTypes,
|
||||
} from './Interfaces';
|
||||
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
import { ILogger, LogTypes } from './Interfaces';
|
||||
|
||||
let logger: ILogger | undefined;
|
||||
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
import { INode, IStatusCodeMessages, JsonObject} from '.';
|
||||
/* eslint-disable @typescript-eslint/no-shadow */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable no-param-reassign */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
// eslint-disable-next-line max-classes-per-file
|
||||
import { parseString } from 'xml2js';
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
import { INode, IStatusCodeMessages, JsonObject } from '.';
|
||||
|
||||
/**
|
||||
* Top-level properties where an error message can be found in an API response.
|
||||
@@ -33,7 +41,14 @@ const ERROR_MESSAGE_PROPERTIES = [
|
||||
/**
|
||||
* Top-level properties where an HTTP error code can be found in an API response.
|
||||
*/
|
||||
const ERROR_STATUS_PROPERTIES = ['statusCode', 'status', 'code', 'status_code', 'errorCode', 'error_code'];
|
||||
const ERROR_STATUS_PROPERTIES = [
|
||||
'statusCode',
|
||||
'status',
|
||||
'code',
|
||||
'status_code',
|
||||
'errorCode',
|
||||
'error_code',
|
||||
];
|
||||
|
||||
/**
|
||||
* Properties where a nested object can be found in an API response.
|
||||
@@ -46,8 +61,11 @@ const ERROR_NESTING_PROPERTIES = ['error', 'err', 'response', 'body', 'data'];
|
||||
*/
|
||||
abstract class NodeError extends Error {
|
||||
description: string | null | undefined;
|
||||
|
||||
cause: Error | JsonObject;
|
||||
|
||||
node: INode;
|
||||
|
||||
timestamp: number;
|
||||
|
||||
constructor(node: INode, error: Error | JsonObject) {
|
||||
@@ -95,13 +113,17 @@ abstract class NodeError extends Error {
|
||||
potentialKeys: string[],
|
||||
traversalKeys: string[] = [],
|
||||
): string | null {
|
||||
for(const key of potentialKeys) {
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const key of potentialKeys) {
|
||||
if (error[key]) {
|
||||
if (typeof error[key] === 'string') return error[key] as string;
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
if (typeof error[key] === 'number') return error[key]!.toString();
|
||||
if (Array.isArray(error[key])) {
|
||||
// @ts-ignore
|
||||
const resolvedErrors: string[] = error[key].map((error) => {
|
||||
const resolvedErrors: string[] = error[key]
|
||||
// @ts-ignore
|
||||
.map((error) => {
|
||||
if (typeof error === 'string') return error;
|
||||
if (typeof error === 'number') return error.toString();
|
||||
if (this.isTraversableObject(error)) {
|
||||
@@ -125,6 +147,7 @@ abstract class NodeError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const key of traversalKeys) {
|
||||
if (this.isTraversableObject(error[key])) {
|
||||
const property = this.findProperty(error[key] as JsonObject, potentialKeys, traversalKeys);
|
||||
@@ -140,18 +163,24 @@ abstract class NodeError extends Error {
|
||||
/**
|
||||
* Check if a value is an object with at least one key, i.e. it can be traversed.
|
||||
*/
|
||||
protected isTraversableObject(value: any): value is JsonObject { // tslint:disable-line:no-any
|
||||
return value && typeof value === 'object' && !Array.isArray(value) && !!Object.keys(value).length;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
protected isTraversableObject(value: any): value is JsonObject {
|
||||
return (
|
||||
value && typeof value === 'object' && !Array.isArray(value) && !!Object.keys(value).length
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove circular references from objects.
|
||||
*/
|
||||
protected removeCircularRefs(obj: JsonObject, seen = new Set()) {
|
||||
protected removeCircularRefs(obj: JsonObject, seen = new Set()) {
|
||||
seen.add(obj);
|
||||
Object.entries(obj).forEach(([key, value]) => {
|
||||
if (this.isTraversableObject(value)) {
|
||||
seen.has(value) ? obj[key] = { circularReference: true } : this.removeCircularRefs(value, seen);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||||
seen.has(value)
|
||||
? (obj[key] = { circularReference: true })
|
||||
: this.removeCircularRefs(value, seen);
|
||||
return;
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
@@ -173,7 +202,6 @@ abstract class NodeError extends Error {
|
||||
* Class for instantiating an operational error, e.g. an invalid credentials error.
|
||||
*/
|
||||
export class NodeOperationError extends NodeError {
|
||||
|
||||
constructor(node: INode, error: Error | string) {
|
||||
if (typeof error === 'string') {
|
||||
error = new Error(error);
|
||||
@@ -211,10 +239,16 @@ export class NodeApiError extends NodeError {
|
||||
constructor(
|
||||
node: INode,
|
||||
error: JsonObject,
|
||||
{ message, description, httpCode, parseXml }: { message?: string, description?: string, httpCode?: string, parseXml?: boolean } = {},
|
||||
{
|
||||
message,
|
||||
description,
|
||||
httpCode,
|
||||
parseXml,
|
||||
}: { message?: string; description?: string; httpCode?: string; parseXml?: boolean } = {},
|
||||
) {
|
||||
super(node, error);
|
||||
if (error.error) { // only for request library error
|
||||
if (error.error) {
|
||||
// only for request library error
|
||||
this.removeCircularRefs(error.error as JsonObject);
|
||||
}
|
||||
if (message) {
|
||||
@@ -236,11 +270,17 @@ export class NodeApiError extends NodeError {
|
||||
}
|
||||
|
||||
private setDescriptionFromXml(xml: string) {
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
parseString(xml, { explicitArray: false }, (_, result) => {
|
||||
if (!result) return;
|
||||
|
||||
const topLevelKey = Object.keys(result)[0];
|
||||
this.description = this.findProperty(result[topLevelKey], ERROR_MESSAGE_PROPERTIES, ['Error'].concat(ERROR_NESTING_PROPERTIES));
|
||||
this.description = this.findProperty(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
result[topLevelKey],
|
||||
ERROR_MESSAGE_PROPERTIES,
|
||||
['Error'].concat(ERROR_NESTING_PROPERTIES),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
/* eslint-disable no-console */
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
/* eslint-disable @typescript-eslint/no-use-before-define */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
|
||||
/* eslint-disable no-param-reassign */
|
||||
/* eslint-disable no-continue */
|
||||
/* eslint-disable prefer-spread */
|
||||
/* eslint-disable no-restricted-syntax */
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
/* eslint-disable import/no-cycle */
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import { get, isEqual } from 'lodash';
|
||||
|
||||
import {
|
||||
IContextObject,
|
||||
INode,
|
||||
@@ -17,13 +31,7 @@ import {
|
||||
WebhookHttpMethod,
|
||||
} from './Interfaces';
|
||||
|
||||
import {
|
||||
Workflow
|
||||
} from './Workflow';
|
||||
|
||||
import { get, isEqual } from 'lodash';
|
||||
|
||||
|
||||
import { Workflow } from './Workflow';
|
||||
|
||||
/**
|
||||
* Gets special parameters which should be added to nodeTypes depending
|
||||
@@ -99,12 +107,7 @@ export function getSpecialNodeParameters(nodeType: INodeType) {
|
||||
},
|
||||
displayOptions: {
|
||||
hide: {
|
||||
mode: [
|
||||
'custom',
|
||||
'everyHour',
|
||||
'everyMinute',
|
||||
'everyX',
|
||||
],
|
||||
mode: ['custom', 'everyHour', 'everyMinute', 'everyX'],
|
||||
},
|
||||
},
|
||||
default: 14,
|
||||
@@ -120,11 +123,7 @@ export function getSpecialNodeParameters(nodeType: INodeType) {
|
||||
},
|
||||
displayOptions: {
|
||||
hide: {
|
||||
mode: [
|
||||
'custom',
|
||||
'everyMinute',
|
||||
'everyX',
|
||||
],
|
||||
mode: ['custom', 'everyMinute', 'everyX'],
|
||||
},
|
||||
},
|
||||
default: 0,
|
||||
@@ -136,9 +135,7 @@ export function getSpecialNodeParameters(nodeType: INodeType) {
|
||||
type: 'number',
|
||||
displayOptions: {
|
||||
show: {
|
||||
mode: [
|
||||
'everyMonth',
|
||||
],
|
||||
mode: ['everyMonth'],
|
||||
},
|
||||
},
|
||||
typeOptions: {
|
||||
@@ -154,9 +151,7 @@ export function getSpecialNodeParameters(nodeType: INodeType) {
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
mode: [
|
||||
'everyWeek',
|
||||
],
|
||||
mode: ['everyWeek'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
@@ -198,13 +193,12 @@ export function getSpecialNodeParameters(nodeType: INodeType) {
|
||||
type: 'string',
|
||||
displayOptions: {
|
||||
show: {
|
||||
mode: [
|
||||
'custom',
|
||||
],
|
||||
mode: ['custom'],
|
||||
},
|
||||
},
|
||||
default: '* * * * * *',
|
||||
description: 'Use custom cron expression. Values and ranges as follows:<ul><li>Seconds: 0-59</li><li>Minutes: 0 - 59</li><li>Hours: 0 - 23</li><li>Day of Month: 1 - 31</li><li>Months: 0 - 11 (Jan - Dec)</li><li>Day of Week: 0 - 6 (Sun - Sat)</li></ul>',
|
||||
description:
|
||||
'Use custom cron expression. Values and ranges as follows:<ul><li>Seconds: 0-59</li><li>Minutes: 0 - 59</li><li>Hours: 0 - 23</li><li>Day of Month: 1 - 31</li><li>Months: 0 - 11 (Jan - Dec)</li><li>Day of Week: 0 - 6 (Sun - Sat)</li></ul>',
|
||||
},
|
||||
{
|
||||
displayName: 'Value',
|
||||
@@ -216,9 +210,7 @@ export function getSpecialNodeParameters(nodeType: INodeType) {
|
||||
},
|
||||
displayOptions: {
|
||||
show: {
|
||||
mode: [
|
||||
'everyX',
|
||||
],
|
||||
mode: ['everyX'],
|
||||
},
|
||||
},
|
||||
default: 2,
|
||||
@@ -230,9 +222,7 @@ export function getSpecialNodeParameters(nodeType: INodeType) {
|
||||
type: 'options',
|
||||
displayOptions: {
|
||||
show: {
|
||||
mode: [
|
||||
'everyX',
|
||||
],
|
||||
mode: ['everyX'],
|
||||
},
|
||||
},
|
||||
options: [
|
||||
@@ -258,7 +248,6 @@ export function getSpecialNodeParameters(nodeType: INodeType) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns if the parameter should be displayed or not
|
||||
*
|
||||
@@ -269,7 +258,11 @@ export function getSpecialNodeParameters(nodeType: INodeType) {
|
||||
* @param {INodeParameters} [nodeValuesRoot] The root node-parameter-data
|
||||
* @returns
|
||||
*/
|
||||
export function displayParameter(nodeValues: INodeParameters, parameter: INodeProperties | INodeCredentialDescription, nodeValuesRoot?: INodeParameters) {
|
||||
export function displayParameter(
|
||||
nodeValues: INodeParameters,
|
||||
parameter: INodeProperties | INodeCredentialDescription,
|
||||
nodeValuesRoot?: INodeParameters,
|
||||
) {
|
||||
if (!parameter.displayOptions) {
|
||||
return true;
|
||||
}
|
||||
@@ -277,7 +270,8 @@ export function displayParameter(nodeValues: INodeParameters, parameter: INodePr
|
||||
nodeValuesRoot = nodeValuesRoot || nodeValues;
|
||||
|
||||
let value;
|
||||
const values: any[] = []; // tslint:disable-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const values: any[] = [];
|
||||
if (parameter.displayOptions.show) {
|
||||
// All the defined rules have to match to display parameter
|
||||
for (const propertyName of Object.keys(parameter.displayOptions.show)) {
|
||||
@@ -296,11 +290,14 @@ export function displayParameter(nodeValues: INodeParameters, parameter: INodePr
|
||||
values.push.apply(values, value);
|
||||
}
|
||||
|
||||
if (values.some(v => (typeof v) === 'string' && (v as string).charAt(0) === '=')) {
|
||||
if (values.some((v) => typeof v === 'string' && v.charAt(0) === '=')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (values.length === 0 || !parameter.displayOptions.show[propertyName].some(v => values.includes(v))) {
|
||||
if (
|
||||
values.length === 0 ||
|
||||
!parameter.displayOptions.show[propertyName].some((v) => values.includes(v))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -324,7 +321,10 @@ export function displayParameter(nodeValues: INodeParameters, parameter: INodePr
|
||||
values.push.apply(values, value);
|
||||
}
|
||||
|
||||
if (values.length !== 0 && parameter.displayOptions.hide[propertyName].some(v => values.includes(v))) {
|
||||
if (
|
||||
values.length !== 0 &&
|
||||
parameter.displayOptions.hide[propertyName].some((v) => values.includes(v))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -333,7 +333,6 @@ export function displayParameter(nodeValues: INodeParameters, parameter: INodePr
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns if the given parameter should be displayed or not considering the path
|
||||
* to the properties
|
||||
@@ -345,28 +344,25 @@ export function displayParameter(nodeValues: INodeParameters, parameter: INodePr
|
||||
* @param {string} path The path to the property
|
||||
* @returns
|
||||
*/
|
||||
export function displayParameterPath(nodeValues: INodeParameters, parameter: INodeProperties | INodeCredentialDescription, path: string) {
|
||||
export function displayParameterPath(
|
||||
nodeValues: INodeParameters,
|
||||
parameter: INodeProperties | INodeCredentialDescription,
|
||||
path: string,
|
||||
) {
|
||||
let resolvedNodeValues = nodeValues;
|
||||
if (path !== '') {
|
||||
resolvedNodeValues = get(
|
||||
nodeValues,
|
||||
path,
|
||||
) as INodeParameters;
|
||||
resolvedNodeValues = get(nodeValues, path) as INodeParameters;
|
||||
}
|
||||
|
||||
// Get the root parameter data
|
||||
let nodeValuesRoot = nodeValues;
|
||||
if (path && path.split('.').indexOf('parameters') === 0) {
|
||||
nodeValuesRoot = get(
|
||||
nodeValues,
|
||||
'parameters',
|
||||
) as INodeParameters;
|
||||
nodeValuesRoot = get(nodeValues, 'parameters') as INodeParameters;
|
||||
}
|
||||
|
||||
return displayParameter(resolvedNodeValues, parameter, nodeValuesRoot);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the context data
|
||||
*
|
||||
@@ -376,7 +372,11 @@ export function displayParameterPath(nodeValues: INodeParameters, parameter: INo
|
||||
* @param {INode} [node] If type "node" is set the node to return the context of has to be supplied
|
||||
* @returns {IContextObject}
|
||||
*/
|
||||
export function getContext(runExecutionData: IRunExecutionData, type: string, node?: INode): IContextObject {
|
||||
export function getContext(
|
||||
runExecutionData: IRunExecutionData,
|
||||
type: string,
|
||||
node?: INode,
|
||||
): IContextObject {
|
||||
if (runExecutionData.executionData === undefined) {
|
||||
// TODO: Should not happen leave it for test now
|
||||
throw new Error('The "executionData" is not initialized!');
|
||||
@@ -395,13 +395,13 @@ export function getContext(runExecutionData: IRunExecutionData, type: string, no
|
||||
}
|
||||
|
||||
if (runExecutionData.executionData.contextData[key] === undefined) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
runExecutionData.executionData.contextData[key] = {};
|
||||
}
|
||||
|
||||
return runExecutionData.executionData.contextData[key];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns which parameters are dependent on which
|
||||
*
|
||||
@@ -409,7 +409,9 @@ export function getContext(runExecutionData: IRunExecutionData, type: string, no
|
||||
* @param {INodeProperties[]} nodePropertiesArray
|
||||
* @returns {IParameterDependencies}
|
||||
*/
|
||||
export function getParamterDependencies(nodePropertiesArray: INodeProperties[]): IParameterDependencies {
|
||||
export function getParamterDependencies(
|
||||
nodePropertiesArray: INodeProperties[],
|
||||
): IParameterDependencies {
|
||||
const dependencies: IParameterDependencies = {};
|
||||
|
||||
let displayRule: string;
|
||||
@@ -436,7 +438,6 @@ export function getParamterDependencies(nodePropertiesArray: INodeProperties[]):
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns in which order the parameters should be resolved
|
||||
* to have the parameters available they depend on
|
||||
@@ -446,7 +447,10 @@ export function getParamterDependencies(nodePropertiesArray: INodeProperties[]):
|
||||
* @param {IParameterDependencies} parameterDependencies
|
||||
* @returns {number[]}
|
||||
*/
|
||||
export function getParameterResolveOrder(nodePropertiesArray: INodeProperties[], parameterDependencies: IParameterDependencies): number[] {
|
||||
export function getParamterResolveOrder(
|
||||
nodePropertiesArray: INodeProperties[],
|
||||
parameterDependencies: IParameterDependencies,
|
||||
): number[] {
|
||||
const executionOrder: number[] = [];
|
||||
const indexToResolve = Array.from({ length: nodePropertiesArray.length }, (v, k) => k);
|
||||
const resolvedParamters: string[] = [];
|
||||
@@ -457,7 +461,7 @@ export function getParameterResolveOrder(nodePropertiesArray: INodeProperties[],
|
||||
let lastIndexLength = indexToResolve.length;
|
||||
let lastIndexReduction = -1;
|
||||
|
||||
let iterations = 0 ;
|
||||
let iterations = 0;
|
||||
|
||||
while (indexToResolve.length !== 0) {
|
||||
iterations += 1;
|
||||
@@ -495,7 +499,9 @@ export function getParameterResolveOrder(nodePropertiesArray: INodeProperties[],
|
||||
}
|
||||
|
||||
if (iterations > lastIndexReduction + nodePropertiesArray.length) {
|
||||
throw new Error('Could not resolve parameter depenencies. Max iterations reached! Hint: If `displayOptions` are specified in any child parameter of a parent `collection` or `fixedCollection`, remove the `displayOptions` from the child parameter.');
|
||||
throw new Error(
|
||||
'Could not resolve parameter depenencies. Max iterations reached! Hint: If `displayOptions` are specified in any child parameter of a parent `collection` or `fixedCollection`, remove the `displayOptions` from the child parameter.',
|
||||
);
|
||||
}
|
||||
lastIndexLength = indexToResolve.length;
|
||||
}
|
||||
@@ -503,7 +509,6 @@ export function getParameterResolveOrder(nodePropertiesArray: INodeProperties[],
|
||||
return executionOrder;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the node parameter values. Depending on the settings it either just returns the none
|
||||
* default values or it applies all the default values.
|
||||
@@ -518,7 +523,17 @@ export function getParameterResolveOrder(nodePropertiesArray: INodeProperties[],
|
||||
* @param {INodeParameters} [nodeValuesRoot] The root node-parameter-data
|
||||
* @returns {(INodeParameters | null)}
|
||||
*/
|
||||
export function getNodeParameters(nodePropertiesArray: INodeProperties[], nodeValues: INodeParameters, returnDefaults: boolean, returnNoneDisplayed: boolean, onlySimpleTypes = false, dataIsResolved = false, nodeValuesRoot?: INodeParameters, parentType?: string, parameterDependencies?: IParameterDependencies): INodeParameters | null {
|
||||
export function getNodeParameters(
|
||||
nodePropertiesArray: INodeProperties[],
|
||||
nodeValues: INodeParameters,
|
||||
returnDefaults: boolean,
|
||||
returnNoneDisplayed: boolean,
|
||||
onlySimpleTypes = false,
|
||||
dataIsResolved = false,
|
||||
nodeValuesRoot?: INodeParameters,
|
||||
parentType?: string,
|
||||
parameterDependencies?: IParameterDependencies,
|
||||
): INodeParameters | null {
|
||||
if (parameterDependencies === undefined) {
|
||||
parameterDependencies = getParamterDependencies(nodePropertiesArray);
|
||||
}
|
||||
@@ -541,27 +556,43 @@ export function getNodeParameters(nodePropertiesArray: INodeProperties[], nodeVa
|
||||
const nodeParametersFull: INodeParameters = {};
|
||||
|
||||
let nodeValuesDisplayCheck = nodeParametersFull;
|
||||
if (dataIsResolved !== true && returnNoneDisplayed === false) {
|
||||
nodeValuesDisplayCheck = getNodeParameters(nodePropertiesArray, nodeValues, true, true, true, true, nodeValuesRoot, parentType, parameterDependencies) as INodeParameters;
|
||||
if (!dataIsResolved && !returnNoneDisplayed) {
|
||||
nodeValuesDisplayCheck = getNodeParameters(
|
||||
nodePropertiesArray,
|
||||
nodeValues,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
nodeValuesRoot,
|
||||
parentType,
|
||||
parameterDependencies,
|
||||
) as INodeParameters;
|
||||
}
|
||||
|
||||
nodeValuesRoot = nodeValuesRoot || nodeValuesDisplayCheck;
|
||||
|
||||
// Go through the parameters in order of their dependencies
|
||||
const parameterItterationOrderIndex = getParameterResolveOrder(nodePropertiesArray, parameterDependencies);
|
||||
const parameterItterationOrderIndex = getParamterResolveOrder(
|
||||
nodePropertiesArray,
|
||||
parameterDependencies,
|
||||
);
|
||||
|
||||
for (const parameterIndex of parameterItterationOrderIndex) {
|
||||
const nodeProperties = nodePropertiesArray[parameterIndex];
|
||||
if (nodeValues[nodeProperties.name] === undefined && (returnDefaults === false || parentType === 'collection')) {
|
||||
if (
|
||||
nodeValues[nodeProperties.name] === undefined &&
|
||||
(!returnDefaults || parentType === 'collection')
|
||||
) {
|
||||
// The value is not defined so go to the next
|
||||
continue;
|
||||
}
|
||||
|
||||
if (returnNoneDisplayed === false && !displayParameter(nodeValuesDisplayCheck, nodeProperties, nodeValuesRoot)) {
|
||||
if (returnNoneDisplayed === false) {
|
||||
continue;
|
||||
}
|
||||
if (returnDefaults === false) {
|
||||
if (
|
||||
!returnNoneDisplayed &&
|
||||
!displayParameter(nodeValuesDisplayCheck, nodeProperties, nodeValuesRoot)
|
||||
) {
|
||||
if (!returnNoneDisplayed || !returnDefaults) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -575,19 +606,27 @@ export function getNodeParameters(nodePropertiesArray: INodeProperties[], nodeVa
|
||||
}
|
||||
}
|
||||
|
||||
if (returnDefaults === true) {
|
||||
if (returnDefaults) {
|
||||
// Set also when it has the default value
|
||||
if (['boolean', 'number', 'options'].includes(nodeProperties.type)) {
|
||||
// Boolean, numbers and options are special as false and 0 are valid values
|
||||
// and should not be replaced with default value
|
||||
nodeParameters[nodeProperties.name] = nodeValues[nodeProperties.name] !== undefined ? nodeValues[nodeProperties.name] : nodeProperties.default;
|
||||
nodeParameters[nodeProperties.name] =
|
||||
nodeValues[nodeProperties.name] !== undefined
|
||||
? nodeValues[nodeProperties.name]
|
||||
: nodeProperties.default;
|
||||
} else {
|
||||
nodeParameters[nodeProperties.name] = nodeValues[nodeProperties.name] || nodeProperties.default;
|
||||
nodeParameters[nodeProperties.name] =
|
||||
nodeValues[nodeProperties.name] || nodeProperties.default;
|
||||
}
|
||||
nodeParametersFull[nodeProperties.name] = nodeParameters[nodeProperties.name];
|
||||
} else if ((nodeValues[nodeProperties.name] !== nodeProperties.default && typeof nodeValues[nodeProperties.name] !== 'object') ||
|
||||
(typeof nodeValues[nodeProperties.name] === 'object' && !isEqual(nodeValues[nodeProperties.name], nodeProperties.default)) ||
|
||||
(nodeValues[nodeProperties.name] !== undefined && parentType === 'collection')) {
|
||||
} else if (
|
||||
(nodeValues[nodeProperties.name] !== nodeProperties.default &&
|
||||
typeof nodeValues[nodeProperties.name] !== 'object') ||
|
||||
(typeof nodeValues[nodeProperties.name] === 'object' &&
|
||||
!isEqual(nodeValues[nodeProperties.name], nodeProperties.default)) ||
|
||||
(nodeValues[nodeProperties.name] !== undefined && parentType === 'collection')
|
||||
) {
|
||||
// Set only if it is different to the default value
|
||||
nodeParameters[nodeProperties.name] = nodeValues[nodeProperties.name];
|
||||
nodeParametersFull[nodeProperties.name] = nodeParameters[nodeProperties.name];
|
||||
@@ -595,7 +634,7 @@ export function getNodeParameters(nodePropertiesArray: INodeProperties[], nodeVa
|
||||
}
|
||||
}
|
||||
|
||||
if (onlySimpleTypes === true) {
|
||||
if (onlySimpleTypes) {
|
||||
// It is only supposed to resolve the simple types. So continue.
|
||||
continue;
|
||||
}
|
||||
@@ -605,16 +644,21 @@ export function getNodeParameters(nodePropertiesArray: INodeProperties[], nodeVa
|
||||
if (nodeProperties.type === 'collection') {
|
||||
// Is collection
|
||||
|
||||
if (nodeProperties.typeOptions !== undefined && nodeProperties.typeOptions.multipleValues === true) {
|
||||
if (
|
||||
nodeProperties.typeOptions !== undefined &&
|
||||
nodeProperties.typeOptions.multipleValues === true
|
||||
) {
|
||||
// Multiple can be set so will be an array
|
||||
|
||||
// Return directly the values like they are
|
||||
if (nodeValues[nodeProperties.name] !== undefined) {
|
||||
nodeParameters[nodeProperties.name] = nodeValues[nodeProperties.name];
|
||||
} else if (returnDefaults === true) {
|
||||
} else if (returnDefaults) {
|
||||
// Does not have values defined but defaults should be returned
|
||||
if (Array.isArray(nodeProperties.default)) {
|
||||
nodeParameters[nodeProperties.name] = JSON.parse(JSON.stringify(nodeProperties.default));
|
||||
nodeParameters[nodeProperties.name] = JSON.parse(
|
||||
JSON.stringify(nodeProperties.default),
|
||||
);
|
||||
} else {
|
||||
// As it is probably wrong for many nodes, do we keep on returning an empty array if
|
||||
// anything else than an array is set as default
|
||||
@@ -622,20 +666,27 @@ export function getNodeParameters(nodePropertiesArray: INodeProperties[], nodeVa
|
||||
}
|
||||
}
|
||||
nodeParametersFull[nodeProperties.name] = nodeParameters[nodeProperties.name];
|
||||
} else {
|
||||
if (nodeValues[nodeProperties.name] !== undefined) {
|
||||
// Has values defined so get them
|
||||
const tempNodeParameters = getNodeParameters(nodeProperties.options as INodeProperties[], nodeValues[nodeProperties.name] as INodeParameters, returnDefaults, returnNoneDisplayed, false, false, nodeValuesRoot, nodeProperties.type);
|
||||
} else if (nodeValues[nodeProperties.name] !== undefined) {
|
||||
// Has values defined so get them
|
||||
const tempNodeParameters = getNodeParameters(
|
||||
nodeProperties.options as INodeProperties[],
|
||||
nodeValues[nodeProperties.name] as INodeParameters,
|
||||
returnDefaults,
|
||||
returnNoneDisplayed,
|
||||
false,
|
||||
false,
|
||||
nodeValuesRoot,
|
||||
nodeProperties.type,
|
||||
);
|
||||
|
||||
if (tempNodeParameters !== null) {
|
||||
nodeParameters[nodeProperties.name] = tempNodeParameters;
|
||||
nodeParametersFull[nodeProperties.name] = nodeParameters[nodeProperties.name];
|
||||
}
|
||||
} else if (returnDefaults === true) {
|
||||
// Does not have values defined but defaults should be returned
|
||||
nodeParameters[nodeProperties.name] = JSON.parse(JSON.stringify(nodeProperties.default));
|
||||
if (tempNodeParameters !== null) {
|
||||
nodeParameters[nodeProperties.name] = tempNodeParameters;
|
||||
nodeParametersFull[nodeProperties.name] = nodeParameters[nodeProperties.name];
|
||||
}
|
||||
} else if (returnDefaults) {
|
||||
// Does not have values defined but defaults should be returned
|
||||
nodeParameters[nodeProperties.name] = JSON.parse(JSON.stringify(nodeProperties.default));
|
||||
nodeParametersFull[nodeProperties.name] = nodeParameters[nodeProperties.name];
|
||||
}
|
||||
} else if (nodeProperties.type === 'fixedCollection') {
|
||||
// Is fixedCollection
|
||||
@@ -646,7 +697,7 @@ export function getNodeParameters(nodePropertiesArray: INodeProperties[], nodeVa
|
||||
let nodePropertyOptions: INodePropertyCollection | undefined;
|
||||
|
||||
let propertyValues = nodeValues[nodeProperties.name];
|
||||
if (returnDefaults === true) {
|
||||
if (returnDefaults) {
|
||||
if (propertyValues === undefined) {
|
||||
propertyValues = JSON.parse(JSON.stringify(nodeProperties.default));
|
||||
}
|
||||
@@ -654,20 +705,39 @@ export function getNodeParameters(nodePropertiesArray: INodeProperties[], nodeVa
|
||||
|
||||
// Iterate over all collections
|
||||
for (const itemName of Object.keys(propertyValues || {})) {
|
||||
if (nodeProperties.typeOptions !== undefined && nodeProperties.typeOptions.multipleValues === true) {
|
||||
if (
|
||||
nodeProperties.typeOptions !== undefined &&
|
||||
nodeProperties.typeOptions.multipleValues === true
|
||||
) {
|
||||
// Multiple can be set so will be an array
|
||||
|
||||
const tempArrayValue: INodeParameters[] = [];
|
||||
// Iterate over all items as it contains multiple ones
|
||||
for (const nodeValue of (propertyValues as INodeParameters)[itemName] as INodeParameters[]) {
|
||||
nodePropertyOptions = nodeProperties!.options!.find((nodePropertyOptions) => nodePropertyOptions.name === itemName) as INodePropertyCollection;
|
||||
for (const nodeValue of (propertyValues as INodeParameters)[
|
||||
itemName
|
||||
] as INodeParameters[]) {
|
||||
nodePropertyOptions = nodeProperties.options!.find(
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
(nodePropertyOptions) => nodePropertyOptions.name === itemName,
|
||||
) as INodePropertyCollection;
|
||||
|
||||
if (nodePropertyOptions === undefined) {
|
||||
throw new Error(`Could not find property option "${itemName}" for "${nodeProperties.name}"`);
|
||||
throw new Error(
|
||||
`Could not find property option "${itemName}" for "${nodeProperties.name}"`,
|
||||
);
|
||||
}
|
||||
|
||||
tempNodePropertiesArray = (nodePropertyOptions as INodePropertyCollection).values!;
|
||||
tempValue = getNodeParameters(tempNodePropertiesArray, nodeValue as INodeParameters, returnDefaults, returnNoneDisplayed, false, false, nodeValuesRoot, nodeProperties.type);
|
||||
tempNodePropertiesArray = nodePropertyOptions.values!;
|
||||
tempValue = getNodeParameters(
|
||||
tempNodePropertiesArray,
|
||||
nodeValue,
|
||||
returnDefaults,
|
||||
returnNoneDisplayed,
|
||||
false,
|
||||
false,
|
||||
nodeValuesRoot,
|
||||
nodeProperties.type,
|
||||
);
|
||||
if (tempValue !== null) {
|
||||
tempArrayValue.push(tempValue);
|
||||
}
|
||||
@@ -678,11 +748,23 @@ export function getNodeParameters(nodePropertiesArray: INodeProperties[], nodeVa
|
||||
tempNodeParameters = {};
|
||||
|
||||
// Get the options of the current item
|
||||
const nodePropertyOptions = nodeProperties!.options!.find((data) => data.name === itemName);
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
const nodePropertyOptions = nodeProperties.options!.find(
|
||||
(data) => data.name === itemName,
|
||||
);
|
||||
|
||||
if (nodePropertyOptions !== undefined) {
|
||||
tempNodePropertiesArray = (nodePropertyOptions as INodePropertyCollection).values!;
|
||||
tempValue = getNodeParameters(tempNodePropertiesArray, (nodeValues[nodeProperties.name] as INodeParameters)[itemName] as INodeParameters, returnDefaults, returnNoneDisplayed, false, false, nodeValuesRoot, nodeProperties.type);
|
||||
tempValue = getNodeParameters(
|
||||
tempNodePropertiesArray,
|
||||
(nodeValues[nodeProperties.name] as INodeParameters)[itemName] as INodeParameters,
|
||||
returnDefaults,
|
||||
returnNoneDisplayed,
|
||||
false,
|
||||
false,
|
||||
nodeValuesRoot,
|
||||
nodeProperties.type,
|
||||
);
|
||||
if (tempValue !== null) {
|
||||
Object.assign(tempNodeParameters, tempValue);
|
||||
}
|
||||
@@ -694,13 +776,15 @@ export function getNodeParameters(nodePropertiesArray: INodeProperties[], nodeVa
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(collectionValues).length !== 0 || returnDefaults === true) {
|
||||
if (Object.keys(collectionValues).length !== 0 || returnDefaults) {
|
||||
// Set only if value got found
|
||||
|
||||
if (returnDefaults === true) {
|
||||
if (returnDefaults) {
|
||||
// Set also when it has the default value
|
||||
if (collectionValues === undefined) {
|
||||
nodeParameters[nodeProperties.name] = JSON.parse(JSON.stringify(nodeProperties.default));
|
||||
nodeParameters[nodeProperties.name] = JSON.parse(
|
||||
JSON.stringify(nodeProperties.default),
|
||||
);
|
||||
} else {
|
||||
nodeParameters[nodeProperties.name] = collectionValues;
|
||||
}
|
||||
@@ -717,7 +801,6 @@ export function getNodeParameters(nodePropertiesArray: INodeProperties[], nodeVa
|
||||
return nodeParameters;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Brings the output data in a format that can be returned from a node
|
||||
*
|
||||
@@ -726,7 +809,10 @@ export function getNodeParameters(nodePropertiesArray: INodeProperties[], nodeVa
|
||||
* @param {number} [outputIndex=0]
|
||||
* @returns {Promise<INodeExecutionData[][]>}
|
||||
*/
|
||||
export async function prepareOutputData(outputData: INodeExecutionData[], outputIndex = 0): Promise<INodeExecutionData[][]> {
|
||||
export async function prepareOutputData(
|
||||
outputData: INodeExecutionData[],
|
||||
outputIndex = 0,
|
||||
): Promise<INodeExecutionData[][]> {
|
||||
// TODO: Check if node has output with that index
|
||||
const returnData = [];
|
||||
|
||||
@@ -739,8 +825,6 @@ export async function prepareOutputData(outputData: INodeExecutionData[], output
|
||||
return returnData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns all the webhooks which should be created for the give node
|
||||
*
|
||||
@@ -749,7 +833,12 @@ export async function prepareOutputData(outputData: INodeExecutionData[], output
|
||||
* @param {INode} node
|
||||
* @returns {IWebhookData[]}
|
||||
*/
|
||||
export function getNodeWebhooks(workflow: Workflow, node: INode, additionalData: IWorkflowExecuteAdditionalData, ignoreRestartWehbooks = false): IWebhookData[] {
|
||||
export function getNodeWebhooks(
|
||||
workflow: Workflow,
|
||||
node: INode,
|
||||
additionalData: IWorkflowExecuteAdditionalData,
|
||||
ignoreRestartWehbooks = false,
|
||||
): IWebhookData[] {
|
||||
if (node.disabled === true) {
|
||||
// Node is disabled so webhooks will also not be enabled
|
||||
return [];
|
||||
@@ -767,15 +856,21 @@ export function getNodeWebhooks(workflow: Workflow, node: INode, additionalData:
|
||||
|
||||
const returnData: IWebhookData[] = [];
|
||||
for (const webhookDescription of nodeType.description.webhooks) {
|
||||
|
||||
if (ignoreRestartWehbooks === true && webhookDescription.restartWebhook === true) {
|
||||
if (ignoreRestartWehbooks && webhookDescription.restartWebhook === true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let nodeWebhookPath = workflow.expression.getSimpleParameterValue(node, webhookDescription['path'], mode, {});
|
||||
let nodeWebhookPath = workflow.expression.getSimpleParameterValue(
|
||||
node,
|
||||
webhookDescription.path,
|
||||
mode,
|
||||
{},
|
||||
);
|
||||
if (nodeWebhookPath === undefined) {
|
||||
// TODO: Use a proper logger
|
||||
console.error(`No webhook path could be found for node "${node.name}" in workflow "${workflowId}".`);
|
||||
console.error(
|
||||
`No webhook path could be found for node "${node.name}" in workflow "${workflowId}".`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -788,15 +883,35 @@ export function getNodeWebhooks(workflow: Workflow, node: INode, additionalData:
|
||||
nodeWebhookPath = nodeWebhookPath.slice(0, -1);
|
||||
}
|
||||
|
||||
const isFullPath: boolean = workflow.expression.getSimpleParameterValue(node, webhookDescription['isFullPath'], 'internal', {}, false) as boolean;
|
||||
const restartWebhook: boolean = workflow.expression.getSimpleParameterValue(node, webhookDescription['restartWebhook'], 'internal', {}, false) as boolean;
|
||||
const isFullPath: boolean = workflow.expression.getSimpleParameterValue(
|
||||
node,
|
||||
webhookDescription.isFullPath,
|
||||
'internal',
|
||||
{},
|
||||
false,
|
||||
) as boolean;
|
||||
const restartWebhook: boolean = workflow.expression.getSimpleParameterValue(
|
||||
node,
|
||||
webhookDescription.restartWebhook,
|
||||
'internal',
|
||||
{},
|
||||
false,
|
||||
) as boolean;
|
||||
const path = getNodeWebhookPath(workflowId, node, nodeWebhookPath, isFullPath, restartWebhook);
|
||||
|
||||
const httpMethod = workflow.expression.getSimpleParameterValue(node, webhookDescription['httpMethod'], mode, {}, 'GET');
|
||||
const httpMethod = workflow.expression.getSimpleParameterValue(
|
||||
node,
|
||||
webhookDescription.httpMethod,
|
||||
mode,
|
||||
{},
|
||||
'GET',
|
||||
);
|
||||
|
||||
if (httpMethod === undefined) {
|
||||
// TODO: Use a proper logger
|
||||
console.error(`The webhook "${path}" for node "${node.name}" in workflow "${workflowId}" could not be added because the httpMethod is not defined.`);
|
||||
console.error(
|
||||
`The webhook "${path}" for node "${node.name}" in workflow "${workflowId}" could not be added because the httpMethod is not defined.`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -838,10 +953,17 @@ export function getNodeWebhooksBasic(workflow: Workflow, node: INode): IWebhookD
|
||||
|
||||
const returnData: IWebhookData[] = [];
|
||||
for (const webhookDescription of nodeType.description.webhooks) {
|
||||
let nodeWebhookPath = workflow.expression.getSimpleParameterValue(node, webhookDescription['path'], mode, {});
|
||||
let nodeWebhookPath = workflow.expression.getSimpleParameterValue(
|
||||
node,
|
||||
webhookDescription.path,
|
||||
mode,
|
||||
{},
|
||||
);
|
||||
if (nodeWebhookPath === undefined) {
|
||||
// TODO: Use a proper logger
|
||||
console.error(`No webhook path could be found for node "${node.name}" in workflow "${workflowId}".`);
|
||||
console.error(
|
||||
`No webhook path could be found for node "${node.name}" in workflow "${workflowId}".`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -854,19 +976,32 @@ export function getNodeWebhooksBasic(workflow: Workflow, node: INode): IWebhookD
|
||||
nodeWebhookPath = nodeWebhookPath.slice(0, -1);
|
||||
}
|
||||
|
||||
const isFullPath: boolean = workflow.expression.getSimpleParameterValue(node, webhookDescription['isFullPath'], mode, {}, false) as boolean;
|
||||
const isFullPath: boolean = workflow.expression.getSimpleParameterValue(
|
||||
node,
|
||||
webhookDescription.isFullPath,
|
||||
mode,
|
||||
{},
|
||||
false,
|
||||
) as boolean;
|
||||
|
||||
const path = getNodeWebhookPath(workflowId, node, nodeWebhookPath, isFullPath);
|
||||
|
||||
const httpMethod = workflow.expression.getSimpleParameterValue(node, webhookDescription['httpMethod'], mode, {});
|
||||
const httpMethod = workflow.expression.getSimpleParameterValue(
|
||||
node,
|
||||
webhookDescription.httpMethod,
|
||||
mode,
|
||||
{},
|
||||
);
|
||||
|
||||
if (httpMethod === undefined) {
|
||||
// TODO: Use a proper logger
|
||||
console.error(`The webhook "${path}" for node "${node.name}" in workflow "${workflowId}" could not be added because the httpMethod is not defined.`);
|
||||
console.error(
|
||||
`The webhook "${path}" for node "${node.name}" in workflow "${workflowId}" could not be added because the httpMethod is not defined.`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
//@ts-ignore
|
||||
// @ts-ignore
|
||||
returnData.push({
|
||||
httpMethod: httpMethod.toString() as WebhookHttpMethod,
|
||||
node: node.name,
|
||||
@@ -879,7 +1014,6 @@ export function getNodeWebhooksBasic(workflow: Workflow, node: INode): IWebhookD
|
||||
return returnData;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the webhook path
|
||||
*
|
||||
@@ -889,11 +1023,18 @@ export function getNodeWebhooksBasic(workflow: Workflow, node: INode): IWebhookD
|
||||
* @param {string} path
|
||||
* @returns {string}
|
||||
*/
|
||||
export function getNodeWebhookPath(workflowId: string, node: INode, path: string, isFullPath?: boolean, restartWebhook?: boolean): string {
|
||||
export function getNodeWebhookPath(
|
||||
workflowId: string,
|
||||
node: INode,
|
||||
path: string,
|
||||
isFullPath?: boolean,
|
||||
restartWebhook?: boolean,
|
||||
): string {
|
||||
let webhookPath = '';
|
||||
if (restartWebhook === true) {
|
||||
return path;
|
||||
} else if (node.webhookId === undefined) {
|
||||
}
|
||||
if (node.webhookId === undefined) {
|
||||
webhookPath = `${workflowId}/${encodeURIComponent(node.name.toLowerCase())}/${path}`;
|
||||
} else {
|
||||
if (isFullPath === true) {
|
||||
@@ -904,7 +1045,6 @@ export function getNodeWebhookPath(workflowId: string, node: INode, path: string
|
||||
return webhookPath;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the webhook URL
|
||||
*
|
||||
@@ -916,7 +1056,13 @@ export function getNodeWebhookPath(workflowId: string, node: INode, path: string
|
||||
* @param {boolean} isFullPath
|
||||
* @returns {string}
|
||||
*/
|
||||
export function getNodeWebhookUrl(baseUrl: string, workflowId: string, node: INode, path: string, isFullPath?: boolean): string {
|
||||
export function getNodeWebhookUrl(
|
||||
baseUrl: string,
|
||||
workflowId: string,
|
||||
node: INode,
|
||||
path: string,
|
||||
isFullPath?: boolean,
|
||||
): string {
|
||||
if ((path.startsWith(':') || path.includes('/:')) && node.webhookId) {
|
||||
// setting this to false to prefix the webhookId
|
||||
isFullPath = false;
|
||||
@@ -927,7 +1073,6 @@ export function getNodeWebhookUrl(baseUrl: string, workflowId: string, node: INo
|
||||
return `${baseUrl}/${getNodeWebhookPath(workflowId, node, path, isFullPath)}`;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns all the parameter-issues of the node
|
||||
*
|
||||
@@ -936,7 +1081,10 @@ export function getNodeWebhookUrl(baseUrl: string, workflowId: string, node: INo
|
||||
* @param {INode} node The data of the node
|
||||
* @returns {(INodeIssues | null)}
|
||||
*/
|
||||
export function getNodeParametersIssues(nodePropertiesArray: INodeProperties[], node: INode): INodeIssues | null {
|
||||
export function getNodeParametersIssues(
|
||||
nodePropertiesArray: INodeProperties[],
|
||||
node: INode,
|
||||
): INodeIssues | null {
|
||||
const foundIssues: INodeIssues = {};
|
||||
let propertyIssues: INodeIssues;
|
||||
|
||||
@@ -957,7 +1105,6 @@ export function getNodeParametersIssues(nodePropertiesArray: INodeProperties[],
|
||||
return foundIssues;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the issues of the node as string
|
||||
*
|
||||
@@ -973,12 +1120,10 @@ export function nodeIssuesToString(issues: INodeIssues, node?: INode): string[]
|
||||
nodeIssues.push(`Execution Error.`);
|
||||
}
|
||||
|
||||
const objectProperties = [
|
||||
'parameters',
|
||||
'credentials',
|
||||
];
|
||||
const objectProperties = ['parameters', 'credentials'];
|
||||
|
||||
let issueText: string, parameterName: string;
|
||||
let issueText: string;
|
||||
let parameterName: string;
|
||||
for (const propertyName of objectProperties) {
|
||||
if (issues[propertyName] !== undefined) {
|
||||
for (parameterName of Object.keys(issues[propertyName] as object)) {
|
||||
@@ -1000,7 +1145,6 @@ export function nodeIssuesToString(issues: INodeIssues, node?: INode): string[]
|
||||
return nodeIssues;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds an issue if the parameter is not defined
|
||||
*
|
||||
@@ -1009,11 +1153,17 @@ export function nodeIssuesToString(issues: INodeIssues, node?: INode): string[]
|
||||
* @param {INodeProperties} nodeProperties The properties of the node
|
||||
* @param {NodeParameterValue} value The value of the parameter
|
||||
*/
|
||||
export function addToIssuesIfMissing(foundIssues: INodeIssues, nodeProperties: INodeProperties, value: NodeParameterValue) {
|
||||
export function addToIssuesIfMissing(
|
||||
foundIssues: INodeIssues,
|
||||
nodeProperties: INodeProperties,
|
||||
value: NodeParameterValue,
|
||||
) {
|
||||
// TODO: Check what it really has when undefined
|
||||
if ((nodeProperties.type === 'string' && (value === '' || value === undefined)) ||
|
||||
if (
|
||||
(nodeProperties.type === 'string' && (value === '' || value === undefined)) ||
|
||||
(nodeProperties.type === 'multiOptions' && Array.isArray(value) && value.length === 0) ||
|
||||
(nodeProperties.type === 'dateTime' && value === undefined)) {
|
||||
(nodeProperties.type === 'dateTime' && value === undefined)
|
||||
) {
|
||||
// Parameter is requried but empty
|
||||
if (foundIssues.parameters === undefined) {
|
||||
foundIssues.parameters = {};
|
||||
@@ -1022,11 +1172,12 @@ export function addToIssuesIfMissing(foundIssues: INodeIssues, nodeProperties: I
|
||||
foundIssues.parameters[nodeProperties.name] = [];
|
||||
}
|
||||
|
||||
foundIssues.parameters[nodeProperties.name].push(`Parameter "${nodeProperties.displayName}" is required.`);
|
||||
foundIssues.parameters[nodeProperties.name].push(
|
||||
`Parameter "${nodeProperties.displayName}" is required.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the parameter value
|
||||
*
|
||||
@@ -1036,15 +1187,14 @@ export function addToIssuesIfMissing(foundIssues: INodeIssues, nodeProperties: I
|
||||
* @param {string} path The path to the properties
|
||||
* @returns
|
||||
*/
|
||||
export function getParameterValueByPath(nodeValues: INodeParameters, parameterName: string, path: string) {
|
||||
return get(
|
||||
nodeValues,
|
||||
path ? path + '.' + parameterName : parameterName,
|
||||
);
|
||||
export function getParameterValueByPath(
|
||||
nodeValues: INodeParameters,
|
||||
parameterName: string,
|
||||
path: string,
|
||||
) {
|
||||
return get(nodeValues, path ? `${path}.${parameterName}` : parameterName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns all the issues with the given node-values
|
||||
*
|
||||
@@ -1054,7 +1204,11 @@ export function getParameterValueByPath(nodeValues: INodeParameters, parameterNa
|
||||
* @param {string} path The path to the properties
|
||||
* @returns {INodeIssues}
|
||||
*/
|
||||
export function getParameterIssues(nodeProperties: INodeProperties, nodeValues: INodeParameters, path: string): INodeIssues {
|
||||
export function getParameterIssues(
|
||||
nodeProperties: INodeProperties,
|
||||
nodeValues: INodeParameters,
|
||||
path: string,
|
||||
): INodeIssues {
|
||||
const foundIssues: INodeIssues = {};
|
||||
let value;
|
||||
|
||||
@@ -1062,11 +1216,15 @@ export function getParameterIssues(nodeProperties: INodeProperties, nodeValues:
|
||||
if (displayParameterPath(nodeValues, nodeProperties, path)) {
|
||||
value = getParameterValueByPath(nodeValues, nodeProperties.name, path);
|
||||
|
||||
if (nodeProperties.typeOptions !== undefined && nodeProperties.typeOptions.multipleValues !== undefined) {
|
||||
if (
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
|
||||
nodeProperties.typeOptions !== undefined &&
|
||||
nodeProperties.typeOptions.multipleValues !== undefined
|
||||
) {
|
||||
// Multiple can be set so will be an array
|
||||
if (Array.isArray(value)) {
|
||||
for (const singleValue of value as NodeParameterValue[]) {
|
||||
addToIssuesIfMissing(foundIssues, nodeProperties, singleValue as NodeParameterValue);
|
||||
addToIssuesIfMissing(foundIssues, nodeProperties, singleValue);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1106,7 +1264,7 @@ export function getParameterIssues(nodeProperties: INodeProperties, nodeValues:
|
||||
});
|
||||
}
|
||||
} else if (nodeProperties.type === 'fixedCollection') {
|
||||
basePath = basePath ? `${basePath}.` : '' + nodeProperties.name + '.';
|
||||
basePath = basePath ? `${basePath}.` : `${nodeProperties.name}.`;
|
||||
|
||||
let propertyOptions: INodePropertyCollection;
|
||||
for (propertyOptions of nodeProperties.options as INodePropertyCollection[]) {
|
||||
@@ -1116,14 +1274,18 @@ export function getParameterIssues(nodeProperties: INodeProperties, nodeValues:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nodeProperties.typeOptions !== undefined && nodeProperties.typeOptions.multipleValues !== undefined) {
|
||||
if (
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
|
||||
nodeProperties.typeOptions !== undefined &&
|
||||
nodeProperties.typeOptions.multipleValues !== undefined
|
||||
) {
|
||||
// Multiple can be set so will be an array of objects
|
||||
if (Array.isArray(value)) {
|
||||
for (let i = 0; i < (value as INodeParameters[]).length; i++) {
|
||||
for (const option of propertyOptions.values) {
|
||||
checkChildNodeProperties.push({
|
||||
basePath: `${basePath}${propertyOptions.name}[${i}]`,
|
||||
data: option as INodeProperties,
|
||||
data: option,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1133,7 +1295,7 @@ export function getParameterIssues(nodeProperties: INodeProperties, nodeValues:
|
||||
for (const option of propertyOptions.values) {
|
||||
checkChildNodeProperties.push({
|
||||
basePath: basePath + propertyOptions.name,
|
||||
data: option as INodeProperties,
|
||||
data: option,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1146,14 +1308,13 @@ export function getParameterIssues(nodeProperties: INodeProperties, nodeValues:
|
||||
let propertyIssues;
|
||||
|
||||
for (const optionData of checkChildNodeProperties) {
|
||||
propertyIssues = getParameterIssues(optionData.data as INodeProperties, nodeValues, optionData.basePath);
|
||||
propertyIssues = getParameterIssues(optionData.data, nodeValues, optionData.basePath);
|
||||
mergeIssues(foundIssues, propertyIssues);
|
||||
}
|
||||
|
||||
return foundIssues;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Merges multiple NodeIssues together
|
||||
*
|
||||
@@ -1172,10 +1333,7 @@ export function mergeIssues(destination: INodeIssues, source: INodeIssues | null
|
||||
destination.execution = true;
|
||||
}
|
||||
|
||||
const objectProperties = [
|
||||
'parameters',
|
||||
'credentials',
|
||||
];
|
||||
const objectProperties = ['parameters', 'credentials'];
|
||||
|
||||
let destinationProperty: INodeIssueObjectProperty;
|
||||
for (const propertyName of objectProperties) {
|
||||
@@ -1190,7 +1348,10 @@ export function mergeIssues(destination: INodeIssues, source: INodeIssues | null
|
||||
if (destinationProperty[parameterName] === undefined) {
|
||||
destinationProperty[parameterName] = [];
|
||||
}
|
||||
destinationProperty[parameterName].push.apply(destinationProperty[parameterName], (source[propertyName] as INodeIssueObjectProperty)[parameterName]);
|
||||
destinationProperty[parameterName].push.apply(
|
||||
destinationProperty[parameterName],
|
||||
(source[propertyName] as INodeIssueObjectProperty)[parameterName],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1200,8 +1361,6 @@ export function mergeIssues(destination: INodeIssues, source: INodeIssues | null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Merges the given node properties
|
||||
*
|
||||
@@ -1209,10 +1368,13 @@ export function mergeIssues(destination: INodeIssues, source: INodeIssues | null
|
||||
* @param {INodeProperties[]} mainProperties
|
||||
* @param {INodeProperties[]} addProperties
|
||||
*/
|
||||
export function mergeNodeProperties(mainProperties: INodeProperties[], addProperties: INodeProperties[]): void {
|
||||
export function mergeNodeProperties(
|
||||
mainProperties: INodeProperties[],
|
||||
addProperties: INodeProperties[],
|
||||
): void {
|
||||
let existingIndex: number;
|
||||
for (const property of addProperties) {
|
||||
existingIndex = mainProperties.findIndex(element => element.name === property.name);
|
||||
existingIndex = mainProperties.findIndex((element) => element.name === property.name);
|
||||
|
||||
if (existingIndex === -1) {
|
||||
// Property does not exist yet, so add
|
||||
|
||||
@@ -1,20 +1,35 @@
|
||||
|
||||
import {
|
||||
IDataObject,
|
||||
IObservableObject,
|
||||
} from './';
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-shadow */
|
||||
/* eslint-disable no-param-reassign */
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
import { IDataObject, IObservableObject } from '.';
|
||||
|
||||
export interface IObservableOptions {
|
||||
ignoreEmptyOnFirstChild?: boolean;
|
||||
}
|
||||
|
||||
export function create(target: IDataObject, parent?: IObservableObject, option?: IObservableOptions, depth?: number): IDataObject {
|
||||
export function create(
|
||||
target: IDataObject,
|
||||
parent?: IObservableObject,
|
||||
option?: IObservableOptions,
|
||||
depth?: number,
|
||||
): IDataObject {
|
||||
// eslint-disable-next-line no-param-reassign, @typescript-eslint/prefer-nullish-coalescing
|
||||
depth = depth || 0;
|
||||
|
||||
// Make all the children of target also observeable
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const key in target) {
|
||||
if (typeof target[key] === 'object' && target[key] !== null) {
|
||||
target[key] = create(target[key] as IDataObject, (parent || target) as IObservableObject, option, depth + 1);
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
target[key] = create(
|
||||
target[key] as IDataObject,
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||
(parent || target) as IObservableObject,
|
||||
option,
|
||||
depth + 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +38,7 @@ export function create(target: IDataObject, parent?: IObservableObject, option?:
|
||||
writable: true,
|
||||
});
|
||||
return new Proxy(target, {
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
deleteProperty(target, name) {
|
||||
if (parent === undefined) {
|
||||
// If no parent is given mark current data as changed
|
||||
@@ -39,8 +55,15 @@ export function create(target: IDataObject, parent?: IObservableObject, option?:
|
||||
set(target, name, value) {
|
||||
if (parent === undefined) {
|
||||
// If no parent is given mark current data as changed
|
||||
if (option !== undefined && option.ignoreEmptyOnFirstChild === true && depth === 0
|
||||
&& target[name.toString()] === undefined && typeof value === 'object' && Object.keys(value).length === 0) {
|
||||
if (
|
||||
option !== undefined &&
|
||||
option.ignoreEmptyOnFirstChild === true &&
|
||||
depth === 0 &&
|
||||
target[name.toString()] === undefined &&
|
||||
typeof value === 'object' &&
|
||||
Object.keys(value).length === 0
|
||||
// eslint-disable-next-line no-empty
|
||||
) {
|
||||
} else {
|
||||
(target as IObservableObject).__dataChanged = true;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
|
||||
/* eslint-disable no-param-reassign */
|
||||
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
/* eslint-disable @typescript-eslint/no-for-in-array */
|
||||
/* eslint-disable no-prototype-builtins */
|
||||
/* eslint-disable @typescript-eslint/prefer-nullish-coalescing */
|
||||
/* eslint-disable no-underscore-dangle */
|
||||
/* eslint-disable no-continue */
|
||||
/* eslint-disable no-restricted-syntax */
|
||||
/* eslint-disable import/no-cycle */
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
import {
|
||||
Expression,
|
||||
IConnections,
|
||||
@@ -26,20 +37,27 @@ import {
|
||||
WebhookSetupMethodNames,
|
||||
WorkflowActivateMode,
|
||||
WorkflowExecuteMode,
|
||||
} from './';
|
||||
} from '.';
|
||||
|
||||
import { IConnection, IDataObject, IObservableObject } from './Interfaces';
|
||||
|
||||
|
||||
export class Workflow {
|
||||
id: string | undefined;
|
||||
|
||||
name: string | undefined;
|
||||
|
||||
nodes: INodes = {};
|
||||
|
||||
connectionsBySourceNode: IConnections;
|
||||
|
||||
connectionsByDestinationNode: IConnections;
|
||||
|
||||
nodeTypes: INodeTypes;
|
||||
|
||||
expression: Expression;
|
||||
|
||||
active: boolean;
|
||||
|
||||
settings: IWorkflowSettings;
|
||||
|
||||
// To save workflow specific static data like for example
|
||||
@@ -47,7 +65,16 @@ export class Workflow {
|
||||
staticData: IDataObject;
|
||||
|
||||
// constructor(id: string | undefined, nodes: INode[], connections: IConnections, active: boolean, nodeTypes: INodeTypes, staticData?: IDataObject, settings?: IWorkflowSettings) {
|
||||
constructor(parameters: {id?: string, name?: string, nodes: INode[], connections: IConnections, active: boolean, nodeTypes: INodeTypes, staticData?: IDataObject, settings?: IWorkflowSettings}) {
|
||||
constructor(parameters: {
|
||||
id?: string;
|
||||
name?: string;
|
||||
nodes: INode[];
|
||||
connections: IConnections;
|
||||
active: boolean;
|
||||
nodeTypes: INodeTypes;
|
||||
staticData?: IDataObject;
|
||||
settings?: IWorkflowSettings;
|
||||
}) {
|
||||
this.id = parameters.id;
|
||||
this.name = parameters.name;
|
||||
this.nodeTypes = parameters.nodeTypes;
|
||||
@@ -70,7 +97,12 @@ export class Workflow {
|
||||
}
|
||||
|
||||
// Add default values
|
||||
const nodeParameters = NodeHelpers.getNodeParameters(nodeType.description.properties, node.parameters, true, false);
|
||||
const nodeParameters = NodeHelpers.getNodeParameters(
|
||||
nodeType.description.properties,
|
||||
node.parameters,
|
||||
true,
|
||||
false,
|
||||
);
|
||||
node.parameters = nodeParameters !== null ? nodeParameters : {};
|
||||
}
|
||||
this.connectionsBySourceNode = parameters.connections;
|
||||
@@ -80,15 +112,15 @@ export class Workflow {
|
||||
|
||||
this.active = parameters.active || false;
|
||||
|
||||
this.staticData = ObservableObject.create(parameters.staticData || {}, undefined, { ignoreEmptyOnFirstChild: true });
|
||||
this.staticData = ObservableObject.create(parameters.staticData || {}, undefined, {
|
||||
ignoreEmptyOnFirstChild: true,
|
||||
});
|
||||
|
||||
this.settings = parameters.settings || {};
|
||||
|
||||
this.expression = new Expression(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The default connections are by source node. This function rewrites them by destination nodes
|
||||
* to easily find parent nodes.
|
||||
@@ -140,8 +172,6 @@ export class Workflow {
|
||||
return returnConnection;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A workflow can only be activated if it has a node which has either triggers
|
||||
* or webhooks defined.
|
||||
@@ -162,6 +192,7 @@ export class Workflow {
|
||||
continue;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
|
||||
if (ignoreNodeTypes !== undefined && ignoreNodeTypes.includes(node.type)) {
|
||||
continue;
|
||||
}
|
||||
@@ -173,7 +204,11 @@ export class Workflow {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nodeType.poll !== undefined || nodeType.trigger !== undefined || nodeType.webhook !== undefined) {
|
||||
if (
|
||||
nodeType.poll !== undefined ||
|
||||
nodeType.trigger !== undefined ||
|
||||
nodeType.webhook !== undefined
|
||||
) {
|
||||
// Is a trigger node. So workflow can be activated.
|
||||
return true;
|
||||
}
|
||||
@@ -182,8 +217,6 @@ export class Workflow {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Checks if everything in the workflow is complete
|
||||
* and ready to be executed. If it returns null everything
|
||||
@@ -216,7 +249,7 @@ export class Workflow {
|
||||
typeUnknown: true,
|
||||
};
|
||||
} else {
|
||||
nodeIssues = NodeHelpers.getNodeParametersIssues(nodeType.description.properties!, node);
|
||||
nodeIssues = NodeHelpers.getNodeParametersIssues(nodeType.description.properties, node);
|
||||
}
|
||||
|
||||
if (nodeIssues !== null) {
|
||||
@@ -231,8 +264,6 @@ export class Workflow {
|
||||
return workflowIssues;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the static data of the workflow.
|
||||
* It gets saved with the workflow and will be the same for
|
||||
@@ -249,11 +280,15 @@ export class Workflow {
|
||||
key = 'global';
|
||||
} else if (type === 'node') {
|
||||
if (node === undefined) {
|
||||
throw new Error(`The request data of context type "node" the node parameter has to be set!`);
|
||||
throw new Error(
|
||||
`The request data of context type "node" the node parameter has to be set!`,
|
||||
);
|
||||
}
|
||||
key = `node:${node.name}`;
|
||||
} else {
|
||||
throw new Error(`The context type "${type}" is not know. Only "global" and node" are supported!`);
|
||||
throw new Error(
|
||||
`The context type "${type}" is not know. Only "global" and node" are supported!`,
|
||||
);
|
||||
}
|
||||
|
||||
if (this.staticData[key] === undefined) {
|
||||
@@ -265,8 +300,6 @@ export class Workflow {
|
||||
return this.staticData[key] as IDataObject;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns all the trigger nodes in the workflow.
|
||||
*
|
||||
@@ -274,10 +307,9 @@ export class Workflow {
|
||||
* @memberof Workflow
|
||||
*/
|
||||
getTriggerNodes(): INode[] {
|
||||
return this.queryNodes((nodeType: INodeType) => !!nodeType.trigger );
|
||||
return this.queryNodes((nodeType: INodeType) => !!nodeType.trigger);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns all the poll nodes in the workflow
|
||||
*
|
||||
@@ -285,10 +317,9 @@ export class Workflow {
|
||||
* @memberof Workflow
|
||||
*/
|
||||
getPollNodes(): INode[] {
|
||||
return this.queryNodes((nodeType: INodeType) => !!nodeType.poll );
|
||||
return this.queryNodes((nodeType: INodeType) => !!nodeType.poll);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns all the nodes in the workflow for which the given
|
||||
* checkFunction return true
|
||||
@@ -321,8 +352,6 @@ export class Workflow {
|
||||
return returnNodes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the node with the given name if it exists else null
|
||||
*
|
||||
@@ -338,7 +367,6 @@ export class Workflow {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Renames nodes in expressions
|
||||
*
|
||||
@@ -348,7 +376,11 @@ export class Workflow {
|
||||
* @returns {(NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[])}
|
||||
* @memberof Workflow
|
||||
*/
|
||||
renameNodeInExpressions(parameterValue: NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[], currentName: string, newName: string): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] {
|
||||
renameNodeInExpressions(
|
||||
parameterValue: NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[],
|
||||
currentName: string,
|
||||
newName: string,
|
||||
): NodeParameterValue | INodeParameters | NodeParameterValue[] | INodeParameters[] {
|
||||
if (typeof parameterValue !== 'object') {
|
||||
// Reached the actual value
|
||||
if (typeof parameterValue === 'string' && parameterValue.charAt(0) === '=') {
|
||||
@@ -362,7 +394,11 @@ export class Workflow {
|
||||
// In case some special characters are used in name escape them
|
||||
const currentNameEscaped = currentName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
|
||||
parameterValue = parameterValue.replace(new RegExp(`(\\$node(\.|\\["|\\[\'))${currentNameEscaped}((\.|"\\]|\'\\]))`, 'g'), `$1${newName}$3`);
|
||||
parameterValue = parameterValue.replace(
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
new RegExp(`(\\$node(\.|\\["|\\[\'))${currentNameEscaped}((\.|"\\]|\'\\]))`, 'g'),
|
||||
`$1${newName}$3`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,7 +406,8 @@ export class Workflow {
|
||||
}
|
||||
|
||||
if (Array.isArray(parameterValue)) {
|
||||
const returnArray: any[] = []; // tslint:disable-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const returnArray: any[] = [];
|
||||
|
||||
for (const currentValue of parameterValue) {
|
||||
returnArray.push(this.renameNodeInExpressions(currentValue, currentName, newName));
|
||||
@@ -379,17 +416,21 @@ export class Workflow {
|
||||
return returnArray;
|
||||
}
|
||||
|
||||
const returnData: any = {}; // tslint:disable-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const returnData: any = {};
|
||||
|
||||
for (const parameterName of Object.keys(parameterValue || {})) {
|
||||
returnData[parameterName] = this.renameNodeInExpressions(parameterValue![parameterName], currentName, newName);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
returnData[parameterName] = this.renameNodeInExpressions(
|
||||
parameterValue![parameterName],
|
||||
currentName,
|
||||
newName,
|
||||
);
|
||||
}
|
||||
|
||||
return returnData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Rename a node in the workflow
|
||||
*
|
||||
@@ -398,7 +439,6 @@ export class Workflow {
|
||||
* @memberof Workflow
|
||||
*/
|
||||
renameNode(currentName: string, newName: string) {
|
||||
|
||||
// Rename the node itself
|
||||
if (this.nodes[currentName] !== undefined) {
|
||||
this.nodes[newName] = this.nodes[currentName];
|
||||
@@ -409,7 +449,11 @@ export class Workflow {
|
||||
// Update the expressions which reference the node
|
||||
// with its old name
|
||||
for (const node of Object.values(this.nodes)) {
|
||||
node.parameters = this.renameNodeInExpressions(node.parameters, currentName, newName) as INodeParameters;
|
||||
node.parameters = this.renameNodeInExpressions(
|
||||
node.parameters,
|
||||
currentName,
|
||||
newName,
|
||||
) as INodeParameters;
|
||||
}
|
||||
|
||||
// Change all source connections
|
||||
@@ -419,12 +463,21 @@ export class Workflow {
|
||||
}
|
||||
|
||||
// Change all destination connections
|
||||
let sourceNode: string, type: string, sourceIndex: string, connectionIndex: string, connectionData: IConnection;
|
||||
let sourceNode: string;
|
||||
let type: string;
|
||||
let sourceIndex: string;
|
||||
let connectionIndex: string;
|
||||
let connectionData: IConnection;
|
||||
for (sourceNode of Object.keys(this.connectionsBySourceNode)) {
|
||||
for (type of Object.keys(this.connectionsBySourceNode[sourceNode])) {
|
||||
for (sourceIndex of Object.keys(this.connectionsBySourceNode[sourceNode][type])) {
|
||||
for (connectionIndex of Object.keys(this.connectionsBySourceNode[sourceNode][type][parseInt(sourceIndex, 10)])) {
|
||||
connectionData = this.connectionsBySourceNode[sourceNode][type][parseInt(sourceIndex, 10)][parseInt(connectionIndex, 10)];
|
||||
for (connectionIndex of Object.keys(
|
||||
this.connectionsBySourceNode[sourceNode][type][parseInt(sourceIndex, 10)],
|
||||
)) {
|
||||
connectionData =
|
||||
this.connectionsBySourceNode[sourceNode][type][parseInt(sourceIndex, 10)][
|
||||
parseInt(connectionIndex, 10)
|
||||
];
|
||||
if (connectionData.node === currentName) {
|
||||
connectionData.node = newName;
|
||||
}
|
||||
@@ -434,11 +487,11 @@ export class Workflow {
|
||||
}
|
||||
|
||||
// Use the updated connections to create updated connections by destionation nodes
|
||||
this.connectionsByDestinationNode = this.__getConnectionsByDestination(this.connectionsBySourceNode);
|
||||
this.connectionsByDestinationNode = this.__getConnectionsByDestination(
|
||||
this.connectionsBySourceNode,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Finds the highest parent nodes of the node with the given name
|
||||
*
|
||||
@@ -448,7 +501,12 @@ export class Workflow {
|
||||
* @returns {string[]}
|
||||
* @memberof Workflow
|
||||
*/
|
||||
getHighestNode(nodeName: string, type = 'main', nodeConnectionIndex?:number, checkedNodes?: string[]): string[] {
|
||||
getHighestNode(
|
||||
nodeName: string,
|
||||
type = 'main',
|
||||
nodeConnectionIndex?: number,
|
||||
checkedNodes?: string[],
|
||||
): string[] {
|
||||
const currentHighest: string[] = [];
|
||||
if (this.nodes[nodeName].disabled === false) {
|
||||
// If the current node is not disabled itself is the highest
|
||||
@@ -467,23 +525,28 @@ export class Workflow {
|
||||
|
||||
checkedNodes = checkedNodes || [];
|
||||
|
||||
if (checkedNodes!.includes(nodeName)) {
|
||||
if (checkedNodes.includes(nodeName)) {
|
||||
// Node got checked already before
|
||||
return currentHighest;
|
||||
}
|
||||
|
||||
checkedNodes!.push(nodeName);
|
||||
checkedNodes.push(nodeName);
|
||||
|
||||
const returnNodes: string[] = [];
|
||||
let addNodes: string[];
|
||||
|
||||
let connectionsByIndex: IConnection[];
|
||||
for (let connectionIndex = 0; connectionIndex < this.connectionsByDestinationNode[nodeName][type].length; connectionIndex++) {
|
||||
for (
|
||||
let connectionIndex = 0;
|
||||
connectionIndex < this.connectionsByDestinationNode[nodeName][type].length;
|
||||
connectionIndex++
|
||||
) {
|
||||
if (nodeConnectionIndex !== undefined && nodeConnectionIndex !== connectionIndex) {
|
||||
// If a connection-index is given ignore all other ones
|
||||
continue;
|
||||
}
|
||||
connectionsByIndex = this.connectionsByDestinationNode[nodeName][type][connectionIndex];
|
||||
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
||||
connectionsByIndex.forEach((connection) => {
|
||||
if (checkedNodes!.includes(connection.node)) {
|
||||
// Node got checked already before
|
||||
@@ -512,8 +575,6 @@ export class Workflow {
|
||||
return returnNodes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns all the after the given one
|
||||
*
|
||||
@@ -527,8 +588,6 @@ export class Workflow {
|
||||
return this.getConnectedNodes(this.connectionsBySourceNode, nodeName, type, depth);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns all the nodes before the given one
|
||||
*
|
||||
@@ -542,8 +601,6 @@ export class Workflow {
|
||||
return this.getConnectedNodes(this.connectionsByDestinationNode, nodeName, type, depth);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets all the nodes which are connected nodes starting from
|
||||
* the given one
|
||||
@@ -556,7 +613,13 @@ export class Workflow {
|
||||
* @returns {string[]}
|
||||
* @memberof Workflow
|
||||
*/
|
||||
getConnectedNodes(connections: IConnections, nodeName: string, type = 'main', depth = -1, checkedNodes?: string[]): string[] {
|
||||
getConnectedNodes(
|
||||
connections: IConnections,
|
||||
nodeName: string,
|
||||
type = 'main',
|
||||
depth = -1,
|
||||
checkedNodes?: string[],
|
||||
): string[] {
|
||||
depth = depth === -1 ? -1 : depth;
|
||||
const newDepth = depth === -1 ? depth : depth - 1;
|
||||
if (depth === 0) {
|
||||
@@ -576,12 +639,12 @@ export class Workflow {
|
||||
|
||||
checkedNodes = checkedNodes || [];
|
||||
|
||||
if (checkedNodes!.includes(nodeName)) {
|
||||
if (checkedNodes.includes(nodeName)) {
|
||||
// Node got checked already before
|
||||
return [];
|
||||
}
|
||||
|
||||
checkedNodes!.push(nodeName);
|
||||
checkedNodes.push(nodeName);
|
||||
|
||||
const returnNodes: string[] = [];
|
||||
let addNodes: string[];
|
||||
@@ -597,7 +660,13 @@ export class Workflow {
|
||||
|
||||
returnNodes.unshift(connection.node);
|
||||
|
||||
addNodes = this.getConnectedNodes(connections, connection.node, type, newDepth, checkedNodes);
|
||||
addNodes = this.getConnectedNodes(
|
||||
connections,
|
||||
connection.node,
|
||||
type,
|
||||
newDepth,
|
||||
checkedNodes,
|
||||
);
|
||||
|
||||
for (i = addNodes.length; i--; i > 0) {
|
||||
// Because nodes can have multiple parents it is possible that
|
||||
@@ -620,8 +689,6 @@ export class Workflow {
|
||||
return returnNodes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns via which output of the parent-node the node
|
||||
* is connected to.
|
||||
@@ -634,7 +701,13 @@ export class Workflow {
|
||||
* @returns {(number | undefined)}
|
||||
* @memberof Workflow
|
||||
*/
|
||||
getNodeConnectionOutputIndex(nodeName: string, parentNodeName: string, type = 'main', depth = -1, checkedNodes?: string[]): number | undefined {
|
||||
getNodeConnectionOutputIndex(
|
||||
nodeName: string,
|
||||
parentNodeName: string,
|
||||
type = 'main',
|
||||
depth = -1,
|
||||
checkedNodes?: string[],
|
||||
): number | undefined {
|
||||
const node = this.getNode(parentNodeName);
|
||||
if (node === null) {
|
||||
return undefined;
|
||||
@@ -665,12 +738,12 @@ export class Workflow {
|
||||
|
||||
checkedNodes = checkedNodes || [];
|
||||
|
||||
if (checkedNodes!.includes(nodeName)) {
|
||||
if (checkedNodes.includes(nodeName)) {
|
||||
// Node got checked already before
|
||||
return undefined;
|
||||
}
|
||||
|
||||
checkedNodes!.push(nodeName);
|
||||
checkedNodes.push(nodeName);
|
||||
|
||||
let outputIndex: number | undefined;
|
||||
for (const connectionsByIndex of this.connectionsByDestinationNode[nodeName][type]) {
|
||||
@@ -679,12 +752,18 @@ export class Workflow {
|
||||
return connection.index;
|
||||
}
|
||||
|
||||
if (checkedNodes!.includes(connection.node)) {
|
||||
if (checkedNodes.includes(connection.node)) {
|
||||
// Node got checked already before so continue with the next one
|
||||
continue;
|
||||
}
|
||||
|
||||
outputIndex = this.getNodeConnectionOutputIndex(connection.node, parentNodeName, type, newDepth, checkedNodes);
|
||||
outputIndex = this.getNodeConnectionOutputIndex(
|
||||
connection.node,
|
||||
parentNodeName,
|
||||
type,
|
||||
newDepth,
|
||||
checkedNodes,
|
||||
);
|
||||
|
||||
if (outputIndex !== undefined) {
|
||||
return outputIndex;
|
||||
@@ -695,9 +774,6 @@ export class Workflow {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns from which of the given nodes the workflow should get started from
|
||||
*
|
||||
@@ -713,7 +789,6 @@ export class Workflow {
|
||||
node = this.nodes[nodeName];
|
||||
nodeType = this.nodeTypes.getByName(node.type) as INodeType;
|
||||
|
||||
|
||||
if (nodeType.trigger !== undefined || nodeType.poll !== undefined) {
|
||||
if (node.disabled === true) {
|
||||
continue;
|
||||
@@ -734,8 +809,6 @@ export class Workflow {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the start node to start the worfklow from
|
||||
*
|
||||
@@ -744,7 +817,6 @@ export class Workflow {
|
||||
* @memberof Workflow
|
||||
*/
|
||||
getStartNode(destinationNode?: string): INode | undefined {
|
||||
|
||||
if (destinationNode) {
|
||||
// Find the highest parent nodes of the given one
|
||||
const nodeNames = this.getHighestNode(destinationNode);
|
||||
@@ -769,8 +841,6 @@ export class Workflow {
|
||||
return this.__getStartNode(Object.keys(this.nodes));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Executes the Webhooks method of the node
|
||||
*
|
||||
@@ -781,11 +851,17 @@ export class Workflow {
|
||||
* @returns {(Promise<boolean | undefined>)}
|
||||
* @memberof Workflow
|
||||
*/
|
||||
async runWebhookMethod(method: WebhookSetupMethodNames, webhookData: IWebhookData, nodeExecuteFunctions: INodeExecuteFunctions, mode: WorkflowExecuteMode, activation: WorkflowActivateMode, isTest?: boolean): Promise<boolean | undefined> {
|
||||
async runWebhookMethod(
|
||||
method: WebhookSetupMethodNames,
|
||||
webhookData: IWebhookData,
|
||||
nodeExecuteFunctions: INodeExecuteFunctions,
|
||||
mode: WorkflowExecuteMode,
|
||||
activation: WorkflowActivateMode,
|
||||
isTest?: boolean,
|
||||
): Promise<boolean | undefined> {
|
||||
const node = this.getNode(webhookData.node) as INode;
|
||||
const nodeType = this.nodeTypes.getByName(node.type) as INodeType;
|
||||
|
||||
|
||||
if (nodeType.webhookMethods === undefined) {
|
||||
return;
|
||||
}
|
||||
@@ -798,11 +874,19 @@ export class Workflow {
|
||||
return;
|
||||
}
|
||||
|
||||
const thisArgs = nodeExecuteFunctions.getExecuteHookFunctions(this, node, webhookData.workflowExecuteAdditionalData, mode, activation, isTest, webhookData);
|
||||
const thisArgs = nodeExecuteFunctions.getExecuteHookFunctions(
|
||||
this,
|
||||
node,
|
||||
webhookData.workflowExecuteAdditionalData,
|
||||
mode,
|
||||
activation,
|
||||
isTest,
|
||||
webhookData,
|
||||
);
|
||||
// eslint-disable-next-line consistent-return
|
||||
return nodeType.webhookMethods[webhookData.webhookDescription.name][method]!.call(thisArgs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Runs the given trigger node so that it can trigger the workflow
|
||||
* when the node has data.
|
||||
@@ -814,7 +898,13 @@ export class Workflow {
|
||||
* @returns {(Promise<ITriggerResponse | undefined>)}
|
||||
* @memberof Workflow
|
||||
*/
|
||||
async runTrigger(node: INode, getTriggerFunctions: IGetExecuteTriggerFunctions, additionalData: IWorkflowExecuteAdditionalData, mode: WorkflowExecuteMode, activation: WorkflowActivateMode): Promise<ITriggerResponse | undefined> {
|
||||
async runTrigger(
|
||||
node: INode,
|
||||
getTriggerFunctions: IGetExecuteTriggerFunctions,
|
||||
additionalData: IWorkflowExecuteAdditionalData,
|
||||
mode: WorkflowExecuteMode,
|
||||
activation: WorkflowActivateMode,
|
||||
): Promise<ITriggerResponse | undefined> {
|
||||
const triggerFunctions = getTriggerFunctions(this, node, additionalData, mode, activation);
|
||||
|
||||
const nodeType = this.nodeTypes.getByName(node.type);
|
||||
@@ -824,29 +914,30 @@ export class Workflow {
|
||||
}
|
||||
|
||||
if (!nodeType.trigger) {
|
||||
throw new Error(`The node type "${node.type}" of node "${node.name}" does not have a trigger function defined.`);
|
||||
throw new Error(
|
||||
`The node type "${node.type}" of node "${node.name}" does not have a trigger function defined.`,
|
||||
);
|
||||
}
|
||||
|
||||
if (mode === 'manual') {
|
||||
// In manual mode we do not just start the trigger function we also
|
||||
// want to be able to get informed as soon as the first data got emitted
|
||||
const triggerResponse = await nodeType.trigger!.call(triggerFunctions);
|
||||
const triggerResponse = await nodeType.trigger.call(triggerFunctions);
|
||||
|
||||
// Add the manual trigger response which resolves when the first time data got emitted
|
||||
triggerResponse!.manualTriggerResponse = new Promise((resolve) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
triggerFunctions.emit = ((resolve) => (data: INodeExecutionData[][]) => {
|
||||
resolve(data);
|
||||
})(resolve);
|
||||
});
|
||||
|
||||
return triggerResponse;
|
||||
} else {
|
||||
// In all other modes simply start the trigger
|
||||
return nodeType.trigger!.call(triggerFunctions);
|
||||
}
|
||||
// In all other modes simply start the trigger
|
||||
return nodeType.trigger.call(triggerFunctions);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Runs the given trigger node so that it can trigger the workflow
|
||||
* when the node has data.
|
||||
@@ -856,7 +947,10 @@ export class Workflow {
|
||||
* @returns
|
||||
* @memberof Workflow
|
||||
*/
|
||||
async runPoll(node: INode, pollFunctions: IPollFunctions): Promise<INodeExecutionData[][] | null> {
|
||||
async runPoll(
|
||||
node: INode,
|
||||
pollFunctions: IPollFunctions,
|
||||
): Promise<INodeExecutionData[][] | null> {
|
||||
const nodeType = this.nodeTypes.getByName(node.type);
|
||||
|
||||
if (nodeType === undefined) {
|
||||
@@ -864,13 +958,14 @@ export class Workflow {
|
||||
}
|
||||
|
||||
if (!nodeType.poll) {
|
||||
throw new Error(`The node type "${node.type}" of node "${node.name}" does not have a poll function defined.`);
|
||||
throw new Error(
|
||||
`The node type "${node.type}" of node "${node.name}" does not have a poll function defined.`,
|
||||
);
|
||||
}
|
||||
|
||||
return nodeType.poll!.call(pollFunctions);
|
||||
return nodeType.poll.call(pollFunctions);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Executes the webhook data to see what it should return and if the
|
||||
* workflow should be started or not
|
||||
@@ -882,7 +977,13 @@ export class Workflow {
|
||||
* @returns {Promise<IWebhookResponseData>}
|
||||
* @memberof Workflow
|
||||
*/
|
||||
async runWebhook(webhookData: IWebhookData, node: INode, additionalData: IWorkflowExecuteAdditionalData, nodeExecuteFunctions: INodeExecuteFunctions, mode: WorkflowExecuteMode): Promise<IWebhookResponseData> {
|
||||
async runWebhook(
|
||||
webhookData: IWebhookData,
|
||||
node: INode,
|
||||
additionalData: IWorkflowExecuteAdditionalData,
|
||||
nodeExecuteFunctions: INodeExecuteFunctions,
|
||||
mode: WorkflowExecuteMode,
|
||||
): Promise<IWebhookResponseData> {
|
||||
const nodeType = this.nodeTypes.getByName(node.type);
|
||||
if (nodeType === undefined) {
|
||||
throw new Error(`The type of the webhook node "${node.name}" is not known.`);
|
||||
@@ -890,11 +991,16 @@ export class Workflow {
|
||||
throw new Error(`The node "${node.name}" does not have any webhooks defined.`);
|
||||
}
|
||||
|
||||
const thisArgs = nodeExecuteFunctions.getExecuteWebhookFunctions(this, node, additionalData, mode, webhookData);
|
||||
const thisArgs = nodeExecuteFunctions.getExecuteWebhookFunctions(
|
||||
this,
|
||||
node,
|
||||
additionalData,
|
||||
mode,
|
||||
webhookData,
|
||||
);
|
||||
return nodeType.webhook.call(thisArgs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Executes the given node.
|
||||
*
|
||||
@@ -908,7 +1014,15 @@ export class Workflow {
|
||||
* @returns {(Promise<INodeExecutionData[][] | null>)}
|
||||
* @memberof Workflow
|
||||
*/
|
||||
async runNode(node: INode, inputData: ITaskDataConnections, runExecutionData: IRunExecutionData, runIndex: number, additionalData: IWorkflowExecuteAdditionalData, nodeExecuteFunctions: INodeExecuteFunctions, mode: WorkflowExecuteMode): Promise<INodeExecutionData[][] | null | undefined> {
|
||||
async runNode(
|
||||
node: INode,
|
||||
inputData: ITaskDataConnections,
|
||||
runExecutionData: IRunExecutionData,
|
||||
runIndex: number,
|
||||
additionalData: IWorkflowExecuteAdditionalData,
|
||||
nodeExecuteFunctions: INodeExecuteFunctions,
|
||||
mode: WorkflowExecuteMode,
|
||||
): Promise<INodeExecutionData[][] | null | undefined> {
|
||||
if (node.disabled === true) {
|
||||
// If node is disabled simply pass the data through
|
||||
// return NodeRunHelpers.
|
||||
@@ -917,7 +1031,7 @@ export class Workflow {
|
||||
if (inputData.main[0] === null) {
|
||||
return undefined;
|
||||
}
|
||||
return [(inputData.main[0] as INodeExecutionData[])];
|
||||
return [inputData.main[0]];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@@ -935,7 +1049,7 @@ export class Workflow {
|
||||
|
||||
if (inputData.hasOwnProperty('main') && inputData.main.length > 0) {
|
||||
// We always use the data of main input and the first input for executeSingle
|
||||
connectionInputData = (inputData.main[0] as INodeExecutionData[]);
|
||||
connectionInputData = inputData.main[0] as INodeExecutionData[];
|
||||
}
|
||||
|
||||
if (connectionInputData.length === 0) {
|
||||
@@ -944,7 +1058,10 @@ export class Workflow {
|
||||
}
|
||||
}
|
||||
|
||||
if (runExecutionData.resultData.lastNodeExecuted === node.name && runExecutionData.resultData.error !== undefined) {
|
||||
if (
|
||||
runExecutionData.resultData.lastNodeExecuted === node.name &&
|
||||
runExecutionData.resultData.error !== undefined
|
||||
) {
|
||||
// The node did already fail. So throw an error here that it displays and logs it correctly.
|
||||
// Does get used by webhook and trigger nodes in case they throw an error that it is possible
|
||||
// to log the error and display in Editor-UI.
|
||||
@@ -959,7 +1076,8 @@ export class Workflow {
|
||||
connectionInputData = connectionInputData.slice(0, 1);
|
||||
const newInputData: ITaskDataConnections = {};
|
||||
for (const inputName of Object.keys(inputData)) {
|
||||
newInputData[inputName] = inputData[inputName].map(input => {
|
||||
newInputData[inputName] = inputData[inputName].map((input) => {
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
|
||||
return input && input.slice(0, 1);
|
||||
});
|
||||
}
|
||||
@@ -970,9 +1088,19 @@ export class Workflow {
|
||||
const returnPromises: Array<Promise<INodeExecutionData>> = [];
|
||||
|
||||
for (let itemIndex = 0; itemIndex < connectionInputData.length; itemIndex++) {
|
||||
const thisArgs = nodeExecuteFunctions.getExecuteSingleFunctions(this, runExecutionData, runIndex, connectionInputData, inputData, node, itemIndex, additionalData, mode);
|
||||
const thisArgs = nodeExecuteFunctions.getExecuteSingleFunctions(
|
||||
this,
|
||||
runExecutionData,
|
||||
runIndex,
|
||||
connectionInputData,
|
||||
inputData,
|
||||
node,
|
||||
itemIndex,
|
||||
additionalData,
|
||||
mode,
|
||||
);
|
||||
|
||||
returnPromises.push(nodeType.executeSingle!.call(thisArgs));
|
||||
returnPromises.push(nodeType.executeSingle.call(thisArgs));
|
||||
}
|
||||
|
||||
if (returnPromises.length === 0) {
|
||||
@@ -990,21 +1118,41 @@ export class Workflow {
|
||||
return [promiseResults];
|
||||
}
|
||||
} else if (nodeType.execute) {
|
||||
const thisArgs = nodeExecuteFunctions.getExecuteFunctions(this, runExecutionData, runIndex, connectionInputData, inputData, node, additionalData, mode);
|
||||
const thisArgs = nodeExecuteFunctions.getExecuteFunctions(
|
||||
this,
|
||||
runExecutionData,
|
||||
runIndex,
|
||||
connectionInputData,
|
||||
inputData,
|
||||
node,
|
||||
additionalData,
|
||||
mode,
|
||||
);
|
||||
return nodeType.execute.call(thisArgs);
|
||||
} else if (nodeType.poll) {
|
||||
if (mode === 'manual') {
|
||||
// In manual mode run the poll function
|
||||
const thisArgs = nodeExecuteFunctions.getExecutePollFunctions(this, node, additionalData, mode, 'manual');
|
||||
const thisArgs = nodeExecuteFunctions.getExecutePollFunctions(
|
||||
this,
|
||||
node,
|
||||
additionalData,
|
||||
mode,
|
||||
'manual',
|
||||
);
|
||||
return nodeType.poll.call(thisArgs);
|
||||
} else {
|
||||
// In any other mode pass data through as it already contains the result of the poll
|
||||
return inputData.main as INodeExecutionData[][];
|
||||
}
|
||||
// In any other mode pass data through as it already contains the result of the poll
|
||||
return inputData.main as INodeExecutionData[][];
|
||||
} else if (nodeType.trigger) {
|
||||
if (mode === 'manual') {
|
||||
// In manual mode start the trigger
|
||||
const triggerResponse = await this.runTrigger(node, nodeExecuteFunctions.getExecuteTriggerFunctions, additionalData, mode, 'manual');
|
||||
const triggerResponse = await this.runTrigger(
|
||||
node,
|
||||
nodeExecuteFunctions.getExecuteTriggerFunctions,
|
||||
additionalData,
|
||||
mode,
|
||||
'manual',
|
||||
);
|
||||
|
||||
if (triggerResponse === undefined) {
|
||||
return null;
|
||||
@@ -1027,11 +1175,9 @@ export class Workflow {
|
||||
}
|
||||
|
||||
return response;
|
||||
} else {
|
||||
// For trigger nodes in any mode except "manual" do we simply pass the data through
|
||||
return inputData.main as INodeExecutionData[][];
|
||||
}
|
||||
|
||||
// For trigger nodes in any mode except "manual" do we simply pass the data through
|
||||
return inputData.main as INodeExecutionData[][];
|
||||
} else if (nodeType.webhook) {
|
||||
// For webhook nodes always simply pass the data through
|
||||
return inputData.main as INodeExecutionData[][];
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/* 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 */
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
import {
|
||||
IDataObject,
|
||||
INodeExecutionData,
|
||||
@@ -9,26 +18,44 @@ import {
|
||||
NodeParameterValue,
|
||||
Workflow,
|
||||
WorkflowExecuteMode,
|
||||
} from './';
|
||||
|
||||
|
||||
} from '.';
|
||||
|
||||
export class WorkflowDataProxy {
|
||||
private workflow: Workflow;
|
||||
|
||||
private runExecutionData: IRunExecutionData | null;
|
||||
|
||||
private defaultReturnRunIndex: number;
|
||||
|
||||
private runIndex: number;
|
||||
|
||||
private itemIndex: number;
|
||||
|
||||
private activeNodeName: string;
|
||||
|
||||
private connectionInputData: INodeExecutionData[];
|
||||
|
||||
private siblingParameters: INodeParameters;
|
||||
|
||||
private mode: WorkflowExecuteMode;
|
||||
|
||||
private selfData: IDataObject;
|
||||
|
||||
private additionalKeys: IWorkflowDataProxyAdditionalKeys;
|
||||
|
||||
|
||||
|
||||
constructor(workflow: Workflow, runExecutionData: IRunExecutionData | null, runIndex: number, itemIndex: number, activeNodeName: string, connectionInputData: INodeExecutionData[], siblingParameters: INodeParameters, mode: WorkflowExecuteMode, additionalKeys: IWorkflowDataProxyAdditionalKeys, defaultReturnRunIndex = -1, selfData = {}) {
|
||||
constructor(
|
||||
workflow: Workflow,
|
||||
runExecutionData: IRunExecutionData | null,
|
||||
runIndex: number,
|
||||
itemIndex: number,
|
||||
activeNodeName: string,
|
||||
connectionInputData: INodeExecutionData[],
|
||||
siblingParameters: INodeParameters,
|
||||
mode: WorkflowExecuteMode,
|
||||
additionalKeys: IWorkflowDataProxyAdditionalKeys,
|
||||
defaultReturnRunIndex = -1,
|
||||
selfData = {},
|
||||
) {
|
||||
this.workflow = workflow;
|
||||
this.runExecutionData = runExecutionData;
|
||||
this.defaultReturnRunIndex = defaultReturnRunIndex;
|
||||
@@ -42,8 +69,6 @@ export class WorkflowDataProxy {
|
||||
this.additionalKeys = additionalKeys;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns a proxy which allows to query context data of a given node
|
||||
*
|
||||
@@ -56,46 +81,51 @@ export class WorkflowDataProxy {
|
||||
const that = this;
|
||||
const node = this.workflow.nodes[nodeName];
|
||||
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
return Reflect.ownKeys(target);
|
||||
return Reflect.ownKeys(target);
|
||||
},
|
||||
get(target, name, receiver) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
name = name.toString();
|
||||
const contextData = NodeHelpers.getContext(that.runExecutionData!, 'node', node);
|
||||
|
||||
if (!contextData.hasOwnProperty(name)) {
|
||||
// Parameter does not exist on node
|
||||
throw new Error(`Could not find parameter "${name}" on context of node "${nodeName}"`);
|
||||
}
|
||||
|
||||
return contextData[name];
|
||||
},
|
||||
},
|
||||
get(target, name, receiver) {
|
||||
name = name.toString();
|
||||
const contextData = NodeHelpers.getContext(that.runExecutionData!, 'node', node);
|
||||
|
||||
if (!contextData.hasOwnProperty(name)) {
|
||||
// Parameter does not exist on node
|
||||
throw new Error(`Could not find parameter "${name}" on context of node "${nodeName}"`);
|
||||
}
|
||||
|
||||
return contextData[name];
|
||||
},
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private selfGetter() {
|
||||
const that = this;
|
||||
|
||||
return new Proxy({}, {
|
||||
ownKeys(target) {
|
||||
return Reflect.ownKeys(target);
|
||||
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];
|
||||
},
|
||||
},
|
||||
get(target, name, receiver) {
|
||||
name = name.toString();
|
||||
return that.selfData[name];
|
||||
},
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a proxy which allows to query parameter data of a given node
|
||||
*
|
||||
@@ -115,12 +145,15 @@ export class WorkflowDataProxy {
|
||||
get(target, name, receiver) {
|
||||
name = name.toString();
|
||||
|
||||
let returnValue: INodeParameters | NodeParameterValue | NodeParameterValue[] | INodeParameters[];
|
||||
let returnValue:
|
||||
| INodeParameters
|
||||
| NodeParameterValue
|
||||
| NodeParameterValue[]
|
||||
| INodeParameters[];
|
||||
if (name[0] === '&') {
|
||||
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 {
|
||||
@@ -134,7 +167,16 @@ export class WorkflowDataProxy {
|
||||
|
||||
if (typeof returnValue === 'string' && returnValue.charAt(0) === '=') {
|
||||
// The found value is an expression so resolve it
|
||||
return that.workflow.expression.getParameterValue(returnValue, that.runExecutionData, that.runIndex, that.itemIndex, that.activeNodeName, that.connectionInputData, that.mode, that.additionalKeys);
|
||||
return that.workflow.expression.getParameterValue(
|
||||
returnValue,
|
||||
that.runExecutionData,
|
||||
that.runIndex,
|
||||
that.itemIndex,
|
||||
that.activeNodeName,
|
||||
that.connectionInputData,
|
||||
that.mode,
|
||||
that.additionalKeys,
|
||||
);
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
@@ -142,7 +184,6 @@ export class WorkflowDataProxy {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the node ExecutionData
|
||||
*
|
||||
@@ -154,11 +195,16 @@ export class WorkflowDataProxy {
|
||||
* @returns {INodeExecutionData[]}
|
||||
* @memberof WorkflowDataProxy
|
||||
*/
|
||||
private getNodeExecutionData(nodeName: string, shortSyntax = false, outputIndex?: number, runIndex?: number): INodeExecutionData[] {
|
||||
private getNodeExecutionData(
|
||||
nodeName: string,
|
||||
shortSyntax = false,
|
||||
outputIndex?: number,
|
||||
runIndex?: number,
|
||||
): INodeExecutionData[] {
|
||||
const that = this;
|
||||
|
||||
let executionData: INodeExecutionData[];
|
||||
if (shortSyntax === false) {
|
||||
if (!shortSyntax) {
|
||||
// Long syntax got used to return data from node in path
|
||||
|
||||
if (that.runExecutionData === null) {
|
||||
@@ -170,7 +216,8 @@ export class WorkflowDataProxy {
|
||||
}
|
||||
|
||||
runIndex = runIndex === undefined ? that.defaultReturnRunIndex : runIndex;
|
||||
runIndex = runIndex === -1 ? (that.runExecutionData.resultData.runData[nodeName].length -1) : runIndex;
|
||||
runIndex =
|
||||
runIndex === -1 ? that.runExecutionData.resultData.runData[nodeName].length - 1 : runIndex;
|
||||
|
||||
if (that.runExecutionData.resultData.runData[nodeName].length < runIndex) {
|
||||
throw new Error(`No execution data found for run "${runIndex}" of node "${nodeName}"`);
|
||||
@@ -187,10 +234,17 @@ export class WorkflowDataProxy {
|
||||
// Depends on how the nodes are connected.
|
||||
// (example "IF" node. If node is connected to "true" or to "false" output)
|
||||
if (outputIndex === undefined) {
|
||||
const outputIndex = that.workflow.getNodeConnectionOutputIndex(that.activeNodeName, nodeName, 'main');
|
||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||
const outputIndex = that.workflow.getNodeConnectionOutputIndex(
|
||||
that.activeNodeName,
|
||||
nodeName,
|
||||
'main',
|
||||
);
|
||||
|
||||
if (outputIndex === undefined) {
|
||||
throw new Error(`The node "${that.activeNodeName}" is not connected with node "${nodeName}" so no data can get returned from it.`);
|
||||
throw new Error(
|
||||
`The node "${that.activeNodeName}" is not connected with node "${nodeName}" so no data can get returned from it.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,7 +253,9 @@ export class WorkflowDataProxy {
|
||||
}
|
||||
|
||||
if (taskData.main.length < outputIndex) {
|
||||
throw new Error(`No data found from "main" input with index "${outputIndex}" via which node is connected with.`);
|
||||
throw new Error(
|
||||
`No data found from "main" input with index "${outputIndex}" via which node is connected with.`,
|
||||
);
|
||||
}
|
||||
|
||||
executionData = taskData.main[outputIndex] as INodeExecutionData[];
|
||||
@@ -217,7 +273,6 @@ export class WorkflowDataProxy {
|
||||
return executionData;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a proxy which allows to query data of a given node
|
||||
*
|
||||
@@ -228,7 +283,6 @@ export class WorkflowDataProxy {
|
||||
* @memberof WorkflowDataGetter
|
||||
*/
|
||||
private nodeDataGetter(nodeName: string, shortSyntax = false) {
|
||||
|
||||
const that = this;
|
||||
const node = this.workflow.nodes[nodeName];
|
||||
|
||||
@@ -236,65 +290,69 @@ export class WorkflowDataProxy {
|
||||
throw new Error(`The node "${nodeName}" does not exist!`);
|
||||
}
|
||||
|
||||
return new Proxy({}, {
|
||||
get(target, name, receiver) {
|
||||
name = name.toString();
|
||||
return new Proxy(
|
||||
{},
|
||||
{
|
||||
get(target, name, receiver) {
|
||||
name = name.toString();
|
||||
|
||||
if (['binary', 'data', 'json'].includes(name)) {
|
||||
const executionData = that.getNodeExecutionData(nodeName, shortSyntax, undefined);
|
||||
if (['binary', 'data', 'json'].includes(name)) {
|
||||
const executionData = that.getNodeExecutionData(nodeName, shortSyntax, undefined);
|
||||
|
||||
if (executionData.length <= that.itemIndex) {
|
||||
throw new Error(`No data found for item-index: "${that.itemIndex}"`);
|
||||
}
|
||||
if (executionData.length <= that.itemIndex) {
|
||||
throw new Error(`No data found for item-index: "${that.itemIndex}"`);
|
||||
}
|
||||
|
||||
if (['data', 'json'].includes(name as string)) {
|
||||
// JSON-Data
|
||||
return executionData[that.itemIndex].json;
|
||||
} else if (name === 'binary') {
|
||||
// Binary-Data
|
||||
const returnData: IDataObject = {};
|
||||
if (['data', 'json'].includes(name)) {
|
||||
// JSON-Data
|
||||
return executionData[that.itemIndex].json;
|
||||
}
|
||||
if (name === 'binary') {
|
||||
// Binary-Data
|
||||
const returnData: IDataObject = {};
|
||||
|
||||
if (!executionData[that.itemIndex].binary) {
|
||||
return returnData;
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
if (!executionData[that.itemIndex].binary) {
|
||||
return returnData;
|
||||
}
|
||||
|
||||
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
|
||||
continue;
|
||||
}
|
||||
(returnData[keyName] as IDataObject)[propertyName] = binaryData[propertyName];
|
||||
}
|
||||
} 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 returnData;
|
||||
return that.runExecutionData.resultData.runData[nodeName].length - 1;
|
||||
}
|
||||
|
||||
} 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;
|
||||
}
|
||||
|
||||
return Reflect.get(target, name, receiver);
|
||||
return Reflect.get(target, name, receiver);
|
||||
},
|
||||
},
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns a proxy to query data from the environment
|
||||
*
|
||||
@@ -303,15 +361,16 @@ export class WorkflowDataProxy {
|
||||
* @memberof WorkflowDataGetter
|
||||
*/
|
||||
private envGetter() {
|
||||
return new Proxy({}, {
|
||||
get(target, name, receiver) {
|
||||
return process.env[name.toString()];
|
||||
return new Proxy(
|
||||
{},
|
||||
{
|
||||
get(target, name, receiver) {
|
||||
return process.env[name.toString()];
|
||||
},
|
||||
},
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns a proxt to query data from the workflow
|
||||
*
|
||||
@@ -320,27 +379,24 @@ export class WorkflowDataProxy {
|
||||
* @memberof WorkflowDataProxy
|
||||
*/
|
||||
private workflowGetter() {
|
||||
const allowedValues = [
|
||||
'active',
|
||||
'id',
|
||||
'name',
|
||||
];
|
||||
const allowedValues = ['active', 'id', 'name'];
|
||||
const that = this;
|
||||
|
||||
return new Proxy({}, {
|
||||
get(target, name, receiver) {
|
||||
if (!allowedValues.includes(name.toString())) {
|
||||
throw new Error(`The key "${name.toString()}" is not supported!`);
|
||||
}
|
||||
return new Proxy(
|
||||
{},
|
||||
{
|
||||
get(target, name, receiver) {
|
||||
if (!allowedValues.includes(name.toString())) {
|
||||
throw new Error(`The key "${name.toString()}" is not supported!`);
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
return that.workflow[name.toString()];
|
||||
// @ts-ignore
|
||||
return that.workflow[name.toString()];
|
||||
},
|
||||
},
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns a proxy to query data of all nodes
|
||||
*
|
||||
@@ -350,15 +406,16 @@ export class WorkflowDataProxy {
|
||||
*/
|
||||
private nodeGetter() {
|
||||
const that = this;
|
||||
return new Proxy({}, {
|
||||
get(target, name, receiver) {
|
||||
return that.nodeDataGetter(name.toString());
|
||||
return new Proxy(
|
||||
{},
|
||||
{
|
||||
get(target, name, receiver) {
|
||||
return that.nodeDataGetter(name.toString());
|
||||
},
|
||||
},
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the data proxy object which allows to query data from current run
|
||||
*
|
||||
@@ -374,11 +431,31 @@ export class WorkflowDataProxy {
|
||||
$env: this.envGetter(),
|
||||
$evaluateExpression: (expression: string, itemIndex?: number) => {
|
||||
itemIndex = itemIndex || that.itemIndex;
|
||||
return that.workflow.expression.getParameterValue('=' + expression, that.runExecutionData, that.runIndex, itemIndex, that.activeNodeName, that.connectionInputData, that.mode, that.additionalKeys);
|
||||
return that.workflow.expression.getParameterValue(
|
||||
`=${expression}`,
|
||||
that.runExecutionData,
|
||||
that.runIndex,
|
||||
itemIndex,
|
||||
that.activeNodeName,
|
||||
that.connectionInputData,
|
||||
that.mode,
|
||||
that.additionalKeys,
|
||||
);
|
||||
},
|
||||
$item: (itemIndex: number, runIndex?: number) => {
|
||||
const defaultReturnRunIndex = runIndex === undefined ? -1 : runIndex;
|
||||
const dataProxy = new WorkflowDataProxy(this.workflow, this.runExecutionData, this.runIndex, itemIndex, this.activeNodeName, this.connectionInputData, that.siblingParameters, that.mode, that.additionalKeys, defaultReturnRunIndex);
|
||||
const dataProxy = new WorkflowDataProxy(
|
||||
this.workflow,
|
||||
this.runExecutionData,
|
||||
this.runIndex,
|
||||
itemIndex,
|
||||
this.activeNodeName,
|
||||
this.connectionInputData,
|
||||
that.siblingParameters,
|
||||
that.mode,
|
||||
that.additionalKeys,
|
||||
defaultReturnRunIndex,
|
||||
);
|
||||
return dataProxy.getDataProxy();
|
||||
},
|
||||
$items: (nodeName?: string, outputIndex?: number, runIndex?: number) => {
|
||||
@@ -410,7 +487,8 @@ export class WorkflowDataProxy {
|
||||
if (['$data', '$json'].includes(name as string)) {
|
||||
// @ts-ignore
|
||||
return that.nodeDataGetter(that.activeNodeName, true).json;
|
||||
} else if (name === '$binary') {
|
||||
}
|
||||
if (name === '$binary') {
|
||||
// @ts-ignore
|
||||
return that.nodeDataGetter(that.activeNodeName, true).binary;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
import { INode } from '.';
|
||||
|
||||
/**
|
||||
@@ -5,9 +6,10 @@ import { INode } from '.';
|
||||
*/
|
||||
export class WorkflowOperationError extends Error {
|
||||
node: INode | undefined;
|
||||
|
||||
timestamp: number;
|
||||
|
||||
constructor(message: string, node?: INode, ) {
|
||||
constructor(message: string, node?: INode) {
|
||||
super(message);
|
||||
this.name = this.constructor.name;
|
||||
this.node = node;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
import {
|
||||
IWorkflowBase,
|
||||
IWorkflowExecuteHooks,
|
||||
@@ -5,16 +6,27 @@ import {
|
||||
WorkflowExecuteMode,
|
||||
} from './Interfaces';
|
||||
|
||||
|
||||
export class WorkflowHooks {
|
||||
mode: WorkflowExecuteMode;
|
||||
|
||||
workflowData: IWorkflowBase;
|
||||
|
||||
executionId: string;
|
||||
|
||||
sessionId?: string;
|
||||
|
||||
retryOf?: string;
|
||||
|
||||
hookFunctions: IWorkflowExecuteHooks;
|
||||
|
||||
constructor(hookFunctions: IWorkflowExecuteHooks, mode: WorkflowExecuteMode, executionId: string, workflowData: IWorkflowBase, optionalParameters?: IWorkflowHooksOptionalParameters) {
|
||||
constructor(
|
||||
hookFunctions: IWorkflowExecuteHooks,
|
||||
mode: WorkflowExecuteMode,
|
||||
executionId: string,
|
||||
workflowData: IWorkflowBase,
|
||||
optionalParameters?: IWorkflowHooksOptionalParameters,
|
||||
) {
|
||||
// eslint-disable-next-line no-param-reassign, @typescript-eslint/prefer-nullish-coalescing
|
||||
optionalParameters = optionalParameters || {};
|
||||
|
||||
this.hookFunctions = hookFunctions;
|
||||
@@ -25,12 +37,15 @@ export class WorkflowHooks {
|
||||
this.retryOf = optionalParameters.retryOf;
|
||||
}
|
||||
|
||||
async executeHookFunctions(hookName: string, parameters: any[]) { // tslint:disable-line:no-any
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
|
||||
async executeHookFunctions(hookName: string, parameters: any[]) {
|
||||
// tslint:disable-line:no-any
|
||||
if (this.hookFunctions[hookName] !== undefined && Array.isArray(this.hookFunctions[hookName])) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, no-restricted-syntax
|
||||
for (const hookFunction of this.hookFunctions[hookName]!) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await hookFunction.apply(this, parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/* eslint-disable import/no-cycle */
|
||||
import * as LoggerProxy from './LoggerProxy';
|
||||
import * as NodeHelpers from './NodeHelpers';
|
||||
import * as ObservableObject from './ObservableObject';
|
||||
|
||||
export * from './Interfaces';
|
||||
export * from './Expression';
|
||||
export * from './NodeErrors';
|
||||
@@ -5,12 +10,4 @@ export * from './Workflow';
|
||||
export * from './WorkflowDataProxy';
|
||||
export * from './WorkflowErrors';
|
||||
export * from './WorkflowHooks';
|
||||
|
||||
import * as LoggerProxy from './LoggerProxy';
|
||||
import * as NodeHelpers from './NodeHelpers';
|
||||
import * as ObservableObject from './ObservableObject';
|
||||
export {
|
||||
LoggerProxy,
|
||||
NodeHelpers,
|
||||
ObservableObject,
|
||||
};
|
||||
export { LoggerProxy, NodeHelpers, ObservableObject };
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
import {
|
||||
INodeType,
|
||||
INodeTypeData,
|
||||
INodeTypes,
|
||||
} from '../src';
|
||||
import { INodeType, INodeTypeData, INodeTypes } from '../src';
|
||||
|
||||
export interface INodeTypesObject {
|
||||
[key: string]: INodeType;
|
||||
}
|
||||
|
||||
class NodeTypesClass implements INodeTypes {
|
||||
|
||||
nodeTypes: INodeTypeData = {
|
||||
'test.set': {
|
||||
sourcePath: '',
|
||||
@@ -96,7 +91,7 @@ class NodeTypesClass implements INodeTypes {
|
||||
},
|
||||
};
|
||||
|
||||
async init(nodeTypes: INodeTypeData): Promise<void> { }
|
||||
async init(nodeTypes: INodeTypeData): Promise<void> {}
|
||||
|
||||
getAll(): INodeType[] {
|
||||
return Object.values(this.nodeTypes).map((data) => data.type);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,6 @@
|
||||
import {
|
||||
IDataObject,
|
||||
ObservableObject,
|
||||
} from '../src';
|
||||
|
||||
import { IDataObject, ObservableObject } from '../src';
|
||||
|
||||
describe('ObservableObject', () => {
|
||||
|
||||
test('should recognize that item on parent level got added (init empty)', () => {
|
||||
const testObject = ObservableObject.create({});
|
||||
expect(testObject.__dataChanged).toBeFalsy();
|
||||
@@ -76,7 +71,9 @@ describe('ObservableObject', () => {
|
||||
});
|
||||
|
||||
test('should recognize that item on first child level changed if it is now empty and option "ignoreEmptyOnFirstChild" === true (init data exists)', () => {
|
||||
const testObject = ObservableObject.create({ a: { b: 1 } }, undefined, { ignoreEmptyOnFirstChild: true });
|
||||
const testObject = ObservableObject.create({ a: { b: 1 } }, undefined, {
|
||||
ignoreEmptyOnFirstChild: true,
|
||||
});
|
||||
expect(testObject.__dataChanged).toBeFalsy();
|
||||
expect((testObject.a! as IDataObject).b).toEqual(1);
|
||||
testObject.a = {};
|
||||
@@ -85,7 +82,9 @@ describe('ObservableObject', () => {
|
||||
});
|
||||
|
||||
test('should recognize that item on first child level changed if it is now empty and option "ignoreEmptyOnFirstChild" === false (init data exists)', () => {
|
||||
const testObject = ObservableObject.create({ a: { b: 1 } }, undefined, { ignoreEmptyOnFirstChild: false });
|
||||
const testObject = ObservableObject.create({ a: { b: 1 } }, undefined, {
|
||||
ignoreEmptyOnFirstChild: false,
|
||||
});
|
||||
expect(testObject.__dataChanged).toBeFalsy();
|
||||
expect((testObject.a! as IDataObject).b).toEqual(1);
|
||||
testObject.a = {};
|
||||
@@ -105,7 +104,7 @@ describe('ObservableObject', () => {
|
||||
test('should recognize that item on second child level changed (init data exists)', () => {
|
||||
const testObject = ObservableObject.create({ a: { b: { c: 1 } } });
|
||||
expect(testObject.__dataChanged).toBeFalsy();
|
||||
expect((testObject.a! as IDataObject).b).toEqual({c: 1});
|
||||
expect((testObject.a! as IDataObject).b).toEqual({ c: 1 });
|
||||
expect(((testObject.a! as IDataObject).b! as IDataObject).c).toEqual(1);
|
||||
((testObject.a! as IDataObject).b! as IDataObject).c = 2;
|
||||
expect(testObject.__dataChanged).toBeTruthy();
|
||||
@@ -123,7 +122,9 @@ describe('ObservableObject', () => {
|
||||
});
|
||||
|
||||
test('should recognize that item on parent level got deleted even with and option "ignoreEmptyOnFirstChild" === true (init data exists)', () => {
|
||||
const testObject = ObservableObject.create({ a: 1 }, undefined, { ignoreEmptyOnFirstChild: true });
|
||||
const testObject = ObservableObject.create({ a: 1 }, undefined, {
|
||||
ignoreEmptyOnFirstChild: true,
|
||||
});
|
||||
expect(testObject.__dataChanged).toBeFalsy();
|
||||
expect(testObject.a!).toEqual(1);
|
||||
delete testObject.a;
|
||||
@@ -152,11 +153,6 @@ describe('ObservableObject', () => {
|
||||
expect((testObject.a! as IDataObject).b).toEqual({ c: 2 });
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// test('xxxxxx', () => {
|
||||
// const testObject = ObservableObject.create({ a: { } }, undefined, { ignoreEmptyOnFirstChild: true });
|
||||
// expect(testObject.__dataChanged).toBeFalsy();
|
||||
@@ -167,12 +163,9 @@ describe('ObservableObject', () => {
|
||||
|
||||
// // expect(testObject.a).toEqual({});
|
||||
|
||||
|
||||
|
||||
// // expect((testObject.a! as DataObject).b).toEqual({ c: 1 });
|
||||
// // expect(((testObject.a! as DataObject).b! as DataObject).c).toEqual(1);
|
||||
// // ((testObject.a! as DataObject).b! as DataObject).c = 2;
|
||||
// // expect((testObject.a! as DataObject).b).toEqual({ c: 2 });
|
||||
// });
|
||||
|
||||
});
|
||||
|
||||
@@ -16,11 +16,8 @@ interface StubNode {
|
||||
parameters: INodeParameters;
|
||||
}
|
||||
|
||||
|
||||
describe('Workflow', () => {
|
||||
|
||||
describe('renameNodeInExpressions', () => {
|
||||
|
||||
const tests = [
|
||||
{
|
||||
description: 'do nothing if there is no expression',
|
||||
@@ -43,13 +40,13 @@ describe('Workflow', () => {
|
||||
currentName: 'Node1',
|
||||
newName: 'NewName',
|
||||
parameters: {
|
||||
value1: '={{$node.Node1.data.value1 + \'Node1\'}}',
|
||||
value2: '={{$node.Node1.data.value2 + \' - \' + $node.Node1.data.value2}}',
|
||||
value1: "={{$node.Node1.data.value1 + 'Node1'}}",
|
||||
value2: "={{$node.Node1.data.value2 + ' - ' + $node.Node1.data.value2}}",
|
||||
},
|
||||
},
|
||||
output: {
|
||||
value1: '={{$node.NewName.data.value1 + \'Node1\'}}',
|
||||
value2: '={{$node.NewName.data.value2 + \' - \' + $node.NewName.data.value2}}',
|
||||
value1: "={{$node.NewName.data.value1 + 'Node1'}}",
|
||||
value2: "={{$node.NewName.data.value2 + ' - ' + $node.NewName.data.value2}}",
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -59,27 +56,31 @@ describe('Workflow', () => {
|
||||
newName: 'NewName',
|
||||
parameters: {
|
||||
value1: '={{$node["Node1"]["data"]["value1"] + \'Node1\'}}',
|
||||
value2: '={{$node["Node1"]["data"]["value2"] + \' - \' + $node["Node1"]["data"]["value2"]}}',
|
||||
value2:
|
||||
'={{$node["Node1"]["data"]["value2"] + \' - \' + $node["Node1"]["data"]["value2"]}}',
|
||||
},
|
||||
},
|
||||
output: {
|
||||
value1: '={{$node["NewName"]["data"]["value1"] + \'Node1\'}}',
|
||||
value2: '={{$node["NewName"]["data"]["value2"] + \' - \' + $node["NewName"]["data"]["value2"]}}',
|
||||
value2:
|
||||
'={{$node["NewName"]["data"]["value2"] + \' - \' + $node["NewName"]["data"]["value2"]}}',
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'should work with [\'nodeName\']',
|
||||
description: "should work with ['nodeName']",
|
||||
input: {
|
||||
currentName: 'Node1',
|
||||
newName: 'NewName',
|
||||
parameters: {
|
||||
value1: '={{$node[\'Node1\'][\'data\'][\'value1\'] + \'Node1\'}}',
|
||||
value2: '={{$node[\'Node1\'][\'data\'][\'value2\'] + \' - \' + $node[\'Node1\'][\'data\'][\'value2\']}}',
|
||||
value1: "={{$node['Node1']['data']['value1'] + 'Node1'}}",
|
||||
value2:
|
||||
"={{$node['Node1']['data']['value2'] + ' - ' + $node['Node1']['data']['value2']}}",
|
||||
},
|
||||
},
|
||||
output: {
|
||||
value1: '={{$node[\'NewName\'][\'data\'][\'value1\'] + \'Node1\'}}',
|
||||
value2: '={{$node[\'NewName\'][\'data\'][\'value2\'] + \' - \' + $node[\'NewName\'][\'data\'][\'value2\']}}',
|
||||
value1: "={{$node['NewName']['data']['value1'] + 'Node1'}}",
|
||||
value2:
|
||||
"={{$node['NewName']['data']['value2'] + ' - ' + $node['NewName']['data']['value2']}}",
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -88,22 +89,22 @@ describe('Workflow', () => {
|
||||
currentName: 'Node1',
|
||||
newName: 'NewName',
|
||||
parameters: {
|
||||
level1a: '={{$node.Node1.data.value1 + \'Node1\'}}',
|
||||
level1a: "={{$node.Node1.data.value1 + 'Node1'}}",
|
||||
level1b: [
|
||||
{
|
||||
value2a: '={{$node.Node1.data.value1 + \'Node1\'}}',
|
||||
value2b: '={{$node.Node1.data.value1 + \'Node1\'}}',
|
||||
value2a: "={{$node.Node1.data.value1 + 'Node1'}}",
|
||||
value2b: "={{$node.Node1.data.value1 + 'Node1'}}",
|
||||
},
|
||||
],
|
||||
level1c: {
|
||||
value2a: {
|
||||
value3a: '={{$node.Node1.data.value1 + \'Node1\'}}',
|
||||
value3a: "={{$node.Node1.data.value1 + 'Node1'}}",
|
||||
value3b: [
|
||||
{
|
||||
value4a: '={{$node.Node1.data.value1 + \'Node1\'}}',
|
||||
value4a: "={{$node.Node1.data.value1 + 'Node1'}}",
|
||||
value4b: {
|
||||
value5a: '={{$node.Node1.data.value1 + \'Node1\'}}',
|
||||
value5b: '={{$node.Node1.data.value1 + \'Node1\'}}',
|
||||
value5a: "={{$node.Node1.data.value1 + 'Node1'}}",
|
||||
value5b: "={{$node.Node1.data.value1 + 'Node1'}}",
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -112,22 +113,22 @@ describe('Workflow', () => {
|
||||
} as INodeParameters,
|
||||
},
|
||||
output: {
|
||||
level1a: '={{$node.NewName.data.value1 + \'Node1\'}}',
|
||||
level1a: "={{$node.NewName.data.value1 + 'Node1'}}",
|
||||
level1b: [
|
||||
{
|
||||
value2a: '={{$node.NewName.data.value1 + \'Node1\'}}',
|
||||
value2b: '={{$node.NewName.data.value1 + \'Node1\'}}',
|
||||
value2a: "={{$node.NewName.data.value1 + 'Node1'}}",
|
||||
value2b: "={{$node.NewName.data.value1 + 'Node1'}}",
|
||||
},
|
||||
],
|
||||
level1c: {
|
||||
value2a: {
|
||||
value3a: '={{$node.NewName.data.value1 + \'Node1\'}}',
|
||||
value3a: "={{$node.NewName.data.value1 + 'Node1'}}",
|
||||
value3b: [
|
||||
{
|
||||
value4a: '={{$node.NewName.data.value1 + \'Node1\'}}',
|
||||
value4a: "={{$node.NewName.data.value1 + 'Node1'}}",
|
||||
value4b: {
|
||||
value5a: '={{$node.NewName.data.value1 + \'Node1\'}}',
|
||||
value5b: '={{$node.NewName.data.value1 + \'Node1\'}}',
|
||||
value5a: "={{$node.NewName.data.value1 + 'Node1'}}",
|
||||
value5b: "={{$node.NewName.data.value1 + 'Node1'}}",
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -142,15 +143,17 @@ describe('Workflow', () => {
|
||||
|
||||
for (const testData of tests) {
|
||||
test(testData.description, () => {
|
||||
const result = workflow.renameNodeInExpressions(testData.input.parameters, testData.input.currentName, testData.input.newName);
|
||||
const result = workflow.renameNodeInExpressions(
|
||||
testData.input.parameters,
|
||||
testData.input.currentName,
|
||||
testData.input.newName,
|
||||
);
|
||||
expect(result).toEqual(testData.output);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
describe('renameNode', () => {
|
||||
|
||||
const tests = [
|
||||
{
|
||||
description: 'rename node without connections',
|
||||
@@ -507,8 +510,8 @@ describe('Workflow', () => {
|
||||
{
|
||||
name: 'Node2',
|
||||
parameters: {
|
||||
value1: '={{$node.Node1.data.value1 + \'Node1\'}}',
|
||||
value2: '={{$node.Node1.data.value2 + \' - \' + $node.Node1.data.value2}}',
|
||||
value1: "={{$node.Node1.data.value1 + 'Node1'}}",
|
||||
value2: "={{$node.Node1.data.value2 + ' - ' + $node.Node1.data.value2}}",
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -526,8 +529,8 @@ describe('Workflow', () => {
|
||||
{
|
||||
name: 'Node2',
|
||||
parameters: {
|
||||
value1: '={{$node.Node1New.data.value1 + \'Node1\'}}',
|
||||
value2: '={{$node.Node1New.data.value2 + \' - \' + $node.Node1New.data.value2}}',
|
||||
value1: "={{$node.Node1New.data.value1 + 'Node1'}}",
|
||||
value2: "={{$node.Node1New.data.value2 + ' - ' + $node.Node1New.data.value2}}",
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -545,10 +548,7 @@ describe('Workflow', () => {
|
||||
parameters: stubData.parameters,
|
||||
type: 'test.set',
|
||||
typeVersion: 1,
|
||||
position: [
|
||||
100,
|
||||
100,
|
||||
],
|
||||
position: [100, 100],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -559,13 +559,17 @@ describe('Workflow', () => {
|
||||
|
||||
for (const testData of tests) {
|
||||
test(testData.description, () => {
|
||||
|
||||
executeNodes = [];
|
||||
for (const node of testData.input.nodes) {
|
||||
executeNodes.push(createNodeData(node));
|
||||
}
|
||||
|
||||
workflow = new Workflow({ nodes: executeNodes, connections: testData.input.connections as IConnections, active: false, nodeTypes });
|
||||
workflow = new Workflow({
|
||||
nodes: executeNodes,
|
||||
connections: testData.input.connections as IConnections,
|
||||
active: false,
|
||||
nodeTypes,
|
||||
});
|
||||
workflow.renameNode(testData.input.currentName, testData.input.newName);
|
||||
|
||||
resultNodes = {};
|
||||
@@ -577,12 +581,9 @@ describe('Workflow', () => {
|
||||
expect(workflow.connectionsBySourceNode).toEqual(testData.output.connections);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('getParameterValue', () => {
|
||||
|
||||
const tests = [
|
||||
{
|
||||
description: 'read simple not expression value',
|
||||
@@ -639,7 +640,8 @@ describe('Workflow', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'read data from node-output-data with with long "$node.{NODE}.data" syntax add value and append text',
|
||||
description:
|
||||
'read data from node-output-data with with long "$node.{NODE}.data" syntax add value and append text',
|
||||
input: {
|
||||
Node1: {
|
||||
parameters: {
|
||||
@@ -657,7 +659,8 @@ describe('Workflow', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'read deep-data from node-output-data with with long "$node.{NODE}.data" syntax with JavaScript Code',
|
||||
description:
|
||||
'read deep-data from node-output-data with with long "$node.{NODE}.data" syntax with JavaScript Code',
|
||||
input: {
|
||||
Node1: {
|
||||
parameters: {
|
||||
@@ -727,7 +730,8 @@ describe('Workflow', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'read deep-data from node-output-data with with long "$node.{NODE}.data" syntax',
|
||||
description:
|
||||
'read deep-data from node-output-data with with long "$node.{NODE}.data" syntax',
|
||||
input: {
|
||||
Node1: {
|
||||
parameters: {
|
||||
@@ -753,7 +757,8 @@ describe('Workflow', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'read binary-string-data from incoming-node-data with with short "$binary" syntax',
|
||||
description:
|
||||
'read binary-string-data from incoming-node-data with with short "$binary" syntax',
|
||||
input: {
|
||||
Node1: {
|
||||
parameters: {
|
||||
@@ -779,7 +784,8 @@ describe('Workflow', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'read binary-string-data from node-output-data with with long "$node.{NODE}.binary" syntax',
|
||||
description:
|
||||
'read binary-string-data from node-output-data with with long "$node.{NODE}.binary" syntax',
|
||||
input: {
|
||||
Node1: {
|
||||
parameters: {
|
||||
@@ -879,7 +885,8 @@ describe('Workflow', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'return resolved value when referencing another property with expression (long "$node.{NODE}.data" syntax)',
|
||||
description:
|
||||
'return resolved value when referencing another property with expression (long "$node.{NODE}.data" syntax)',
|
||||
input: {
|
||||
Node1: {
|
||||
parameters: {
|
||||
@@ -899,7 +906,8 @@ describe('Workflow', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'return resolved value when referencing another property with expression (short "data" syntax)',
|
||||
description:
|
||||
'return resolved value when referencing another property with expression (short "data" syntax)',
|
||||
input: {
|
||||
Node1: {
|
||||
parameters: {
|
||||
@@ -919,7 +927,8 @@ describe('Workflow', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'return resolved value when referencing another property with expression when a node has spaces (long "$node["{NODE}"].parameter" syntax)',
|
||||
description:
|
||||
'return resolved value when referencing another property with expression when a node has spaces (long "$node["{NODE}"].parameter" syntax)',
|
||||
input: {
|
||||
Node1: {
|
||||
parameters: {
|
||||
@@ -937,7 +946,8 @@ describe('Workflow', () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
description: 'return resolved value when referencing another property with expression on another node (long "$node["{NODE}"].parameter" syntax)',
|
||||
description:
|
||||
'return resolved value when referencing another property with expression on another node (long "$node["{NODE}"].parameter" syntax)',
|
||||
input: {
|
||||
Node1: {
|
||||
parameters: {
|
||||
@@ -987,75 +997,67 @@ describe('Workflow', () => {
|
||||
// },
|
||||
];
|
||||
|
||||
|
||||
const nodeTypes = Helpers.NodeTypes();
|
||||
|
||||
for (const testData of tests) {
|
||||
test(testData.description, () => {
|
||||
|
||||
const nodes: INode[] = [
|
||||
{
|
||||
"name": "Node1",
|
||||
"parameters": testData.input.Node1.parameters,
|
||||
"type": "test.set",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
100,
|
||||
100,
|
||||
],
|
||||
name: 'Node1',
|
||||
parameters: testData.input.Node1.parameters,
|
||||
type: 'test.set',
|
||||
typeVersion: 1,
|
||||
position: [100, 100],
|
||||
},
|
||||
{
|
||||
"name": "Node2",
|
||||
"parameters": testData.input.Node2.parameters,
|
||||
"type": "test.set",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
100,
|
||||
200,
|
||||
],
|
||||
name: 'Node2',
|
||||
parameters: testData.input.Node2.parameters,
|
||||
type: 'test.set',
|
||||
typeVersion: 1,
|
||||
position: [100, 200],
|
||||
},
|
||||
{
|
||||
"name": "Node3",
|
||||
name: 'Node3',
|
||||
// @ts-ignore
|
||||
"parameters": testData.input.hasOwnProperty('Node3') ? testData.input.Node3.parameters : {},
|
||||
"type": "test.set",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
100,
|
||||
300,
|
||||
],
|
||||
parameters: testData.input.hasOwnProperty('Node3')
|
||||
? // @ts-ignore
|
||||
testData.input.Node3.parameters
|
||||
: {},
|
||||
type: 'test.set',
|
||||
typeVersion: 1,
|
||||
position: [100, 300],
|
||||
},
|
||||
{
|
||||
"name": "Node 4 with spaces",
|
||||
name: 'Node 4 with spaces',
|
||||
// @ts-ignore
|
||||
"parameters": testData.input.hasOwnProperty('Node4') ? testData.input.Node4.parameters : {},
|
||||
"type": "test.set",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
100,
|
||||
400,
|
||||
],
|
||||
parameters: testData.input.hasOwnProperty('Node4')
|
||||
? // @ts-ignore
|
||||
testData.input.Node4.parameters
|
||||
: {},
|
||||
type: 'test.set',
|
||||
typeVersion: 1,
|
||||
position: [100, 400],
|
||||
},
|
||||
];
|
||||
const connections: IConnections = {
|
||||
"Node1": {
|
||||
"main": [
|
||||
Node1: {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
"node": "Node2",
|
||||
"type": "main",
|
||||
"index": 0,
|
||||
node: 'Node2',
|
||||
type: 'main',
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
"Node2": {
|
||||
"main": [
|
||||
Node2: {
|
||||
main: [
|
||||
[
|
||||
{
|
||||
"node": "Node3",
|
||||
"type": "main",
|
||||
"index": 0,
|
||||
node: 'Node3',
|
||||
type: 'main',
|
||||
index: 0,
|
||||
},
|
||||
],
|
||||
],
|
||||
@@ -1093,19 +1095,29 @@ describe('Workflow', () => {
|
||||
|
||||
const itemIndex = 0;
|
||||
const runIndex = 0;
|
||||
const connectionInputData: INodeExecutionData[] = runExecutionData.resultData.runData!['Node1']![0]!.data!.main[0]!;
|
||||
const connectionInputData: INodeExecutionData[] =
|
||||
runExecutionData.resultData.runData!['Node1']![0]!.data!.main[0]!;
|
||||
|
||||
for (const parameterName of Object.keys(testData.output)) {
|
||||
const parameterValue = nodes.find((node) => node.name === activeNodeName)!.parameters[parameterName];
|
||||
const result = workflow.expression.getParameterValue(parameterValue, runExecutionData, runIndex, itemIndex, activeNodeName, connectionInputData, 'manual', {});
|
||||
const parameterValue = nodes.find((node) => node.name === activeNodeName)!.parameters[
|
||||
parameterName
|
||||
];
|
||||
const result = workflow.expression.getParameterValue(
|
||||
parameterValue,
|
||||
runExecutionData,
|
||||
runIndex,
|
||||
itemIndex,
|
||||
activeNodeName,
|
||||
connectionInputData,
|
||||
'manual',
|
||||
{},
|
||||
);
|
||||
// @ts-ignore
|
||||
expect(result).toEqual(testData.output[parameterName]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
// test('should be able to set and read key data without initial data set', () => {
|
||||
|
||||
// const nodes: Node[] = [
|
||||
@@ -1175,7 +1187,6 @@ describe('Workflow', () => {
|
||||
// ]
|
||||
// };
|
||||
|
||||
|
||||
// const itemIndex = 0;
|
||||
// const connectionInputData: NodeExecutionData[] = runData!['Node1']![0]!.data!.main[0]!;
|
||||
|
||||
@@ -1184,34 +1195,29 @@ describe('Workflow', () => {
|
||||
// expect(result).toEqual('outputSet1');
|
||||
// });
|
||||
|
||||
|
||||
test('should also resolve all child parameters when the parent get requested', () => {
|
||||
|
||||
const nodeTypes = Helpers.NodeTypes();
|
||||
|
||||
const nodes: INode[] = [
|
||||
{
|
||||
"name": "Node1",
|
||||
"parameters": {
|
||||
"values": {
|
||||
"string": [
|
||||
name: 'Node1',
|
||||
parameters: {
|
||||
values: {
|
||||
string: [
|
||||
{
|
||||
"name": "name1",
|
||||
"value": "value1",
|
||||
name: 'name1',
|
||||
value: 'value1',
|
||||
},
|
||||
{
|
||||
"name": "name2",
|
||||
"value": "={{$parameter.values.string[0].value}}A",
|
||||
name: 'name2',
|
||||
value: '={{$parameter.values.string[0].value}}A',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
"type": "test.setMulti",
|
||||
"typeVersion": 1,
|
||||
"position": [
|
||||
100,
|
||||
100,
|
||||
],
|
||||
type: 'test.setMulti',
|
||||
typeVersion: 1,
|
||||
position: [100, 100],
|
||||
},
|
||||
];
|
||||
const connections: IConnections = {};
|
||||
@@ -1243,11 +1249,23 @@ describe('Workflow', () => {
|
||||
|
||||
const itemIndex = 0;
|
||||
const runIndex = 0;
|
||||
const connectionInputData: INodeExecutionData[] = runExecutionData.resultData.runData!['Node1']![0]!.data!.main[0]!;
|
||||
const connectionInputData: INodeExecutionData[] =
|
||||
runExecutionData.resultData.runData!['Node1']![0]!.data!.main[0]!;
|
||||
const parameterName = 'values';
|
||||
|
||||
const parameterValue = nodes.find((node) => node.name === activeNodeName)!.parameters[parameterName];
|
||||
const result = workflow.expression.getParameterValue(parameterValue, runExecutionData, runIndex, itemIndex, activeNodeName, connectionInputData, 'manual', {});
|
||||
const parameterValue = nodes.find((node) => node.name === activeNodeName)!.parameters[
|
||||
parameterName
|
||||
];
|
||||
const result = workflow.expression.getParameterValue(
|
||||
parameterValue,
|
||||
runExecutionData,
|
||||
runIndex,
|
||||
itemIndex,
|
||||
activeNodeName,
|
||||
connectionInputData,
|
||||
'manual',
|
||||
{},
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
string: [
|
||||
@@ -1261,9 +1279,6 @@ describe('Workflow', () => {
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user