2021-09-21 10:38:24 -07:00
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
2021-08-29 11:58:11 -07:00
/* 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' ;
2019-06-23 03:35:23 -07:00
import {
IContextObject ,
INode ,
2020-10-22 06:46:03 -07:00
INodeCredentialDescription ,
2019-06-23 03:35:23 -07:00
INodeExecutionData ,
INodeIssueObjectProperty ,
2020-10-22 06:46:03 -07:00
INodeIssues ,
2019-06-23 03:35:23 -07:00
INodeParameters ,
INodeProperties ,
INodePropertyCollection ,
INodeType ,
2021-09-21 10:38:24 -07:00
INodeVersionedType ,
2019-07-13 10:50:41 -07:00
IParameterDependencies ,
2019-06-23 03:35:23 -07:00
IRunExecutionData ,
IWebhookData ,
2019-07-13 10:50:41 -07:00
IWorkflowExecuteAdditionalData ,
2019-06-23 03:35:23 -07:00
NodeParameterValue ,
WebhookHttpMethod ,
} from './Interfaces' ;
2021-08-29 11:58:11 -07:00
import { Workflow } from './Workflow' ;
2019-12-31 12:19:37 -08:00
/ * *
* Gets special parameters which should be added to nodeTypes depending
* on their type or configuration
*
* @export
* @param { INodeType } nodeType
* @returns
* /
2021-09-21 10:38:24 -07:00
export function getSpecialNodeParameters ( nodeType : INodeType ) : INodeProperties [ ] {
2019-12-31 12:19:37 -08:00
if ( nodeType . description . polling === true ) {
return [
{
displayName : 'Poll Times' ,
name : 'pollTimes' ,
type : 'fixedCollection' ,
typeOptions : {
multipleValues : true ,
multipleValueButtonText : 'Add Poll Time' ,
} ,
default : { } ,
2021-12-04 02:11:22 -08:00
description : 'Time at which polling should occur' ,
2019-12-31 12:19:37 -08:00
placeholder : 'Add Poll Time' ,
options : [
{
name : 'item' ,
displayName : 'Item' ,
values : [
{
displayName : 'Mode' ,
name : 'mode' ,
type : 'options' ,
options : [
{
name : 'Every Minute' ,
value : 'everyMinute' ,
} ,
{
name : 'Every Hour' ,
value : 'everyHour' ,
} ,
{
name : 'Every Day' ,
value : 'everyDay' ,
} ,
{
name : 'Every Week' ,
value : 'everyWeek' ,
} ,
{
name : 'Every Month' ,
value : 'everyMonth' ,
} ,
2019-12-31 15:41:47 -08:00
{
name : 'Every X' ,
value : 'everyX' ,
} ,
2019-12-31 12:19:37 -08:00
{
name : 'Custom' ,
value : 'custom' ,
} ,
] ,
default : 'everyDay' ,
description : 'How often to trigger.' ,
} ,
{
displayName : 'Hour' ,
name : 'hour' ,
type : 'number' ,
typeOptions : {
minValue : 0 ,
maxValue : 23 ,
} ,
displayOptions : {
hide : {
2021-08-29 11:58:11 -07:00
mode : [ 'custom' , 'everyHour' , 'everyMinute' , 'everyX' ] ,
2019-12-31 12:19:37 -08:00
} ,
} ,
default : 14 ,
2021-12-04 02:11:22 -08:00
description : 'The hour of the day to trigger (24h format)' ,
2019-12-31 12:19:37 -08:00
} ,
{
displayName : 'Minute' ,
name : 'minute' ,
type : 'number' ,
typeOptions : {
minValue : 0 ,
maxValue : 59 ,
} ,
displayOptions : {
hide : {
2021-08-29 11:58:11 -07:00
mode : [ 'custom' , 'everyMinute' , 'everyX' ] ,
2019-12-31 12:19:37 -08:00
} ,
} ,
default : 0 ,
2021-12-04 02:11:22 -08:00
description : 'The minute of the day to trigger' ,
2019-12-31 12:19:37 -08:00
} ,
{
displayName : 'Day of Month' ,
name : 'dayOfMonth' ,
type : 'number' ,
displayOptions : {
show : {
2021-08-29 11:58:11 -07:00
mode : [ 'everyMonth' ] ,
2019-12-31 12:19:37 -08:00
} ,
} ,
typeOptions : {
minValue : 1 ,
maxValue : 31 ,
} ,
default : 1 ,
2021-12-04 02:11:22 -08:00
description : 'The day of the month to trigger' ,
2019-12-31 12:19:37 -08:00
} ,
{
displayName : 'Weekday' ,
name : 'weekday' ,
type : 'options' ,
displayOptions : {
show : {
2021-08-29 11:58:11 -07:00
mode : [ 'everyWeek' ] ,
2019-12-31 12:19:37 -08:00
} ,
} ,
options : [
{
name : 'Monday' ,
value : '1' ,
} ,
{
name : 'Tuesday' ,
value : '2' ,
} ,
{
name : 'Wednesday' ,
value : '3' ,
} ,
{
name : 'Thursday' ,
value : '4' ,
} ,
{
name : 'Friday' ,
value : '5' ,
} ,
{
name : 'Saturday' ,
value : '6' ,
} ,
{
name : 'Sunday' ,
value : '0' ,
} ,
] ,
default : '1' ,
2021-12-04 02:11:22 -08:00
description : 'The weekday to trigger' ,
2019-12-31 12:19:37 -08:00
} ,
{
displayName : 'Cron Expression' ,
name : 'cronExpression' ,
type : 'string' ,
displayOptions : {
show : {
2021-08-29 11:58:11 -07:00
mode : [ 'custom' ] ,
2019-12-31 12:19:37 -08:00
} ,
} ,
default : '* * * * * *' ,
2021-08-29 11:58:11 -07:00
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>' ,
2019-12-31 12:19:37 -08:00
} ,
2019-12-31 15:41:47 -08:00
{
displayName : 'Value' ,
name : 'value' ,
type : 'number' ,
typeOptions : {
minValue : 0 ,
maxValue : 1000 ,
} ,
displayOptions : {
show : {
2021-08-29 11:58:11 -07:00
mode : [ 'everyX' ] ,
2019-12-31 15:41:47 -08:00
} ,
} ,
default : 2 ,
2021-12-04 02:11:22 -08:00
description : 'All how many X minutes/hours it should trigger' ,
2019-12-31 15:41:47 -08:00
} ,
{
displayName : 'Unit' ,
name : 'unit' ,
type : 'options' ,
displayOptions : {
show : {
2021-08-29 11:58:11 -07:00
mode : [ 'everyX' ] ,
2019-12-31 15:41:47 -08:00
} ,
} ,
options : [
{
name : 'Minutes' ,
2020-10-22 06:46:03 -07:00
value : 'minutes' ,
2019-12-31 15:41:47 -08:00
} ,
{
name : 'Hours' ,
2020-10-22 06:46:03 -07:00
value : 'hours' ,
2019-12-31 15:41:47 -08:00
} ,
] ,
default : 'hours' ,
2021-12-04 02:11:22 -08:00
description : 'If it should trigger all X minutes or hours' ,
2019-12-31 15:41:47 -08:00
} ,
2019-12-31 12:19:37 -08:00
] ,
} ,
] ,
} ,
] ;
}
return [ ] ;
}
2019-06-23 03:35:23 -07:00
/ * *
* Returns if the parameter should be displayed or not
*
* @export
* @param { INodeParameters } nodeValues The data on the node which decides if the parameter
* should be displayed
* @param { ( INodeProperties | INodeCredentialDescription ) } parameter The parameter to check if it should be displayed
* @param { INodeParameters } [ nodeValuesRoot ] The root node - parameter - data
* @returns
* /
2021-08-29 11:58:11 -07:00
export function displayParameter (
nodeValues : INodeParameters ,
parameter : INodeProperties | INodeCredentialDescription ,
nodeValuesRoot? : INodeParameters ,
) {
2019-06-23 03:35:23 -07:00
if ( ! parameter . displayOptions ) {
return true ;
}
nodeValuesRoot = nodeValuesRoot || nodeValues ;
let value ;
2021-08-29 11:58:11 -07:00
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const values : any [ ] = [ ] ;
2019-06-23 03:35:23 -07:00
if ( parameter . displayOptions . show ) {
// All the defined rules have to match to display parameter
for ( const propertyName of Object . keys ( parameter . displayOptions . show ) ) {
if ( propertyName . charAt ( 0 ) === '/' ) {
// Get the value from the root of the node
2020-01-10 10:57:01 -08:00
value = get ( nodeValuesRoot , propertyName . slice ( 1 ) ) ;
2019-06-23 03:35:23 -07:00
} else {
// Get the value from current level
2020-01-10 10:57:01 -08:00
value = get ( nodeValues , propertyName ) ;
2019-06-23 03:35:23 -07:00
}
2020-05-08 10:49:57 -07:00
values . length = 0 ;
if ( ! Array . isArray ( value ) ) {
values . push ( value ) ;
} else {
values . push . apply ( values , value ) ;
}
2021-08-29 11:58:11 -07:00
if ( values . some ( ( v ) = > typeof v === 'string' && v . charAt ( 0 ) === '=' ) ) {
2021-05-15 15:51:14 -07:00
return true ;
}
2021-08-29 11:58:11 -07:00
if (
values . length === 0 ||
2021-09-21 10:38:24 -07:00
! parameter . displayOptions . show [ propertyName ] ! . some ( ( v ) = > values . includes ( v ) )
2021-08-29 11:58:11 -07:00
) {
2019-06-23 03:35:23 -07:00
return false ;
}
}
}
if ( parameter . displayOptions . hide ) {
2021-08-29 04:58:20 -07:00
// Any of the defined hide rules have to match to hide the parameter
2019-06-23 03:35:23 -07:00
for ( const propertyName of Object . keys ( parameter . displayOptions . hide ) ) {
if ( propertyName . charAt ( 0 ) === '/' ) {
// Get the value from the root of the node
2020-01-10 10:57:01 -08:00
value = get ( nodeValuesRoot , propertyName . slice ( 1 ) ) ;
2019-06-23 03:35:23 -07:00
} else {
// Get the value from current level
2020-01-10 10:57:01 -08:00
value = get ( nodeValues , propertyName ) ;
2019-06-23 03:35:23 -07:00
}
2020-05-08 10:49:57 -07:00
values . length = 0 ;
if ( ! Array . isArray ( value ) ) {
values . push ( value ) ;
} else {
values . push . apply ( values , value ) ;
}
2021-08-29 11:58:11 -07:00
if (
values . length !== 0 &&
2021-09-21 10:38:24 -07:00
parameter . displayOptions . hide [ propertyName ] ! . some ( ( v ) = > values . includes ( v ) )
2021-08-29 11:58:11 -07:00
) {
2019-06-23 03:35:23 -07:00
return false ;
}
}
}
return true ;
}
/ * *
* Returns if the given parameter should be displayed or not considering the path
* to the properties
*
* @export
* @param { INodeParameters } nodeValues The data on the node which decides if the parameter
* should be displayed
* @param { ( INodeProperties | INodeCredentialDescription ) } parameter The parameter to check if it should be displayed
* @param { string } path The path to the property
* @returns
* /
2021-08-29 11:58:11 -07:00
export function displayParameterPath (
nodeValues : INodeParameters ,
parameter : INodeProperties | INodeCredentialDescription ,
path : string ,
) {
2019-06-23 03:35:23 -07:00
let resolvedNodeValues = nodeValues ;
if ( path !== '' ) {
2021-08-29 11:58:11 -07:00
resolvedNodeValues = get ( nodeValues , path ) as INodeParameters ;
2019-06-23 03:35:23 -07:00
}
// Get the root parameter data
let nodeValuesRoot = nodeValues ;
if ( path && path . split ( '.' ) . indexOf ( 'parameters' ) === 0 ) {
2021-08-29 11:58:11 -07:00
nodeValuesRoot = get ( nodeValues , 'parameters' ) as INodeParameters ;
2019-06-23 03:35:23 -07:00
}
return displayParameter ( resolvedNodeValues , parameter , nodeValuesRoot ) ;
}
/ * *
* Returns the context data
*
* @export
* @param { IRunExecutionData } runExecutionData The run execution data
* @param { string } type The data type . "node" / "flow"
* @param { INode } [ node ] If type "node" is set the node to return the context of has to be supplied
* @returns { IContextObject }
* /
2021-08-29 11:58:11 -07:00
export function getContext (
runExecutionData : IRunExecutionData ,
type : string ,
node? : INode ,
) : IContextObject {
2019-06-23 03:35:23 -07:00
if ( runExecutionData . executionData === undefined ) {
// TODO: Should not happen leave it for test now
throw new Error ( 'The "executionData" is not initialized!' ) ;
}
let key : string ;
if ( type === 'flow' ) {
key = 'flow' ;
} else if ( type === 'node' ) {
if ( node === undefined ) {
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 "flow" and node" are supported! ` ) ;
}
if ( runExecutionData . executionData . contextData [ key ] === undefined ) {
2021-08-29 11:58:11 -07:00
// eslint-disable-next-line no-param-reassign
2019-06-23 03:35:23 -07:00
runExecutionData . executionData . contextData [ key ] = { } ;
}
return runExecutionData . executionData . contextData [ key ] ;
}
2019-07-13 10:50:41 -07:00
/ * *
* Returns which parameters are dependent on which
*
* @export
* @param { INodeProperties [ ] } nodePropertiesArray
* @returns { IParameterDependencies }
* /
2021-08-29 11:58:11 -07:00
export function getParamterDependencies (
nodePropertiesArray : INodeProperties [ ] ,
) : IParameterDependencies {
2019-07-13 10:50:41 -07:00
const dependencies : IParameterDependencies = { } ;
let displayRule : string ;
let parameterName : string ;
for ( const nodeProperties of nodePropertiesArray ) {
if ( dependencies [ nodeProperties . name ] === undefined ) {
dependencies [ nodeProperties . name ] = [ ] ;
}
if ( nodeProperties . displayOptions === undefined ) {
// Does not have any dependencies
continue ;
}
for ( displayRule of Object . keys ( nodeProperties . displayOptions ) ) {
// @ts-ignore
for ( parameterName of Object . keys ( nodeProperties . displayOptions [ displayRule ] ) ) {
if ( ! dependencies [ nodeProperties . name ] . includes ( parameterName ) ) {
dependencies [ nodeProperties . name ] . push ( parameterName ) ;
}
}
}
}
return dependencies ;
}
/ * *
* Returns in which order the parameters should be resolved
2021-08-29 04:58:20 -07:00
* to have the parameters available they depend on
2019-07-13 10:50:41 -07:00
*
* @export
* @param { INodeProperties [ ] } nodePropertiesArray
* @param { IParameterDependencies } parameterDependencies
* @returns { number [ ] }
* /
2021-08-29 11:58:11 -07:00
export function getParamterResolveOrder (
nodePropertiesArray : INodeProperties [ ] ,
parameterDependencies : IParameterDependencies ,
) : number [ ] {
2019-07-13 10:50:41 -07:00
const executionOrder : number [ ] = [ ] ;
const indexToResolve = Array . from ( { length : nodePropertiesArray.length } , ( v , k ) = > k ) ;
const resolvedParamters : string [ ] = [ ] ;
let index : number ;
let property : INodeProperties ;
let lastIndexLength = indexToResolve . length ;
let lastIndexReduction = - 1 ;
2021-08-29 11:58:11 -07:00
let iterations = 0 ;
2019-07-13 10:50:41 -07:00
while ( indexToResolve . length !== 0 ) {
2021-08-29 05:00:22 -07:00
iterations += 1 ;
2019-07-13 10:50:41 -07:00
index = indexToResolve . shift ( ) as number ;
property = nodePropertiesArray [ index ] ;
if ( parameterDependencies [ property . name ] . length === 0 ) {
// Does not have any dependencies so simply add
executionOrder . push ( index ) ;
resolvedParamters . push ( property . name ) ;
continue ;
}
// Parameter has dependencies
for ( const dependency of parameterDependencies [ property . name ] ) {
if ( ! resolvedParamters . includes ( dependency ) ) {
if ( dependency . charAt ( 0 ) === '/' ) {
// Assume that root level depenencies are resolved
continue ;
}
// Dependencies for that paramter are still missing so
// try to add again later
indexToResolve . push ( index ) ;
continue ;
}
}
// All dependencies got found so add
executionOrder . push ( index ) ;
resolvedParamters . push ( property . name ) ;
if ( indexToResolve . length < lastIndexLength ) {
2021-08-29 05:00:22 -07:00
lastIndexReduction = iterations ;
2019-07-13 10:50:41 -07:00
}
2021-08-29 05:00:22 -07:00
if ( iterations > lastIndexReduction + nodePropertiesArray . length ) {
2021-08-29 11:58:11 -07:00
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.' ,
) ;
2019-07-13 10:50:41 -07:00
}
lastIndexLength = indexToResolve . length ;
}
return executionOrder ;
}
2019-06-23 03:35:23 -07:00
/ * *
* Returns the node parameter values . Depending on the settings it either just returns the none
* default values or it applies all the default values .
*
* @export
* @param { INodeProperties [ ] } nodePropertiesArray The properties which exist and their settings
* @param { INodeParameters } nodeValues The node parameter data
* @param { boolean } returnDefaults If default values get added or only none default values returned
* @param { boolean } returnNoneDisplayed If also values which should not be displayed should be returned
* @param { boolean } [ onlySimpleTypes = false ] If only simple types should be resolved
* @param { boolean } [ dataIsResolved = false ] If nodeValues are already fully resolved ( so that all default values got added already )
* @param { INodeParameters } [ nodeValuesRoot ] The root node - parameter - data
* @returns { ( INodeParameters | null ) }
* /
2021-08-29 11:58:11 -07:00
export function getNodeParameters (
nodePropertiesArray : INodeProperties [ ] ,
nodeValues : INodeParameters ,
returnDefaults : boolean ,
returnNoneDisplayed : boolean ,
onlySimpleTypes = false ,
dataIsResolved = false ,
nodeValuesRoot? : INodeParameters ,
parentType? : string ,
parameterDependencies? : IParameterDependencies ,
) : INodeParameters | null {
2019-07-13 10:50:41 -07:00
if ( parameterDependencies === undefined ) {
parameterDependencies = getParamterDependencies ( nodePropertiesArray ) ;
}
2019-07-12 11:58:52 -07:00
// Get the parameter names which get used multiple times as for this
// ones we have to always check which ones get displayed and which ones not
const duplicateParameterNames : string [ ] = [ ] ;
const parameterNames : string [ ] = [ ] ;
for ( const nodeProperties of nodePropertiesArray ) {
if ( parameterNames . includes ( nodeProperties . name ) ) {
if ( ! duplicateParameterNames . includes ( nodeProperties . name ) ) {
duplicateParameterNames . push ( nodeProperties . name ) ;
}
} else {
parameterNames . push ( nodeProperties . name ) ;
}
}
2019-06-23 03:35:23 -07:00
const nodeParameters : INodeParameters = { } ;
2019-07-13 10:50:41 -07:00
const nodeParametersFull : INodeParameters = { } ;
2019-06-23 03:35:23 -07:00
2019-07-13 10:50:41 -07:00
let nodeValuesDisplayCheck = nodeParametersFull ;
2021-08-29 11:58:11 -07:00
if ( ! dataIsResolved && ! returnNoneDisplayed ) {
nodeValuesDisplayCheck = getNodeParameters (
nodePropertiesArray ,
nodeValues ,
true ,
true ,
true ,
true ,
nodeValuesRoot ,
parentType ,
parameterDependencies ,
) as INodeParameters ;
2019-06-23 03:35:23 -07:00
}
nodeValuesRoot = nodeValuesRoot || nodeValuesDisplayCheck ;
2019-07-13 10:50:41 -07:00
// Go through the parameters in order of their dependencies
2021-08-29 11:58:11 -07:00
const parameterItterationOrderIndex = getParamterResolveOrder (
nodePropertiesArray ,
parameterDependencies ,
) ;
2019-07-13 10:50:41 -07:00
for ( const parameterIndex of parameterItterationOrderIndex ) {
const nodeProperties = nodePropertiesArray [ parameterIndex ] ;
2021-08-29 11:58:11 -07:00
if (
nodeValues [ nodeProperties . name ] === undefined &&
( ! returnDefaults || parentType === 'collection' )
) {
2019-06-23 03:35:23 -07:00
// The value is not defined so go to the next
continue ;
}
2021-08-29 11:58:11 -07:00
if (
! returnNoneDisplayed &&
! displayParameter ( nodeValuesDisplayCheck , nodeProperties , nodeValuesRoot )
) {
if ( ! returnNoneDisplayed || ! returnDefaults ) {
2019-06-23 03:35:23 -07:00
continue ;
}
}
if ( ! [ 'collection' , 'fixedCollection' ] . includes ( nodeProperties . type ) ) {
// Is a simple property so can be set as it is
2019-07-12 11:58:52 -07:00
if ( duplicateParameterNames . includes ( nodeProperties . name ) ) {
if ( ! displayParameter ( nodeValuesDisplayCheck , nodeProperties , nodeValuesRoot ) ) {
continue ;
}
}
2021-08-29 11:58:11 -07:00
if ( returnDefaults ) {
2019-06-23 03:35:23 -07:00
// Set also when it has the default value
2019-11-30 15:24:25 -08:00
if ( [ 'boolean' , 'number' , 'options' ] . includes ( nodeProperties . type ) ) {
// Boolean, numbers and options are special as false and 0 are valid values
2019-06-23 03:35:23 -07:00
// and should not be replaced with default value
2021-08-29 11:58:11 -07:00
nodeParameters [ nodeProperties . name ] =
nodeValues [ nodeProperties . name ] !== undefined
? nodeValues [ nodeProperties . name ]
: nodeProperties . default ;
2019-06-23 03:35:23 -07:00
} else {
2021-08-29 11:58:11 -07:00
nodeParameters [ nodeProperties . name ] =
nodeValues [ nodeProperties . name ] || nodeProperties . default ;
2019-06-23 03:35:23 -07:00
}
2019-07-13 10:50:41 -07:00
nodeParametersFull [ nodeProperties . name ] = nodeParameters [ nodeProperties . name ] ;
2021-08-29 11:58:11 -07:00
} 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' )
) {
2019-06-23 03:35:23 -07:00
// Set only if it is different to the default value
nodeParameters [ nodeProperties . name ] = nodeValues [ nodeProperties . name ] ;
2019-07-13 10:50:41 -07:00
nodeParametersFull [ nodeProperties . name ] = nodeParameters [ nodeProperties . name ] ;
2019-06-23 03:35:23 -07:00
continue ;
}
}
2021-08-29 11:58:11 -07:00
if ( onlySimpleTypes ) {
2019-06-23 03:35:23 -07:00
// It is only supposed to resolve the simple types. So continue.
continue ;
}
// Is a complex property so check lower levels
let tempValue : INodeParameters | null ;
if ( nodeProperties . type === 'collection' ) {
// Is collection
2021-08-29 11:58:11 -07:00
if (
nodeProperties . typeOptions !== undefined &&
nodeProperties . typeOptions . multipleValues === true
) {
2019-06-23 03:35:23 -07:00
// 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 ] ;
2021-08-29 11:58:11 -07:00
} else if ( returnDefaults ) {
2021-05-19 16:44:27 -07:00
// Does not have values defined but defaults should be returned
2021-05-19 17:26:29 -07:00
if ( Array . isArray ( nodeProperties . default ) ) {
2021-08-29 11:58:11 -07:00
nodeParameters [ nodeProperties . name ] = JSON . parse (
JSON . stringify ( nodeProperties . default ) ,
) ;
2021-05-19 17:26:29 -07:00
} 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
nodeParameters [ nodeProperties . name ] = [ ] ;
}
2019-06-23 03:35:23 -07:00
}
2019-07-13 10:50:41 -07:00
nodeParametersFull [ nodeProperties . name ] = nodeParameters [ nodeProperties . name ] ;
2021-08-29 11:58:11 -07:00
} 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 ;
2019-07-13 10:50:41 -07:00
nodeParametersFull [ nodeProperties . name ] = nodeParameters [ nodeProperties . name ] ;
2019-06-23 03:35:23 -07:00
}
2021-08-29 11:58:11 -07:00
} 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 ] ;
2019-06-23 03:35:23 -07:00
}
} else if ( nodeProperties . type === 'fixedCollection' ) {
// Is fixedCollection
const collectionValues : INodeParameters = { } ;
let tempNodeParameters : INodeParameters ;
let tempNodePropertiesArray : INodeProperties [ ] ;
let nodePropertyOptions : INodePropertyCollection | undefined ;
let propertyValues = nodeValues [ nodeProperties . name ] ;
2021-08-29 11:58:11 -07:00
if ( returnDefaults ) {
2019-06-23 03:35:23 -07:00
if ( propertyValues === undefined ) {
propertyValues = JSON . parse ( JSON . stringify ( nodeProperties . default ) ) ;
}
}
2021-01-23 11:00:32 -08:00
// Iterate over all collections
2020-10-26 01:26:07 -07:00
for ( const itemName of Object . keys ( propertyValues || { } ) ) {
2021-08-29 11:58:11 -07:00
if (
nodeProperties . typeOptions !== undefined &&
nodeProperties . typeOptions . multipleValues === true
) {
2019-06-23 03:35:23 -07:00
// Multiple can be set so will be an array
const tempArrayValue : INodeParameters [ ] = [ ] ;
2021-01-23 11:00:32 -08:00
// Iterate over all items as it contains multiple ones
2021-08-29 11:58:11 -07:00
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 ;
2019-06-23 03:35:23 -07:00
if ( nodePropertyOptions === undefined ) {
2021-08-29 11:58:11 -07:00
throw new Error (
` Could not find property option " ${ itemName } " for " ${ nodeProperties . name } " ` ,
) ;
2019-06-23 03:35:23 -07:00
}
2021-08-29 11:58:11 -07:00
tempNodePropertiesArray = nodePropertyOptions . values ! ;
tempValue = getNodeParameters (
tempNodePropertiesArray ,
nodeValue ,
returnDefaults ,
returnNoneDisplayed ,
false ,
false ,
nodeValuesRoot ,
nodeProperties . type ,
) ;
2019-06-23 03:35:23 -07:00
if ( tempValue !== null ) {
tempArrayValue . push ( tempValue ) ;
}
}
collectionValues [ itemName ] = tempArrayValue ;
} else {
// Only one can be set so is an object of objects
tempNodeParameters = { } ;
// Get the options of the current item
2021-08-29 11:58:11 -07:00
// eslint-disable-next-line @typescript-eslint/no-shadow
const nodePropertyOptions = nodeProperties . options ! . find (
( data ) = > data . name === itemName ,
) ;
2019-06-23 03:35:23 -07:00
if ( nodePropertyOptions !== undefined ) {
tempNodePropertiesArray = ( nodePropertyOptions as INodePropertyCollection ) . values ! ;
2021-08-29 11:58:11 -07:00
tempValue = getNodeParameters (
tempNodePropertiesArray ,
( nodeValues [ nodeProperties . name ] as INodeParameters ) [ itemName ] as INodeParameters ,
returnDefaults ,
returnNoneDisplayed ,
false ,
false ,
nodeValuesRoot ,
nodeProperties . type ,
) ;
2019-06-23 03:35:23 -07:00
if ( tempValue !== null ) {
Object . assign ( tempNodeParameters , tempValue ) ;
}
}
if ( Object . keys ( tempNodeParameters ) . length !== 0 ) {
collectionValues [ itemName ] = tempNodeParameters ;
}
}
}
2021-08-29 11:58:11 -07:00
if ( Object . keys ( collectionValues ) . length !== 0 || returnDefaults ) {
2019-06-23 03:35:23 -07:00
// Set only if value got found
2021-08-29 11:58:11 -07:00
if ( returnDefaults ) {
2019-06-23 03:35:23 -07:00
// Set also when it has the default value
if ( collectionValues === undefined ) {
2021-08-29 11:58:11 -07:00
nodeParameters [ nodeProperties . name ] = JSON . parse (
JSON . stringify ( nodeProperties . default ) ,
) ;
2019-06-23 03:35:23 -07:00
} else {
nodeParameters [ nodeProperties . name ] = collectionValues ;
}
2019-07-13 10:50:41 -07:00
nodeParametersFull [ nodeProperties . name ] = nodeParameters [ nodeProperties . name ] ;
2019-06-23 03:35:23 -07:00
} else if ( collectionValues !== nodeProperties . default ) {
// Set only if values got found and it is not the default
nodeParameters [ nodeProperties . name ] = collectionValues ;
2019-07-13 10:50:41 -07:00
nodeParametersFull [ nodeProperties . name ] = nodeParameters [ nodeProperties . name ] ;
2019-06-23 03:35:23 -07:00
}
}
}
}
return nodeParameters ;
}
/ * *
* Brings the output data in a format that can be returned from a node
*
* @export
* @param { INodeExecutionData [ ] } outputData
* @param { number } [ outputIndex = 0 ]
* @returns { Promise < INodeExecutionData [ ] [ ] > }
* /
2021-08-29 11:58:11 -07:00
export async function prepareOutputData (
outputData : INodeExecutionData [ ] ,
outputIndex = 0 ,
) : Promise < INodeExecutionData [ ] [ ] > {
2019-06-23 03:35:23 -07:00
// TODO: Check if node has output with that index
const returnData = [ ] ;
for ( let i = 0 ; i < outputIndex ; i ++ ) {
returnData . push ( [ ] ) ;
}
returnData . push ( outputData ) ;
return returnData ;
}
/ * *
* Returns all the webhooks which should be created for the give node
*
* @export
*
* @param { INode } node
* @returns { IWebhookData [ ] }
* /
2021-08-29 11:58:11 -07:00
export function getNodeWebhooks (
workflow : Workflow ,
node : INode ,
additionalData : IWorkflowExecuteAdditionalData ,
ignoreRestartWehbooks = false ,
) : IWebhookData [ ] {
2019-06-23 03:35:23 -07:00
if ( node . disabled === true ) {
// Node is disabled so webhooks will also not be enabled
return [ ] ;
}
2021-09-21 10:38:24 -07:00
const nodeType = workflow . nodeTypes . getByNameAndVersion ( node . type , node . typeVersion ) as INodeType ;
2019-06-23 03:35:23 -07:00
if ( nodeType . description . webhooks === undefined ) {
// Node does not have any webhooks so return
return [ ] ;
}
2020-05-03 08:55:14 -07:00
const workflowId = workflow . id || '__UNSAVED__' ;
2021-01-29 00:31:40 -08:00
const mode = 'internal' ;
2020-05-03 08:55:14 -07:00
2019-06-23 03:35:23 -07:00
const returnData : IWebhookData [ ] = [ ] ;
for ( const webhookDescription of nodeType . description . webhooks ) {
2021-08-29 11:58:11 -07:00
if ( ignoreRestartWehbooks && webhookDescription . restartWebhook === true ) {
2021-08-21 05:11:32 -07:00
continue ;
}
2021-08-29 11:58:11 -07:00
let nodeWebhookPath = workflow . expression . getSimpleParameterValue (
node ,
webhookDescription . path ,
mode ,
{ } ,
) ;
2019-06-23 03:35:23 -07:00
if ( nodeWebhookPath === undefined ) {
// TODO: Use a proper logger
2021-08-29 11:58:11 -07:00
console . error (
` No webhook path could be found for node " ${ node . name } " in workflow " ${ workflowId } ". ` ,
) ;
2019-06-23 03:35:23 -07:00
continue ;
}
2019-08-01 09:22:48 -07:00
nodeWebhookPath = nodeWebhookPath . toString ( ) ;
2021-02-09 00:14:40 -08:00
if ( nodeWebhookPath . startsWith ( '/' ) ) {
2019-06-23 03:35:23 -07:00
nodeWebhookPath = nodeWebhookPath . slice ( 1 ) ;
}
2021-02-09 00:14:40 -08:00
if ( nodeWebhookPath . endsWith ( '/' ) ) {
nodeWebhookPath = nodeWebhookPath . slice ( 0 , - 1 ) ;
}
2019-06-23 03:35:23 -07:00
2021-08-29 11:58:11 -07:00
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 ;
2021-08-21 05:11:32 -07:00
const path = getNodeWebhookPath ( workflowId , node , nodeWebhookPath , isFullPath , restartWebhook ) ;
2019-06-23 03:35:23 -07:00
2021-08-29 11:58:11 -07:00
const httpMethod = workflow . expression . getSimpleParameterValue (
node ,
webhookDescription . httpMethod ,
mode ,
{ } ,
'GET' ,
) ;
2019-06-23 03:35:23 -07:00
if ( httpMethod === undefined ) {
// TODO: Use a proper logger
2021-08-29 11:58:11 -07:00
console . error (
` The webhook " ${ path } " for node " ${ node . name } " in workflow " ${ workflowId } " could not be added because the httpMethod is not defined. ` ,
) ;
2019-06-23 03:35:23 -07:00
continue ;
}
2021-01-23 11:00:32 -08:00
let webhookId : string | undefined ;
if ( ( path . startsWith ( ':' ) || path . includes ( '/:' ) ) && node . webhookId ) {
webhookId = node . webhookId ;
}
2019-06-23 03:35:23 -07:00
returnData . push ( {
2019-08-01 09:22:48 -07:00
httpMethod : httpMethod.toString ( ) as WebhookHttpMethod ,
2019-06-23 03:35:23 -07:00
node : node.name ,
path ,
webhookDescription ,
2020-05-03 08:55:14 -07:00
workflowId ,
2019-06-23 03:35:23 -07:00
workflowExecuteAdditionalData : additionalData ,
2021-01-23 11:00:32 -08:00
webhookId ,
2019-06-23 03:35:23 -07:00
} ) ;
}
return returnData ;
}
2020-05-27 16:32:49 -07:00
export function getNodeWebhooksBasic ( workflow : Workflow , node : INode ) : IWebhookData [ ] {
if ( node . disabled === true ) {
// Node is disabled so webhooks will also not be enabled
return [ ] ;
}
2021-09-21 10:38:24 -07:00
const nodeType = workflow . nodeTypes . getByNameAndVersion ( node . type , node . typeVersion ) as INodeType ;
2020-05-27 16:32:49 -07:00
if ( nodeType . description . webhooks === undefined ) {
// Node does not have any webhooks so return
return [ ] ;
}
const workflowId = workflow . id || '__UNSAVED__' ;
2021-01-29 00:31:40 -08:00
const mode = 'internal' ;
2020-05-27 16:32:49 -07:00
const returnData : IWebhookData [ ] = [ ] ;
for ( const webhookDescription of nodeType . description . webhooks ) {
2021-08-29 11:58:11 -07:00
let nodeWebhookPath = workflow . expression . getSimpleParameterValue (
node ,
webhookDescription . path ,
mode ,
{ } ,
) ;
2020-05-27 16:32:49 -07:00
if ( nodeWebhookPath === undefined ) {
// TODO: Use a proper logger
2021-08-29 11:58:11 -07:00
console . error (
` No webhook path could be found for node " ${ node . name } " in workflow " ${ workflowId } ". ` ,
) ;
2020-05-27 16:32:49 -07:00
continue ;
}
nodeWebhookPath = nodeWebhookPath . toString ( ) ;
2021-02-09 00:14:40 -08:00
if ( nodeWebhookPath . startsWith ( '/' ) ) {
2020-05-27 16:32:49 -07:00
nodeWebhookPath = nodeWebhookPath . slice ( 1 ) ;
}
2021-02-09 00:14:40 -08:00
if ( nodeWebhookPath . endsWith ( '/' ) ) {
nodeWebhookPath = nodeWebhookPath . slice ( 0 , - 1 ) ;
}
2020-05-27 16:32:49 -07:00
2021-08-29 11:58:11 -07:00
const isFullPath : boolean = workflow . expression . getSimpleParameterValue (
node ,
webhookDescription . isFullPath ,
mode ,
{ } ,
false ,
) as boolean ;
2020-05-27 16:32:49 -07:00
2020-06-10 06:39:15 -07:00
const path = getNodeWebhookPath ( workflowId , node , nodeWebhookPath , isFullPath ) ;
2021-08-29 11:58:11 -07:00
const httpMethod = workflow . expression . getSimpleParameterValue (
node ,
webhookDescription . httpMethod ,
mode ,
{ } ,
) ;
2020-05-27 16:32:49 -07:00
if ( httpMethod === undefined ) {
// TODO: Use a proper logger
2021-08-29 11:58:11 -07:00
console . error (
` The webhook " ${ path } " for node " ${ node . name } " in workflow " ${ workflowId } " could not be added because the httpMethod is not defined. ` ,
) ;
2020-05-27 16:32:49 -07:00
continue ;
}
2021-08-29 11:58:11 -07:00
// @ts-ignore
2020-05-27 16:32:49 -07:00
returnData . push ( {
httpMethod : httpMethod.toString ( ) as WebhookHttpMethod ,
node : node.name ,
path ,
webhookDescription ,
workflowId ,
} ) ;
}
return returnData ;
}
2019-06-23 03:35:23 -07:00
/ * *
* Returns the webhook path
*
* @export
* @param { string } workflowId
* @param { string } nodeTypeName
* @param { string } path
* @returns { string }
* /
2021-08-29 11:58:11 -07:00
export function getNodeWebhookPath (
workflowId : string ,
node : INode ,
path : string ,
isFullPath? : boolean ,
restartWebhook? : boolean ,
) : string {
2020-05-27 16:32:49 -07:00
let webhookPath = '' ;
2021-08-21 05:11:32 -07:00
if ( restartWebhook === true ) {
return path ;
2021-08-29 11:58:11 -07:00
}
if ( node . webhookId === undefined ) {
2020-05-27 16:32:49 -07:00
webhookPath = ` ${ workflowId } / ${ encodeURIComponent ( node . name . toLowerCase ( ) ) } / ${ path } ` ;
} else {
2020-06-10 06:39:15 -07:00
if ( isFullPath === true ) {
2020-05-27 16:32:49 -07:00
return path ;
}
2020-06-10 07:17:16 -07:00
webhookPath = ` ${ node . webhookId } / ${ path } ` ;
2020-05-27 16:32:49 -07:00
}
return webhookPath ;
2019-06-23 03:35:23 -07:00
}
/ * *
* Returns the webhook URL
*
* @export
* @param { string } baseUrl
* @param { string } workflowId
* @param { string } nodeTypeName
* @param { string } path
2020-06-10 06:39:15 -07:00
* @param { boolean } isFullPath
2019-06-23 03:35:23 -07:00
* @returns { string }
* /
2021-08-29 11:58:11 -07:00
export function getNodeWebhookUrl (
baseUrl : string ,
workflowId : string ,
node : INode ,
path : string ,
isFullPath? : boolean ,
) : string {
2021-01-23 11:00:32 -08:00
if ( ( path . startsWith ( ':' ) || path . includes ( '/:' ) ) && node . webhookId ) {
// setting this to false to prefix the webhookId
isFullPath = false ;
}
if ( path . startsWith ( '/' ) ) {
path = path . slice ( 1 ) ;
}
2020-06-10 06:39:15 -07:00
return ` ${ baseUrl } / ${ getNodeWebhookPath ( workflowId , node , path , isFullPath ) } ` ;
2019-06-23 03:35:23 -07:00
}
/ * *
* Returns all the parameter - issues of the node
*
* @export
* @param { INodeProperties [ ] } nodePropertiesArray The properties of the node
* @param { INode } node The data of the node
* @returns { ( INodeIssues | null ) }
* /
2021-08-29 11:58:11 -07:00
export function getNodeParametersIssues (
nodePropertiesArray : INodeProperties [ ] ,
node : INode ,
) : INodeIssues | null {
2019-06-23 03:35:23 -07:00
const foundIssues : INodeIssues = { } ;
let propertyIssues : INodeIssues ;
2019-07-07 10:17:34 -07:00
if ( node . disabled === true ) {
// Ignore issues on disabled nodes
return null ;
}
2019-06-23 03:35:23 -07:00
for ( const nodeProperty of nodePropertiesArray ) {
propertyIssues = getParameterIssues ( nodeProperty , node . parameters , '' ) ;
mergeIssues ( foundIssues , propertyIssues ) ;
}
if ( Object . keys ( foundIssues ) . length === 0 ) {
return null ;
}
return foundIssues ;
}
/ * *
* Returns the issues of the node as string
*
* @export
* @param { INodeIssues } issues The issues of the node
* @param { INode } node The node
* @returns { string [ ] }
* /
export function nodeIssuesToString ( issues : INodeIssues , node? : INode ) : string [ ] {
const nodeIssues = [ ] ;
if ( issues . execution !== undefined ) {
nodeIssues . push ( ` Execution Error. ` ) ;
}
2021-08-29 11:58:11 -07:00
const objectProperties = [ 'parameters' , 'credentials' ] ;
2019-06-23 03:35:23 -07:00
2021-08-29 11:58:11 -07:00
let issueText : string ;
let parameterName : string ;
2019-06-23 03:35:23 -07:00
for ( const propertyName of objectProperties ) {
if ( issues [ propertyName ] !== undefined ) {
for ( parameterName of Object . keys ( issues [ propertyName ] as object ) ) {
for ( issueText of ( issues [ propertyName ] as INodeIssueObjectProperty ) [ parameterName ] ) {
nodeIssues . push ( issueText ) ;
}
}
}
}
if ( issues . typeUnknown !== undefined ) {
if ( node !== undefined ) {
nodeIssues . push ( ` Node Type " ${ node . type } " is not known. ` ) ;
} else {
nodeIssues . push ( ` Node Type is not known. ` ) ;
}
}
return nodeIssues ;
}
/ * *
* Adds an issue if the parameter is not defined
*
* @export
* @param { INodeIssues } foundIssues The already found issues
* @param { INodeProperties } nodeProperties The properties of the node
* @param { NodeParameterValue } value The value of the parameter
* /
2021-08-29 11:58:11 -07:00
export function addToIssuesIfMissing (
foundIssues : INodeIssues ,
nodeProperties : INodeProperties ,
value : NodeParameterValue ,
) {
2019-06-23 03:35:23 -07:00
// TODO: Check what it really has when undefined
2021-08-29 11:58:11 -07:00
if (
( nodeProperties . type === 'string' && ( value === '' || value === undefined ) ) ||
2019-06-23 03:35:23 -07:00
( nodeProperties . type === 'multiOptions' && Array . isArray ( value ) && value . length === 0 ) ||
2021-08-29 11:58:11 -07:00
( nodeProperties . type === 'dateTime' && value === undefined )
) {
2019-06-23 03:35:23 -07:00
// Parameter is requried but empty
if ( foundIssues . parameters === undefined ) {
foundIssues . parameters = { } ;
}
if ( foundIssues . parameters [ nodeProperties . name ] === undefined ) {
foundIssues . parameters [ nodeProperties . name ] = [ ] ;
}
2021-08-29 11:58:11 -07:00
foundIssues . parameters [ nodeProperties . name ] . push (
` Parameter " ${ nodeProperties . displayName } " is required. ` ,
) ;
2019-06-23 03:35:23 -07:00
}
}
/ * *
* Returns the parameter value
*
* @export
* @param { INodeParameters } nodeValues The values of the node
* @param { string } parameterName The name of the parameter to return the value of
* @param { string } path The path to the properties
* @returns
* /
2021-08-29 11:58:11 -07:00
export function getParameterValueByPath (
nodeValues : INodeParameters ,
parameterName : string ,
path : string ,
) {
return get ( nodeValues , path ? ` ${ path } . ${ parameterName } ` : parameterName ) ;
2019-06-23 03:35:23 -07:00
}
/ * *
* Returns all the issues with the given node - values
*
* @export
* @param { INodeProperties } nodeProperties The properties of the node
* @param { INodeParameters } nodeValues The values of the node
* @param { string } path The path to the properties
* @returns { INodeIssues }
* /
2021-08-29 11:58:11 -07:00
export function getParameterIssues (
nodeProperties : INodeProperties ,
nodeValues : INodeParameters ,
path : string ,
) : INodeIssues {
2019-06-23 03:35:23 -07:00
const foundIssues : INodeIssues = { } ;
let value ;
if ( nodeProperties . required === true ) {
if ( displayParameterPath ( nodeValues , nodeProperties , path ) ) {
value = getParameterValueByPath ( nodeValues , nodeProperties . name , path ) ;
2021-08-29 11:58:11 -07:00
if (
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
nodeProperties . typeOptions !== undefined &&
nodeProperties . typeOptions . multipleValues !== undefined
) {
2019-06-23 03:35:23 -07:00
// Multiple can be set so will be an array
if ( Array . isArray ( value ) ) {
for ( const singleValue of value as NodeParameterValue [ ] ) {
2021-08-29 11:58:11 -07:00
addToIssuesIfMissing ( foundIssues , nodeProperties , singleValue ) ;
2019-06-23 03:35:23 -07:00
}
}
} else {
// Only one can be set so will be a single value
addToIssuesIfMissing ( foundIssues , nodeProperties , value as NodeParameterValue ) ;
}
}
}
// Check if there are any child parameters
if ( nodeProperties . options === undefined ) {
// There are none so nothing else to check
return foundIssues ;
}
// Check the child parameters
// Important:
// Checks the child properties only if the property is defined on current level.
// That means that the required flag works only for the current level only. If
// it is set on a lower level it means that the property is only required in case
// the parent property got set.
let basePath = path ? ` ${ path } . ` : '' ;
const checkChildNodeProperties : Array < {
basePath : string ;
data : INodeProperties ;
} > = [ ] ;
// Collect all the properties to check
if ( nodeProperties . type === 'collection' ) {
for ( const option of nodeProperties . options ) {
checkChildNodeProperties . push ( {
basePath ,
data : option as INodeProperties ,
} ) ;
}
} else if ( nodeProperties . type === 'fixedCollection' ) {
2021-08-29 11:58:11 -07:00
basePath = basePath ? ` ${ basePath } . ` : ` ${ nodeProperties . name } . ` ;
2019-06-23 03:35:23 -07:00
let propertyOptions : INodePropertyCollection ;
for ( propertyOptions of nodeProperties . options as INodePropertyCollection [ ] ) {
// Check if the option got set and if not skip it
value = getParameterValueByPath ( nodeValues , propertyOptions . name , basePath . slice ( 0 , - 1 ) ) ;
if ( value === undefined ) {
continue ;
}
2021-08-29 11:58:11 -07:00
if (
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain
nodeProperties . typeOptions !== undefined &&
nodeProperties . typeOptions . multipleValues !== undefined
) {
2019-06-23 03:35:23 -07:00
// 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 } ] ` ,
2021-08-29 11:58:11 -07:00
data : option ,
2019-06-23 03:35:23 -07:00
} ) ;
}
}
}
} else {
// Only one can be set so will be an object
for ( const option of propertyOptions . values ) {
checkChildNodeProperties . push ( {
basePath : basePath + propertyOptions . name ,
2021-08-29 11:58:11 -07:00
data : option ,
2019-06-23 03:35:23 -07:00
} ) ;
}
}
}
} else {
// For all other types there is nothing to check so return
return foundIssues ;
}
let propertyIssues ;
for ( const optionData of checkChildNodeProperties ) {
2021-08-29 11:58:11 -07:00
propertyIssues = getParameterIssues ( optionData . data , nodeValues , optionData . basePath ) ;
2019-06-23 03:35:23 -07:00
mergeIssues ( foundIssues , propertyIssues ) ;
}
return foundIssues ;
}
/ * *
* Merges multiple NodeIssues together
*
* @export
* @param { INodeIssues } destination The issues to merge into
* @param { ( INodeIssues | null ) } source The issues to merge
* @returns
* /
export function mergeIssues ( destination : INodeIssues , source : INodeIssues | null ) {
if ( source === null ) {
// Nothing to merge
return ;
}
if ( source . execution === true ) {
destination . execution = true ;
}
2021-08-29 11:58:11 -07:00
const objectProperties = [ 'parameters' , 'credentials' ] ;
2019-06-23 03:35:23 -07:00
let destinationProperty : INodeIssueObjectProperty ;
for ( const propertyName of objectProperties ) {
if ( source [ propertyName ] !== undefined ) {
if ( destination [ propertyName ] === undefined ) {
destination [ propertyName ] = { } ;
}
let parameterName : string ;
for ( parameterName of Object . keys ( source [ propertyName ] as INodeIssueObjectProperty ) ) {
destinationProperty = destination [ propertyName ] as INodeIssueObjectProperty ;
if ( destinationProperty [ parameterName ] === undefined ) {
destinationProperty [ parameterName ] = [ ] ;
}
2021-08-29 11:58:11 -07:00
destinationProperty [ parameterName ] . push . apply (
destinationProperty [ parameterName ] ,
( source [ propertyName ] as INodeIssueObjectProperty ) [ parameterName ] ,
) ;
2019-06-23 03:35:23 -07:00
}
}
}
if ( source . typeUnknown === true ) {
destination . typeUnknown = true ;
}
}
2020-05-16 10:05:40 -07:00
/ * *
* Merges the given node properties
*
* @export
* @param { INodeProperties [ ] } mainProperties
* @param { INodeProperties [ ] } addProperties
* /
2021-08-29 11:58:11 -07:00
export function mergeNodeProperties (
mainProperties : INodeProperties [ ] ,
addProperties : INodeProperties [ ] ,
) : void {
2020-05-16 10:05:40 -07:00
let existingIndex : number ;
for ( const property of addProperties ) {
2021-08-29 11:58:11 -07:00
existingIndex = mainProperties . findIndex ( ( element ) = > element . name === property . name ) ;
2020-05-16 10:05:40 -07:00
if ( existingIndex === - 1 ) {
// Property does not exist yet, so add
mainProperties . push ( property ) ;
} else {
// Property exists already, so overwrite
mainProperties [ existingIndex ] = property ;
}
}
}
2021-09-21 10:38:24 -07:00
2021-11-15 02:19:43 -08:00
export function getVersionedNodeType (
2021-09-21 10:38:24 -07:00
object : INodeVersionedType | INodeType ,
version? : number ,
) : INodeType {
if ( isNodeTypeVersioned ( object ) ) {
return ( object as INodeVersionedType ) . getNodeType ( version ) ;
}
return object as INodeType ;
}
2021-11-15 02:19:43 -08:00
export function getVersionedNodeTypeAll ( object : INodeVersionedType | INodeType ) : INodeType [ ] {
2021-09-21 10:38:24 -07:00
if ( isNodeTypeVersioned ( object ) ) {
return Object . values ( ( object as INodeVersionedType ) . nodeVersions ) . map ( ( element ) = > {
element . description . name = object . description . name ;
return element ;
} ) ;
}
return [ object as INodeType ] ;
}
export function isNodeTypeVersioned ( object : INodeVersionedType | INodeType ) : boolean {
return ! ! ( 'getNodeType' in object ) ;
}