diff --git a/packages/@n8n_io/eslint-config/base.js b/packages/@n8n_io/eslint-config/base.js index d244f76855..0f0093b303 100644 --- a/packages/@n8n_io/eslint-config/base.js +++ b/packages/@n8n_io/eslint-config/base.js @@ -137,7 +137,7 @@ const config = (module.exports = { /** * https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/ban-ts-comment.md */ - '@typescript-eslint/ban-ts-comment': ['warn', { 'ts-ignore': true }], + '@typescript-eslint/ban-ts-comment': ['error', { 'ts-ignore': true }], /** * https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/ban-types.md diff --git a/packages/cli/.eslintrc.js b/packages/cli/.eslintrc.js index 35596b779b..07458ac920 100644 --- a/packages/cli/.eslintrc.js +++ b/packages/cli/.eslintrc.js @@ -12,5 +12,6 @@ module.exports = { rules: { // TODO: Remove this 'import/order': 'off', + '@typescript-eslint/ban-ts-comment': ['warn', { 'ts-ignore': true }], }, - }; +}; diff --git a/packages/core/.eslintrc.js b/packages/core/.eslintrc.js index 4e71be5b40..2055297741 100644 --- a/packages/core/.eslintrc.js +++ b/packages/core/.eslintrc.js @@ -6,5 +6,6 @@ module.exports = { rules: { // TODO: Remove this 'import/order': 'off', + '@typescript-eslint/ban-ts-comment': ['error', { 'ts-ignore': true }], }, }; diff --git a/packages/core/src/BinaryDataManager/index.ts b/packages/core/src/BinaryDataManager/index.ts index eeaeee407c..57b9313b53 100644 --- a/packages/core/src/BinaryDataManager/index.ts +++ b/packages/core/src/BinaryDataManager/index.ts @@ -4,7 +4,7 @@ import { IBinaryDataConfig, IBinaryDataManager } from '../Interfaces'; import { BinaryDataFileSystem } from './FileSystem'; export class BinaryDataManager { - private static instance: BinaryDataManager; + static instance: BinaryDataManager | undefined; private managers: { [key: string]: IBinaryDataManager; diff --git a/packages/core/src/NodeExecuteFunctions.ts b/packages/core/src/NodeExecuteFunctions.ts index 3ba44c3dcc..78ec4ebc24 100644 --- a/packages/core/src/NodeExecuteFunctions.ts +++ b/packages/core/src/NodeExecuteFunctions.ts @@ -77,8 +77,8 @@ import { get } from 'lodash'; import type { Request, Response } from 'express'; import FormData from 'form-data'; import path from 'path'; -import { OptionsWithUri, OptionsWithUrl } from 'request'; -import requestPromise from 'request-promise-native'; +import { OptionsWithUri, OptionsWithUrl, RequestCallback, RequiredUriUrl } from 'request'; +import requestPromise, { RequestPromiseOptions } from 'request-promise-native'; import { fromBuffer } from 'file-type'; import { lookup } from 'mime-types'; @@ -123,18 +123,16 @@ const requestPromiseWithDefaults = requestPromise.defaults({ const pushFormDataValue = (form: FormData, key: string, value: any) => { if (value?.hasOwnProperty('value') && value.hasOwnProperty('options')) { - // @ts-ignore form.append(key, value.value, value.options); } else { form.append(key, value); } }; -const createFormDataObject = (data: object) => { +const createFormDataObject = (data: Record) => { const formData = new FormData(); const keys = Object.keys(data); keys.forEach((key) => { - // @ts-ignore const formField = data[key]; if (formField instanceof Array) { @@ -231,7 +229,7 @@ async function parseRequestObject(requestObject: IDataObject) { if (requestObject.formData !== undefined && requestObject.formData instanceof FormData) { axiosConfig.data = requestObject.formData; } else { - const allData = { + const allData: Partial = { ...(requestObject.body as object | undefined), ...(requestObject.formData as object | undefined), }; @@ -240,7 +238,6 @@ async function parseRequestObject(requestObject: IDataObject) { } // replace the existing header with a new one that // contains the boundary property. - // @ts-ignore delete axiosConfig.headers[contentTypeHeaderKeyName]; const headers = axiosConfig.data.getHeaders(); axiosConfig.headers = Object.assign(axiosConfig.headers || {}, headers); @@ -276,7 +273,7 @@ async function parseRequestObject(requestObject: IDataObject) { if (requestObject.formData instanceof FormData) { axiosConfig.data = requestObject.formData; } else { - axiosConfig.data = createFormDataObject(requestObject.formData as object); + axiosConfig.data = createFormDataObject(requestObject.formData as Record); } // Mix in headers as FormData creates the boundary. const headers = axiosConfig.data.getHeaders(); @@ -284,9 +281,8 @@ async function parseRequestObject(requestObject: IDataObject) { await generateContentLengthHeader(axiosConfig.data, axiosConfig.headers); } else if (requestObject.body !== undefined) { // If we have body and possibly form - if (requestObject.form !== undefined) { + if (requestObject.form !== undefined && requestObject.body) { // merge both objects when exist. - // @ts-ignore requestObject.body = Object.assign(requestObject.body, requestObject.form); } axiosConfig.data = requestObject.body as FormData | GenericValue | GenericValue[]; @@ -313,10 +309,25 @@ async function parseRequestObject(requestObject: IDataObject) { axiosConfig.params = requestObject.qs as IDataObject; } + function hasArrayFormatOptions( + arg: IDataObject, + ): arg is IDataObject & { qsStringifyOptions: { arrayFormat: 'repeat' | 'brackets' } } { + if ( + typeof arg.qsStringifyOptions === 'object' && + arg.qsStringifyOptions !== null && + !Array.isArray(arg.qsStringifyOptions) && + 'arrayFormat' in arg.qsStringifyOptions + ) { + return true; + } + + return false; + } + if ( requestObject.useQuerystring === true || - // @ts-ignore - requestObject.qsStringifyOptions?.arrayFormat === 'repeat' + (hasArrayFormatOptions(requestObject) && + requestObject.qsStringifyOptions.arrayFormat === 'repeat') ) { axiosConfig.paramsSerializer = (params) => { return stringify(params, { arrayFormat: 'repeat' }); @@ -327,8 +338,10 @@ async function parseRequestObject(requestObject: IDataObject) { }; } - // @ts-ignore - if (requestObject.qsStringifyOptions?.arrayFormat === 'brackets') { + if ( + hasArrayFormatOptions(requestObject) && + requestObject.qsStringifyOptions.arrayFormat === 'brackets' + ) { axiosConfig.paramsSerializer = (params) => { return stringify(params, { arrayFormat: 'brackets' }); }; @@ -552,8 +565,11 @@ async function proxyRequestToAxios( ): Promise { // Check if there's a better way of getting this config here if (process.env.N8N_USE_DEPRECATED_REQUEST_LIB) { - // @ts-ignore - return requestPromiseWithDefaults.call(null, uriOrObject, options); + return requestPromiseWithDefaults.call( + null, + uriOrObject as unknown as RequiredUriUrl & RequestPromiseOptions, + options as unknown as RequestCallback, + ); } let axiosConfig: AxiosRequestConfig = { @@ -970,10 +986,8 @@ export async function requestOAuth2( const newRequestOptions = token.sign(requestOptions as clientOAuth2.RequestObject); const newRequestHeaders = (newRequestOptions.headers = newRequestOptions.headers ?? {}); // If keep bearer is false remove the it from the authorization header - if (oAuth2Options?.keepBearer === false) { - newRequestHeaders.Authorization = - // @ts-ignore - newRequestHeaders.Authorization.split(' ')[1]; + if (oAuth2Options?.keepBearer === false && typeof newRequestHeaders.Authorization === 'string') { + newRequestHeaders.Authorization = newRequestHeaders.Authorization.split(' ')[1]; } if (oAuth2Options?.keyToIncludeInAccessTokenHeader) { @@ -1110,10 +1124,8 @@ export async function requestOAuth2( const newRequestOptions = newToken.sign(requestOptions as clientOAuth2.RequestObject); newRequestOptions.headers = newRequestOptions.headers ?? {}; - // @ts-ignore if (oAuth2Options?.keyToIncludeInAccessTokenHeader) { Object.assign(newRequestOptions.headers, { - // @ts-ignore [oAuth2Options.keyToIncludeInAccessTokenHeader]: token.accessToken, }); } @@ -1126,9 +1138,8 @@ export async function requestOAuth2( }); } -/* Makes a request using OAuth1 data for authentication - * - * @param {(OptionsWithUrl | requestPromise.RequestPromiseOptions)} requestOptions +/** + * Makes a request using OAuth1 data for authentication */ export async function requestOAuth1( this: IAllExecuteFunctions, @@ -1169,20 +1180,21 @@ export async function requestOAuth1( secret: oauthTokenData.oauth_token_secret as string, }; - // @ts-ignore + // @ts-expect-error @TECH_DEBT: Remove request library requestOptions.data = { ...requestOptions.qs, ...requestOptions.form }; // Fixes issue that OAuth1 library only works with "url" property and not with "uri" - // @ts-ignore + // @ts-expect-error @TECH_DEBT: Remove request library if (requestOptions.uri && !requestOptions.url) { - // @ts-ignore + // @ts-expect-error @TECH_DEBT: Remove request library requestOptions.url = requestOptions.uri; - // @ts-ignore + // @ts-expect-error @TECH_DEBT: Remove request library delete requestOptions.uri; } - // @ts-ignore - requestOptions.headers = oauth.toHeader(oauth.authorize(requestOptions, token)); + requestOptions.headers = oauth.toHeader( + oauth.authorize(requestOptions as unknown as clientOAuth1.RequestOptions, token), + ); if (isN8nRequest) { return this.helpers.httpRequest(requestOptions as IHttpRequestOptions); } diff --git a/packages/core/src/WorkflowExecute.ts b/packages/core/src/WorkflowExecute.ts index 632c336ae3..6f8318f7fd 100644 --- a/packages/core/src/WorkflowExecute.ts +++ b/packages/core/src/WorkflowExecute.ts @@ -156,7 +156,6 @@ export class WorkflowExecute { startNodes: string[], destinationNode: string, pinData?: IPinData, - // @ts-ignore ): PCancelable { let incomingNodeConnections: INodeConnections | undefined; let connection: IConnection; @@ -783,7 +782,6 @@ export class WorkflowExecute { gotCancel = true; } - // @ts-ignore if (gotCancel) { return Promise.resolve(); } @@ -911,7 +909,6 @@ export class WorkflowExecute { } for (let tryIndex = 0; tryIndex < maxTries; tryIndex++) { - // @ts-ignore if (gotCancel) { return Promise.resolve(); } diff --git a/packages/core/test/NodeExecuteFunctions.test.ts b/packages/core/test/NodeExecuteFunctions.test.ts index 653ff4456c..c3ec81a180 100644 --- a/packages/core/test/NodeExecuteFunctions.test.ts +++ b/packages/core/test/NodeExecuteFunctions.test.ts @@ -11,7 +11,6 @@ describe('NodeExecuteFunctions', () => { describe(`test binary data helper methods`, () => { // Reset BinaryDataManager for each run. This is a dirty operation, as individual managers are not cleaned. beforeEach(() => { - //@ts-ignore BinaryDataManager.instance = undefined; }); diff --git a/packages/design-system/.eslintrc.js b/packages/design-system/.eslintrc.js index 1924d2f23b..502408aeed 100644 --- a/packages/design-system/.eslintrc.js +++ b/packages/design-system/.eslintrc.js @@ -23,5 +23,6 @@ module.exports = { '@typescript-eslint/prefer-nullish-coalescing': 'off', '@typescript-eslint/prefer-optional-chain': 'off', '@typescript-eslint/restrict-template-expressions': 'off', + '@typescript-eslint/ban-ts-comment': ['warn', { 'ts-ignore': true }], } }; diff --git a/packages/editor-ui/.eslintrc.js b/packages/editor-ui/.eslintrc.js index 568f6d0f83..e31d9ca0b8 100644 --- a/packages/editor-ui/.eslintrc.js +++ b/packages/editor-ui/.eslintrc.js @@ -49,5 +49,6 @@ module.exports = { '@typescript-eslint/restrict-template-expressions': 'off', '@typescript-eslint/return-await': 'off', '@typescript-eslint/unbound-method': 'off', + '@typescript-eslint/ban-ts-comment': ['warn', { 'ts-ignore': true }], }, }; diff --git a/packages/node-dev/.eslintrc.js b/packages/node-dev/.eslintrc.js index 0fa7780bcc..b2dfdae442 100644 --- a/packages/node-dev/.eslintrc.js +++ b/packages/node-dev/.eslintrc.js @@ -8,5 +8,6 @@ module.exports = { ], rules: { 'import/order': 'off', // TODO: remove this + '@typescript-eslint/ban-ts-comment': ['warn', { 'ts-ignore': true }], }, }; diff --git a/packages/nodes-base/.eslintrc.js b/packages/nodes-base/.eslintrc.js index cbdbb994ed..bf39010df0 100644 --- a/packages/nodes-base/.eslintrc.js +++ b/packages/nodes-base/.eslintrc.js @@ -59,6 +59,7 @@ module.exports = { '@typescript-eslint/restrict-template-expressions': 'off', '@typescript-eslint/return-await': 'off', '@typescript-eslint/unbound-method': 'off', + '@typescript-eslint/ban-ts-comment': ['warn', { 'ts-ignore': true }], }, overrides: [ diff --git a/packages/workflow/src/Expression.ts b/packages/workflow/src/Expression.ts index 7d41149d15..81f5dac4bf 100644 --- a/packages/workflow/src/Expression.ts +++ b/packages/workflow/src/Expression.ts @@ -157,7 +157,6 @@ export class Expression { data.Reflect = {}; data.Proxy = {}; - // @ts-ignore data.constructor = {}; // Deprecated diff --git a/packages/workflow/src/Interfaces.ts b/packages/workflow/src/Interfaces.ts index c51b200344..0ff80ad866 100644 --- a/packages/workflow/src/Interfaces.ts +++ b/packages/workflow/src/Interfaces.ts @@ -1400,6 +1400,7 @@ export interface IWorkflowDataProxyData { $thisItemIndex: number; $now: any; $today: any; + constructor: any; } export type IWorkflowDataProxyAdditionalKeys = IDataObject; diff --git a/packages/workflow/test/RoutingNode.test.ts b/packages/workflow/test/RoutingNode.test.ts index e8fbaa80d9..2725527159 100644 --- a/packages/workflow/test/RoutingNode.test.ts +++ b/packages/workflow/test/RoutingNode.test.ts @@ -16,6 +16,7 @@ import { IN8nRequestOperations, INodeCredentialDescription, IExecuteData, + INodeTypeDescription, } from '../src'; import * as Helpers from './Helpers'; @@ -1689,8 +1690,7 @@ describe('RoutingNode', () => { connections: {}, }; - // @ts-ignore - nodeType.description = { ...testData.input.nodeType }; + nodeType.description = { ...testData.input.nodeType } as INodeTypeDescription; const workflow = new Workflow({ nodes: workflowData.nodes, @@ -1714,8 +1714,7 @@ describe('RoutingNode', () => { source: null, } as IExecuteData; - // @ts-ignore - const nodeExecuteFunctions: INodeExecuteFunctions = { + const nodeExecuteFunctions: Partial = { getExecuteFunctions: () => { return Helpers.getExecuteFunctions( workflow, @@ -1751,7 +1750,7 @@ describe('RoutingNode', () => { runIndex, nodeType, executeData, - nodeExecuteFunctions, + nodeExecuteFunctions as INodeExecuteFunctions, ); expect(result).toEqual(testData.output); @@ -1763,12 +1762,7 @@ describe('RoutingNode', () => { const tests: Array<{ description: string; input: { - nodeType: { - properties?: INodeProperties[]; - credentials?: INodeCredentialDescription[]; - requestDefaults?: IHttpRequestOptions; - requestOperations?: IN8nRequestOperations; - }; + nodeType: Partial; node: { parameters: INodeParameters; }; @@ -1868,8 +1862,7 @@ describe('RoutingNode', () => { connections: {}, }; - // @ts-ignore - nodeType.description = { ...testData.input.nodeType }; + nodeType.description = { ...testData.input.nodeType } as INodeTypeDescription; const workflow = new Workflow({ nodes: workflowData.nodes, @@ -1895,8 +1888,7 @@ describe('RoutingNode', () => { let currentItemIndex = 0; for (let iteration = 0; iteration < inputData.main[0]!.length; iteration++) { - // @ts-ignore - const nodeExecuteFunctions: INodeExecuteFunctions = { + const nodeExecuteFunctions: Partial = { getExecuteFunctions: () => { return Helpers.getExecuteFunctions( workflow, @@ -1927,6 +1919,10 @@ describe('RoutingNode', () => { }, }; + if (!nodeExecuteFunctions.getExecuteSingleFunctions) { + fail('Expected nodeExecuteFunctions to contain getExecuteSingleFunctions'); + } + const routingNodeExecutionContext = nodeExecuteFunctions.getExecuteSingleFunctions( routingNode.workflow, routingNode.runExecutionData, diff --git a/packages/workflow/test/Workflow.test.ts b/packages/workflow/test/Workflow.test.ts index 5922b68a15..8b07046ebd 100644 --- a/packages/workflow/test/Workflow.test.ts +++ b/packages/workflow/test/Workflow.test.ts @@ -1,9 +1,12 @@ import { + IBinaryKeyData, IConnections, + IDataObject, INode, INodeExecutionData, INodeParameters, IRunExecutionData, + NodeParameterValueType, Workflow, } from '../src'; @@ -696,7 +699,17 @@ describe('Workflow', () => { }); describe('getParameterValue', () => { - const tests = [ + const tests: { + description: string; + input: { + [nodeName: string]: { + parameters: Record; + outputJson?: IDataObject; + outputBinary?: IBinaryKeyData; + }; + }; + output: Record; + }[] = [ { description: 'read simple not expression value', input: { @@ -881,6 +894,7 @@ describe('Workflow', () => { binaryKey: { data: '', type: '', + mimeType: 'test', fileName: 'test-file1.jpg', }, }, @@ -908,6 +922,7 @@ describe('Workflow', () => { binaryKey: { data: '', type: '', + mimeType: 'test', fileName: 'test-file1.jpg', }, }, @@ -1134,8 +1149,7 @@ describe('Workflow', () => { { name: 'Node3', parameters: testData.input.hasOwnProperty('Node3') - ? // @ts-ignore - testData.input.Node3.parameters + ? testData.input.Node3?.parameters : {}, type: 'test.set', typeVersion: 1, @@ -1145,8 +1159,7 @@ describe('Workflow', () => { { name: 'Node 4 with spaces', parameters: testData.input.hasOwnProperty('Node4') - ? // @ts-ignore - testData.input.Node4.parameters + ? testData.input.Node4.parameters : {}, type: 'test.set', typeVersion: 1, @@ -1187,6 +1200,11 @@ describe('Workflow', () => { runData: { Node1: [ { + source: [ + { + previousNode: 'test', + }, + ], startTime: 1, executionTime: 1, data: { @@ -1194,7 +1212,6 @@ describe('Workflow', () => { [ { json: testData.input.Node1.outputJson || testData.input.Node1.parameters, - // @ts-ignore binary: testData.input.Node1.outputBinary, }, ], @@ -1226,7 +1243,6 @@ describe('Workflow', () => { timezone, {}, ); - // @ts-ignore expect(result).toEqual(testData.output[parameterName]); } }); @@ -1278,7 +1294,6 @@ describe('Workflow', () => { // const workflow = new Workflow({ nodes, connections, active: false, nodeTypes }); // const activeNodeName = 'Node2'; - // // @ts-ignore // const parameterValue = nodes.find((node) => node.name === activeNodeName).parameters.name; // // const parameterValue = '=[data.propertyName]'; // TODO: Make this dynamic from node-data via "activeNodeName"! // const runData: RunData = {