diff --git a/packages/workflow/src/Expression.ts b/packages/workflow/src/Expression.ts index c804e55241..794331dc1b 100644 --- a/packages/workflow/src/Expression.ts +++ b/packages/workflow/src/Expression.ts @@ -1,5 +1,3 @@ -/* eslint-disable id-denylist */ -// @ts-ignore import * as tmpl from '@n8n_io/riot-tmpl'; import { DateTime, Duration, Interval } from 'luxon'; @@ -12,20 +10,17 @@ import { INodeParameters, IRunExecutionData, IWorkflowDataProxyAdditionalKeys, + IWorkflowDataProxyData, NodeParameterValue, Workflow, WorkflowDataProxy, WorkflowExecuteMode, } from '.'; -// @ts-ignore - // 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 error get forwarded -// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access tmpl.tmpl.errorHandler = (error: Error) => { if (error instanceof ExpressionError) { if (error.context.failExecution) { @@ -114,7 +109,6 @@ export class Expression { const data = dataProxy.getDataProxy(); // Support only a subset of process properties - // @ts-ignore data.process = { arch: process.arch, env: process.env, @@ -130,7 +124,6 @@ export class Expression { * Denylist */ - // @ts-ignore data.document = {}; data.global = {}; data.window = {}; @@ -223,11 +216,13 @@ export class Expression { data.Intl = typeof Intl !== 'undefined' ? Intl : {}; // Text + // eslint-disable-next-line id-denylist data.String = String; data.RegExp = RegExp; // Math data.Math = Math; + // eslint-disable-next-line id-denylist data.Number = Number; data.BigInt = typeof BigInt !== 'undefined' ? BigInt : {}; data.Infinity = Infinity; @@ -250,15 +245,28 @@ export class Expression { data.decodeURIComponent = decodeURIComponent; // Other + // eslint-disable-next-line id-denylist data.Boolean = Boolean; data.Symbol = Symbol; // Execute the expression - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let returnValue; + const returnValue = this.renderExpression(parameterValue, data); + if (typeof returnValue === 'function') { + throw new Error('Expression resolved to a function. Please add "()"'); + } else if (typeof returnValue === 'string') { + return returnValue; + } else if (returnValue !== null && typeof returnValue === 'object') { + if (returnObjectAsString) { + return this.convertObjectValueToString(returnValue); + } + } + + return returnValue; + } + + private renderExpression(expression: string, data: IWorkflowDataProxyData): tmpl.ReturnValue { try { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call - returnValue = tmpl.tmpl(parameterValue, data); + return tmpl.tmpl(expression, data); } catch (error) { if (error instanceof ExpressionError) { // Ignore all errors except if they are ExpressionErrors and they are supposed @@ -268,18 +276,7 @@ export class Expression { } } } - - if (typeof returnValue === 'function') { - throw new Error('Expression resolved to a function. Please add "()"'); - } else if (returnValue !== null && typeof returnValue === 'object') { - if (returnObjectAsString) { - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - return this.convertObjectValueToString(returnValue); - } - } - - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return returnValue; + return null; } /** @@ -495,33 +492,25 @@ export class Expression { } // The parameter value is complex so resolve depending on type - 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 && typeof returnData === 'object') { - return this.convertObjectValueToString(returnData); - } - + const returnData = parameterValue.map((item) => resolveParameterValue(item, {})); return returnData as NodeParameterValue[] | INodeParameters[]; } + if (parameterValue === null || parameterValue === undefined) { return parameterValue; } + if (typeof parameterValue !== 'object') { + return {}; + } + // 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, - ); + for (const [key, value] of Object.entries(parameterValue)) { + returnData[key] = resolveParameterValue(value, parameterValue); } if (returnObjectAsString && typeof returnData === 'object') { diff --git a/packages/workflow/src/Interfaces.ts b/packages/workflow/src/Interfaces.ts index 5a366ae0e9..fb0774b8ab 100644 --- a/packages/workflow/src/Interfaces.ts +++ b/packages/workflow/src/Interfaces.ts @@ -90,8 +90,7 @@ export abstract class ICredentials { nodesAccess: ICredentialNodeAccess[], data?: string, ) { - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - this.id = nodeCredentials.id || undefined; + this.id = nodeCredentials.id ?? undefined; this.name = nodeCredentials.name; this.type = type; this.nodesAccess = nodesAccess; diff --git a/packages/workflow/src/NodeErrors.ts b/packages/workflow/src/NodeErrors.ts index 678c715844..c4ed371219 100644 --- a/packages/workflow/src/NodeErrors.ts +++ b/packages/workflow/src/NodeErrors.ts @@ -76,9 +76,8 @@ export abstract class ExecutionBaseError extends Error { this.message = error.message as string; } - if (Object.prototype.hasOwnProperty.call(error, 'context')) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - this.context = (error as any).context; + if (error instanceof ExecutionBaseError) { + this.context = error.context; } } } @@ -130,14 +129,12 @@ abstract class NodeError extends ExecutionBaseError { ): string | null { // 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] - // @ts-ignore + const value = error[key]; + if (value) { + if (typeof value === 'string') return value; + if (typeof value === 'number') return value.toString(); + if (Array.isArray(value)) { + const resolvedErrors: string[] = value .map((error) => { if (typeof error === 'string') return error; if (typeof error === 'number') return error.toString(); @@ -146,15 +143,15 @@ abstract class NodeError extends ExecutionBaseError { } return null; }) - .filter((errorValue: string | null) => errorValue !== null); + .filter((errorValue): errorValue is string => errorValue !== null); if (resolvedErrors.length === 0) { return null; } return resolvedErrors.join(' | '); } - if (this.isTraversableObject(error[key])) { - const property = this.findProperty(error[key] as JsonObject, potentialKeys); + if (this.isTraversableObject(value)) { + const property = this.findProperty(value, potentialKeys); if (property) { return property; } @@ -164,8 +161,9 @@ abstract class NodeError extends ExecutionBaseError { // 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); + const value = error[key]; + if (this.isTraversableObject(value)) { + const property = this.findProperty(value, potentialKeys, traversalKeys); if (property) { return property; } diff --git a/packages/workflow/src/NodeHelpers.ts b/packages/workflow/src/NodeHelpers.ts index 03cd9b9bdc..9b67b45572 100644 --- a/packages/workflow/src/NodeHelpers.ts +++ b/packages/workflow/src/NodeHelpers.ts @@ -427,26 +427,26 @@ export function getParamterDependencies( ): IParameterDependencies { const dependencies: IParameterDependencies = {}; - let displayRule: string; - let parameterName: string; for (const nodeProperties of nodePropertiesArray) { - if (dependencies[nodeProperties.name] === undefined) { - dependencies[nodeProperties.name] = []; + const { name, displayOptions } = nodeProperties; + + if (!dependencies[name]) { + dependencies[name] = []; } - if (nodeProperties.displayOptions === undefined) { + + if (!displayOptions) { // 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)) { + for (const displayRule of Object.values(displayOptions)) { + for (const parameterName of Object.keys(displayRule)) { + if (!dependencies[name].includes(parameterName)) { if (parameterName.charAt(0) === '@') { // Is a special parameter so can be skipped continue; } - dependencies[nodeProperties.name].push(parameterName); + dependencies[name].push(parameterName); } } } diff --git a/packages/workflow/src/WorkflowDataProxy.ts b/packages/workflow/src/WorkflowDataProxy.ts index fb86d2cad3..fada367949 100644 --- a/packages/workflow/src/WorkflowDataProxy.ts +++ b/packages/workflow/src/WorkflowDataProxy.ts @@ -352,7 +352,7 @@ export class WorkflowDataProxy { } return new Proxy( - {}, + { binary: undefined, data: undefined, json: undefined }, { get(target, name, receiver) { name = name.toString(); @@ -472,8 +472,7 @@ export class WorkflowDataProxy { throw new Error(`The key "${name.toString()}" is not supported!`); } - // @ts-ignore - return that.workflow[name.toString()]; + return that.workflow[name as keyof typeof target]; }, }, ); @@ -1004,12 +1003,10 @@ export class WorkflowDataProxy { return new Proxy(base, { get(target, name, receiver) { if (['$data', '$json'].includes(name as string)) { - // @ts-ignore - return that.nodeDataGetter(that.activeNodeName, true).json; + return that.nodeDataGetter(that.activeNodeName, true)?.json; } if (name === '$binary') { - // @ts-ignore - return that.nodeDataGetter(that.activeNodeName, true).binary; + return that.nodeDataGetter(that.activeNodeName, true)?.binary; } return Reflect.get(target, name, receiver); diff --git a/packages/workflow/src/types.d.ts b/packages/workflow/src/types.d.ts new file mode 100644 index 0000000000..85bfad7a58 --- /dev/null +++ b/packages/workflow/src/types.d.ts @@ -0,0 +1,14 @@ +declare module '@n8n_io/riot-tmpl' { + interface Brackets { + set(token: string): void; + } + + type ReturnValue = string | null | (() => unknown); + type TmplFn = (value: string, data: unknown) => ReturnValue; + interface Tmpl extends TmplFn { + errorHandler?(error: Error): void; + } + + let brackets: Brackets; + let tmpl: Tmpl; +} diff --git a/packages/workflow/test/RoutingNode.test.ts b/packages/workflow/test/RoutingNode.test.ts index 849dbc410b..95558504a6 100644 --- a/packages/workflow/test/RoutingNode.test.ts +++ b/packages/workflow/test/RoutingNode.test.ts @@ -634,8 +634,6 @@ describe('RoutingNode', () => { for (const testData of tests) { test(testData.description, () => { node.parameters = testData.input.nodeParameters; - - // @ts-ignore nodeType.description.properties = [testData.input.nodeTypeProperties]; const workflow = new Workflow({ diff --git a/packages/workflow/test/Workflow.test.ts b/packages/workflow/test/Workflow.test.ts index 6870350030..20d2d2f7f5 100644 --- a/packages/workflow/test/Workflow.test.ts +++ b/packages/workflow/test/Workflow.test.ts @@ -1022,7 +1022,6 @@ describe('Workflow', () => { }, { name: 'Node3', - // @ts-ignore parameters: testData.input.hasOwnProperty('Node3') ? // @ts-ignore testData.input.Node3.parameters @@ -1034,7 +1033,6 @@ describe('Workflow', () => { }, { name: 'Node 4 with spaces', - // @ts-ignore parameters: testData.input.hasOwnProperty('Node4') ? // @ts-ignore testData.input.Node4.parameters @@ -1080,12 +1078,10 @@ describe('Workflow', () => { { startTime: 1, executionTime: 1, - // @ts-ignore data: { main: [ [ { - // @ts-ignore json: testData.input.Node1.outputJson || testData.input.Node1.parameters, // @ts-ignore binary: testData.input.Node1.outputBinary, diff --git a/packages/workflow/test/WorkflowDataProxy.test.ts b/packages/workflow/test/WorkflowDataProxy.test.ts index f08beda0d0..d014ee5cf2 100644 --- a/packages/workflow/test/WorkflowDataProxy.test.ts +++ b/packages/workflow/test/WorkflowDataProxy.test.ts @@ -75,7 +75,6 @@ describe('WorkflowDataProxy', () => { { startTime: 1, executionTime: 1, - // @ts-ignore data: { main: [ [ @@ -104,7 +103,6 @@ describe('WorkflowDataProxy', () => { { startTime: 1, executionTime: 1, - // @ts-ignore data: { main: [ [