mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-15 17:16:45 +00:00
build: Update ESLint to v9 (#16639)
This commit is contained in:
@@ -21,7 +21,7 @@ yarn-error.log*
|
||||
*.sw*
|
||||
|
||||
.editorconfig
|
||||
.eslintrc.js
|
||||
eslint.config.js
|
||||
tsconfig.json
|
||||
|
||||
.turbo
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
const sharedOptions = require('@n8n/eslint-config/shared');
|
||||
|
||||
/**
|
||||
* @type {import('@types/eslint').ESLint.ConfigData}
|
||||
*/
|
||||
module.exports = {
|
||||
extends: ['@n8n/eslint-config/base', 'plugin:cypress/recommended'],
|
||||
|
||||
...sharedOptions(__dirname),
|
||||
|
||||
plugins: ['cypress'],
|
||||
|
||||
env: {
|
||||
'cypress/globals': true,
|
||||
},
|
||||
|
||||
rules: {
|
||||
// TODO: remove these rules
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
'@typescript-eslint/no-unsafe-argument': 'off',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'off',
|
||||
'@typescript-eslint/no-unsafe-call': 'off',
|
||||
'@typescript-eslint/no-unsafe-member-access': 'off',
|
||||
'@typescript-eslint/no-unsafe-return': 'off',
|
||||
'@typescript-eslint/no-unused-expressions': 'off',
|
||||
'@typescript-eslint/no-use-before-define': 'off',
|
||||
'@typescript-eslint/promise-function-async': 'off',
|
||||
'n8n-local-rules/no-uncaught-json-parse': 'off',
|
||||
'cypress/no-assigning-return-values': 'warn',
|
||||
'cypress/no-unnecessary-waiting': 'warn',
|
||||
'cypress/unsafe-to-chain-command': 'warn',
|
||||
'import/no-extraneous-dependencies': [
|
||||
'error',
|
||||
{
|
||||
devDependencies: ['**/cypress/**'],
|
||||
optionalDependencies: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
2
cypress/augmentation.d.ts
vendored
2
cypress/augmentation.d.ts
vendored
@@ -1,4 +1,4 @@
|
||||
declare module 'cypress-otp' {
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
// eslint-disable-next-line import-x/no-default-export
|
||||
export default function generateOTPToken(secret: string): string;
|
||||
}
|
||||
|
||||
39
cypress/eslint.config.mjs
Normal file
39
cypress/eslint.config.mjs
Normal file
@@ -0,0 +1,39 @@
|
||||
import { defineConfig, globalIgnores } from 'eslint/config';
|
||||
import { baseConfig } from '@n8n/eslint-config/base';
|
||||
import cypressPlugin from 'eslint-plugin-cypress/flat';
|
||||
|
||||
export default defineConfig(
|
||||
globalIgnores(['scripts/**/*.js']),
|
||||
baseConfig,
|
||||
cypressPlugin.configs.recommended,
|
||||
{
|
||||
rules: {
|
||||
// TODO: Remove this
|
||||
'no-useless-escape': 'warn',
|
||||
'import-x/order': 'warn',
|
||||
'import-x/no-extraneous-dependencies': [
|
||||
'error',
|
||||
{
|
||||
devDependencies: ['**/cypress/**'],
|
||||
optionalDependencies: false,
|
||||
},
|
||||
],
|
||||
'@typescript-eslint/naming-convention': 'warn',
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
'@typescript-eslint/no-unsafe-argument': 'warn',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'warn',
|
||||
'@typescript-eslint/no-unsafe-call': 'warn',
|
||||
'@typescript-eslint/no-unsafe-member-access': 'warn',
|
||||
'@typescript-eslint/no-unsafe-return': 'warn',
|
||||
'@typescript-eslint/no-unused-expressions': 'warn',
|
||||
'@typescript-eslint/no-use-before-define': 'warn',
|
||||
'@typescript-eslint/promise-function-async': 'warn',
|
||||
'@typescript-eslint/prefer-nullish-coalescing': 'warn',
|
||||
'@typescript-eslint/unbound-method': 'warn',
|
||||
'cypress/no-assigning-return-values': 'warn',
|
||||
'cypress/no-unnecessary-waiting': 'warn',
|
||||
'cypress/unsafe-to-chain-command': 'warn',
|
||||
'n8n-local-rules/no-uncaught-json-parse': 'warn',
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -19,7 +19,7 @@
|
||||
"@cypress/grep": "^4.1.0",
|
||||
"@n8n/api-types": "workspace:*",
|
||||
"@types/lodash": "catalog:",
|
||||
"eslint-plugin-cypress": "^3.5.0",
|
||||
"eslint-plugin-cypress": "^4.3.0",
|
||||
"n8n-workflow": "workspace:*"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
"babel-plugin-transform-import-meta": "^2.3.2",
|
||||
"bundlemon": "^3.1.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "catalog:",
|
||||
"jest": "^29.6.2",
|
||||
"jest-environment-jsdom": "^29.6.2",
|
||||
"jest-expect-message": "^1.1.3",
|
||||
@@ -94,7 +95,7 @@
|
||||
"tar-fs": "2.1.3",
|
||||
"tslib": "^2.6.2",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"typescript": "^5.8.2",
|
||||
"typescript": "catalog:",
|
||||
"vue-tsc": "^2.2.8",
|
||||
"google-gax": "^4.3.7",
|
||||
"ws": ">=8.17.1",
|
||||
@@ -110,7 +111,6 @@
|
||||
"@types/ws@8.18.1": "patches/@types__ws@8.18.1.patch",
|
||||
"@types/uuencode@0.0.3": "patches/@types__uuencode@0.0.3.patch",
|
||||
"vue-tsc@2.2.8": "patches/vue-tsc@2.2.8.patch",
|
||||
"eslint-plugin-n8n-local-rules": "patches/eslint-plugin-n8n-local-rules.patch",
|
||||
"element-plus@2.4.3": "patches/element-plus@2.4.3.patch"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
const sharedOptions = require('@n8n/eslint-config/shared');
|
||||
|
||||
/**
|
||||
* @type {import('@types/eslint').ESLint.ConfigData}
|
||||
*/
|
||||
module.exports = {
|
||||
extends: ['@n8n/eslint-config/node'],
|
||||
|
||||
...sharedOptions(__dirname),
|
||||
|
||||
ignorePatterns: ['jest.config.js'],
|
||||
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
|
||||
complexity: 'error',
|
||||
},
|
||||
};
|
||||
11
packages/@n8n/ai-workflow-builder/eslint.config.mjs
Normal file
11
packages/@n8n/ai-workflow-builder/eslint.config.mjs
Normal file
@@ -0,0 +1,11 @@
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import { nodeConfig } from '@n8n/eslint-config/node';
|
||||
|
||||
export default defineConfig(nodeConfig, {
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
complexity: 'error',
|
||||
'@typescript-eslint/require-await': 'warn',
|
||||
'@typescript-eslint/naming-convention': 'warn',
|
||||
},
|
||||
});
|
||||
@@ -1,10 +0,0 @@
|
||||
const sharedOptions = require('@n8n/eslint-config/shared');
|
||||
|
||||
/** @type {import('@types/eslint').ESLint.ConfigData} */
|
||||
module.exports = {
|
||||
extends: ['@n8n/eslint-config/base'],
|
||||
...sharedOptions(__dirname),
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
},
|
||||
};
|
||||
12
packages/@n8n/api-types/eslint.config.mjs
Normal file
12
packages/@n8n/api-types/eslint.config.mjs
Normal file
@@ -0,0 +1,12 @@
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import { baseConfig } from '@n8n/eslint-config/base';
|
||||
|
||||
export default defineConfig(baseConfig, {
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
|
||||
// TODO: Remove this
|
||||
'@typescript-eslint/naming-convention': 'warn',
|
||||
'@typescript-eslint/no-empty-object-type': 'warn',
|
||||
},
|
||||
});
|
||||
@@ -8,7 +8,7 @@
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome ci .",
|
||||
"lint": "eslint .",
|
||||
"lint": "eslint . --quiet",
|
||||
"lintfix": "eslint . --fix",
|
||||
"watch": "tsc -p tsconfig.build.json --watch",
|
||||
"test": "jest",
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
const sharedOptions = require('@n8n/eslint-config/shared');
|
||||
|
||||
/** @type {import('@types/eslint').ESLint.ConfigData} */
|
||||
module.exports = {
|
||||
extends: ['@n8n/eslint-config/base'],
|
||||
...sharedOptions(__dirname),
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
},
|
||||
};
|
||||
25
packages/@n8n/backend-common/eslint.config.mjs
Normal file
25
packages/@n8n/backend-common/eslint.config.mjs
Normal file
@@ -0,0 +1,25 @@
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import { baseConfig } from '@n8n/eslint-config/base';
|
||||
|
||||
export default defineConfig(
|
||||
baseConfig,
|
||||
{
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
|
||||
// TODO: Remove this
|
||||
'@typescript-eslint/naming-convention': 'warn',
|
||||
'@typescript-eslint/no-wrapper-object-types': 'warn',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.test.ts'],
|
||||
rules: {
|
||||
'n8n-local-rules/no-uncaught-json-parse': 'warn',
|
||||
'@typescript-eslint/no-unsafe-return': 'warn',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'warn',
|
||||
'@typescript-eslint/no-unsafe-argument': 'warn',
|
||||
'@typescript-eslint/unbound-method': 'warn',
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -8,7 +8,7 @@
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome ci .",
|
||||
"lint": "eslint .",
|
||||
"lint": "eslint . --quiet",
|
||||
"lintfix": "eslint . --fix",
|
||||
"watch": "tsc -p tsconfig.build.json --watch",
|
||||
"test": "jest",
|
||||
|
||||
@@ -12,7 +12,7 @@ export function isObjectLiteral(candidate: unknown): candidate is ObjectLiteral
|
||||
typeof candidate === 'object' &&
|
||||
candidate !== null &&
|
||||
!Array.isArray(candidate) &&
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
(Object.getPrototypeOf(candidate) as Object)?.constructor?.name === 'Object'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
const sharedOptions = require('@n8n/eslint-config/shared');
|
||||
|
||||
/** @type {import('@types/eslint').ESLint.ConfigData} */
|
||||
module.exports = {
|
||||
extends: ['@n8n/eslint-config/base'],
|
||||
...sharedOptions(__dirname),
|
||||
};
|
||||
10
packages/@n8n/backend-test-utils/eslint.config.mjs
Normal file
10
packages/@n8n/backend-test-utils/eslint.config.mjs
Normal file
@@ -0,0 +1,10 @@
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import { baseConfig } from '@n8n/eslint-config/base';
|
||||
|
||||
export default defineConfig(baseConfig, {
|
||||
rules: {
|
||||
// TODO: Remove this
|
||||
'@typescript-eslint/require-await': 'warn',
|
||||
'@typescript-eslint/naming-convention': 'warn',
|
||||
},
|
||||
});
|
||||
@@ -8,7 +8,7 @@
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome ci .",
|
||||
"lint": "eslint .",
|
||||
"lint": "eslint . --quiet",
|
||||
"lintfix": "eslint . --fix",
|
||||
"watch": "tsc -p tsconfig.build.json --watch",
|
||||
"test": "jest",
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
const sharedOptions = require('@n8n/eslint-config/shared');
|
||||
|
||||
/**
|
||||
* @type {import('@types/eslint').ESLint.ConfigData}
|
||||
*/
|
||||
module.exports = {
|
||||
extends: ['@n8n/eslint-config/node'],
|
||||
|
||||
...sharedOptions(__dirname),
|
||||
|
||||
parserOptions: {
|
||||
project: './tsconfig.json',
|
||||
},
|
||||
|
||||
ignorePatterns: ['scenarios/**'],
|
||||
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
'n8n-local-rules/no-plain-errors': 'off',
|
||||
complexity: 'error',
|
||||
},
|
||||
|
||||
overrides: [
|
||||
{
|
||||
files: ['./src/commands/*.ts'],
|
||||
rules: {
|
||||
'import/no-default-export': 'off',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
22
packages/@n8n/benchmark/eslint.config.mjs
Normal file
22
packages/@n8n/benchmark/eslint.config.mjs
Normal file
@@ -0,0 +1,22 @@
|
||||
import { defineConfig, globalIgnores } from 'eslint/config';
|
||||
import { nodeConfig } from '@n8n/eslint-config/node';
|
||||
|
||||
export default defineConfig(
|
||||
nodeConfig,
|
||||
globalIgnores(['scenarios/**', 'scripts/**']),
|
||||
{
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
'n8n-local-rules/no-plain-errors': 'off',
|
||||
complexity: 'error',
|
||||
'@typescript-eslint/naming-convention': 'warn',
|
||||
'no-empty': 'warn',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['./src/commands/*.ts'],
|
||||
rules: {
|
||||
'import-x/no-default-export': 'off',
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -7,7 +7,7 @@
|
||||
"build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome ci .",
|
||||
"lint": "eslint .",
|
||||
"lint": "eslint . --quiet",
|
||||
"lintfix": "eslint . --fix",
|
||||
"start": "./bin/n8n-benchmark",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
const sharedOptions = require('@n8n/eslint-config/shared');
|
||||
|
||||
/**
|
||||
* @type {import('@types/eslint').ESLint.ConfigData}
|
||||
*/
|
||||
module.exports = {
|
||||
extends: ['@n8n/eslint-config/base'],
|
||||
|
||||
...sharedOptions(__dirname),
|
||||
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
'n8n-local-rules/no-plain-errors': 'off',
|
||||
'n8n-local-rules/no-uncaught-json-parse': 'off',
|
||||
},
|
||||
};
|
||||
29
packages/@n8n/client-oauth2/eslint.config.mjs
Normal file
29
packages/@n8n/client-oauth2/eslint.config.mjs
Normal file
@@ -0,0 +1,29 @@
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import { baseConfig } from '@n8n/eslint-config/base';
|
||||
|
||||
export default defineConfig(
|
||||
baseConfig,
|
||||
{
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
'n8n-local-rules/no-plain-errors': 'off',
|
||||
'n8n-local-rules/no-uncaught-json-parse': 'off',
|
||||
|
||||
// TODO: Remove this
|
||||
'@typescript-eslint/naming-convention': 'warn',
|
||||
'@typescript-eslint/require-await': 'warn',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.test.ts'],
|
||||
rules: {
|
||||
// TODO: Remove this
|
||||
'id-denylist': 'warn',
|
||||
'@typescript-eslint/no-unsafe-return': 'warn',
|
||||
'@typescript-eslint/no-unsafe-call': 'warn',
|
||||
'@typescript-eslint/no-unsafe-member-access': 'warn',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'warn',
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -1,12 +0,0 @@
|
||||
const sharedOptions = require('@n8n/eslint-config/shared');
|
||||
|
||||
/**
|
||||
* @type {import('@types/eslint').ESLint.ConfigData}
|
||||
*/
|
||||
module.exports = {
|
||||
extends: ['@n8n/eslint-config/base'],
|
||||
|
||||
...sharedOptions(__dirname),
|
||||
|
||||
ignorePatterns: ['src/expressions/grammar*.ts'],
|
||||
};
|
||||
11
packages/@n8n/codemirror-lang/eslint.config.mjs
Normal file
11
packages/@n8n/codemirror-lang/eslint.config.mjs
Normal file
@@ -0,0 +1,11 @@
|
||||
import { defineConfig, globalIgnores } from 'eslint/config';
|
||||
import { baseConfig } from '@n8n/eslint-config/base';
|
||||
|
||||
export default defineConfig(baseConfig, globalIgnores(['src/expressions/grammar*.ts']), {
|
||||
rules: {
|
||||
// TODO: Remove this
|
||||
'@typescript-eslint/naming-convention': 'warn',
|
||||
'no-useless-escape': 'warn',
|
||||
'@typescript-eslint/unbound-method': 'warn',
|
||||
},
|
||||
});
|
||||
@@ -22,8 +22,8 @@
|
||||
"generate": "pnpm generate:expressions:grammar && pnpm format",
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"test": "jest",
|
||||
"lint": "eslint . --ext .ts --quiet",
|
||||
"lintfix": "eslint . --ext .ts --fix",
|
||||
"lint": "eslint . --quiet",
|
||||
"lintfix": "eslint . --fix",
|
||||
"format": "biome format --write src test",
|
||||
"format:check": "biome ci src test"
|
||||
},
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
const sharedOptions = require('@n8n/eslint-config/shared');
|
||||
|
||||
/**
|
||||
* @type {import('@types/eslint').ESLint.ConfigData}
|
||||
*/
|
||||
module.exports = {
|
||||
extends: ['@n8n/eslint-config/node'],
|
||||
|
||||
...sharedOptions(__dirname),
|
||||
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
},
|
||||
|
||||
overrides: [
|
||||
{
|
||||
files: ['**/*.config.ts'],
|
||||
rules: {
|
||||
'n8n-local-rules/no-untyped-config-class-field': 'error',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
22
packages/@n8n/config/eslint.config.mjs
Normal file
22
packages/@n8n/config/eslint.config.mjs
Normal file
@@ -0,0 +1,22 @@
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import { nodeConfig } from '@n8n/eslint-config/node';
|
||||
|
||||
export default defineConfig(
|
||||
nodeConfig,
|
||||
{
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
|
||||
// TODO: Remove this
|
||||
'@typescript-eslint/naming-convention': 'warn',
|
||||
'@typescript-eslint/no-unsafe-call': 'warn',
|
||||
'@typescript-eslint/no-unsafe-function-type': 'warn',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.config.ts'],
|
||||
rules: {
|
||||
'n8n-local-rules/no-untyped-config-class-field': 'error',
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -8,7 +8,7 @@
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"format": "biome format --write src test",
|
||||
"format:check": "biome ci src test",
|
||||
"lint": "eslint .",
|
||||
"lint": "eslint . --quiet",
|
||||
"lintfix": "eslint . --fix",
|
||||
"watch": "tsc -p tsconfig.build.json --watch",
|
||||
"test": "jest",
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Container, Service } from '@n8n/di';
|
||||
import { readFileSync } from 'fs';
|
||||
import { z } from 'zod';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
type Class = Function;
|
||||
type Constructable<T = unknown> = new (rawValue: string) => T;
|
||||
type PropertyKey = string | symbol;
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
const sharedOptions = require('@n8n/eslint-config/shared');
|
||||
|
||||
/** @type {import('@types/eslint').ESLint.ConfigData} */
|
||||
module.exports = {
|
||||
extends: ['@n8n/eslint-config/base'],
|
||||
...sharedOptions(__dirname),
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
},
|
||||
};
|
||||
8
packages/@n8n/constants/eslint.config.mjs
Normal file
8
packages/@n8n/constants/eslint.config.mjs
Normal file
@@ -0,0 +1,8 @@
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import { baseConfig } from '@n8n/eslint-config/base';
|
||||
|
||||
export default defineConfig(baseConfig, {
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
},
|
||||
});
|
||||
@@ -8,7 +8,7 @@
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome ci .",
|
||||
"lint": "eslint .",
|
||||
"lint": "eslint . --quiet",
|
||||
"lintfix": "eslint . --fix",
|
||||
"watch": "tsc -p tsconfig.build.json --watch"
|
||||
},
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
const sharedOptions = require('@n8n/eslint-config/shared');
|
||||
|
||||
/** @type {import('@types/eslint').ESLint.ConfigData} */
|
||||
module.exports = {
|
||||
extends: ['@n8n/eslint-config/base'],
|
||||
...sharedOptions(__dirname),
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['./src/migrations/**/*.ts'],
|
||||
rules: {
|
||||
'unicorn/filename-case': 'off',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
38
packages/@n8n/db/eslint.config.mjs
Normal file
38
packages/@n8n/db/eslint.config.mjs
Normal file
@@ -0,0 +1,38 @@
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import { baseConfig } from '@n8n/eslint-config/base';
|
||||
|
||||
export default defineConfig(
|
||||
baseConfig,
|
||||
{
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
|
||||
// TODO: Remove this
|
||||
'@typescript-eslint/naming-convention': 'warn',
|
||||
'@typescript-eslint/no-unsafe-member-access': 'warn',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'warn',
|
||||
'@typescript-eslint/prefer-nullish-coalescing': 'warn',
|
||||
'@typescript-eslint/unbound-method': 'warn',
|
||||
'@typescript-eslint/no-base-to-string': 'warn',
|
||||
'@typescript-eslint/require-await': 'warn',
|
||||
'@typescript-eslint/no-unsafe-call': 'warn',
|
||||
'@typescript-eslint/no-unsafe-function-type': 'warn',
|
||||
'@typescript-eslint/no-empty-object-type': 'warn',
|
||||
'@typescript-eslint/no-restricted-types': 'warn',
|
||||
'no-useless-escape': 'warn',
|
||||
'no-empty': 'warn',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.test.ts', '**/__tests__/**/*.ts'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-unsafe-return': 'warn',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['./src/migrations/**/*.ts'],
|
||||
rules: {
|
||||
'unicorn/filename-case': 'off',
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -8,7 +8,7 @@
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome ci .",
|
||||
"lint": "eslint .",
|
||||
"lint": "eslint . --quiet",
|
||||
"lintfix": "eslint . --fix",
|
||||
"watch": "tsc -p tsconfig.build.json --watch",
|
||||
"test": "jest",
|
||||
|
||||
@@ -56,7 +56,7 @@ export interface IrreversibleMigration extends BaseMigration {
|
||||
down?: never;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
export interface Migration extends Function {
|
||||
prototype: ReversibleMigration | IrreversibleMigration;
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
const sharedOptions = require('@n8n/eslint-config/shared');
|
||||
|
||||
/** @type {import('@types/eslint').ESLint.ConfigData} */
|
||||
module.exports = {
|
||||
extends: ['@n8n/eslint-config/base'],
|
||||
...sharedOptions(__dirname),
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
},
|
||||
};
|
||||
28
packages/@n8n/decorators/eslint.config.mjs
Normal file
28
packages/@n8n/decorators/eslint.config.mjs
Normal file
@@ -0,0 +1,28 @@
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import { baseConfig } from '@n8n/eslint-config/base';
|
||||
|
||||
export default defineConfig(
|
||||
baseConfig,
|
||||
{
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
|
||||
// TODO: Remove this
|
||||
'@typescript-eslint/require-await': 'warn',
|
||||
'@typescript-eslint/no-unsafe-call': 'warn',
|
||||
'@typescript-eslint/naming-convention': 'warn',
|
||||
'@typescript-eslint/no-base-to-string': 'warn',
|
||||
'@typescript-eslint/no-unsafe-function-type': 'warn',
|
||||
'import-x/export': 'warn',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.test.ts'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-unused-expressions': 'warn',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'warn',
|
||||
'@typescript-eslint/unbound-method': 'warn',
|
||||
'import-x/no-duplicates': 'warn',
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -8,7 +8,7 @@
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome ci .",
|
||||
"lint": "eslint .",
|
||||
"lint": "eslint . --quiet",
|
||||
"lintfix": "eslint . --fix",
|
||||
"watch": "tsc -p tsconfig.build.json --watch",
|
||||
"test": "jest",
|
||||
|
||||
@@ -43,7 +43,7 @@ type FieldName = 'user' | 'inviter' | 'invitee';
|
||||
export const Redactable =
|
||||
(fieldName: FieldName = 'user'): MethodDecorator =>
|
||||
(_target, _propertyName, propertyDescriptor: PropertyDescriptor) => {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
const originalMethod = propertyDescriptor.value as Function;
|
||||
|
||||
type MethodArgs = Array<{ [fieldName: string]: UserLike }>;
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
const sharedOptions = require('@n8n/eslint-config/shared');
|
||||
|
||||
/** @type {import('@types/eslint').ESLint.ConfigData} */
|
||||
module.exports = {
|
||||
extends: ['@n8n/eslint-config/base'],
|
||||
...sharedOptions(__dirname),
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
},
|
||||
};
|
||||
13
packages/@n8n/di/eslint.config.mjs
Normal file
13
packages/@n8n/di/eslint.config.mjs
Normal file
@@ -0,0 +1,13 @@
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import { baseConfig } from '@n8n/eslint-config/base';
|
||||
|
||||
export default defineConfig(baseConfig, {
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
|
||||
// TODO: Remove this
|
||||
'@typescript-eslint/naming-convention': 'warn',
|
||||
'@typescript-eslint/no-unsafe-function-type': 'warn',
|
||||
'import-x/order': 'warn',
|
||||
},
|
||||
});
|
||||
@@ -8,7 +8,7 @@
|
||||
"build": "tsc -p tsconfig.build.json",
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome ci .",
|
||||
"lint": "eslint .",
|
||||
"lint": "eslint . --quiet",
|
||||
"lintfix": "eslint . --fix",
|
||||
"watch": "tsc -p tsconfig.build.json --watch",
|
||||
"test": "jest",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
// eslint-disable-next-line import-x/no-cycle
|
||||
import { ServiceB } from './service-b';
|
||||
import { Service } from '../../di';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// eslint-disable-next-line import/no-cycle
|
||||
// eslint-disable-next-line import-x/no-cycle
|
||||
import { ServiceA } from './service-a';
|
||||
import { Service } from '../../di';
|
||||
|
||||
|
||||
@@ -30,9 +30,9 @@ const instances = new Map<ServiceIdentifier, Metadata>();
|
||||
* @param options.factory Optional factory function to create instances of this class
|
||||
* @returns A class decorator to be applied to the target class
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
export function Service<T = unknown>(): Function;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-types
|
||||
export function Service<T = unknown>(options: Options<T>): Function;
|
||||
export function Service<T>({ factory }: Options<T> = {}) {
|
||||
return function (target: Constructable<T>) {
|
||||
|
||||
@@ -1,498 +0,0 @@
|
||||
/**
|
||||
* @type {import('@types/eslint').ESLint.ConfigData}
|
||||
*/
|
||||
const config = (module.exports = {
|
||||
ignorePatterns: [
|
||||
'node_modules/**',
|
||||
'dist/**',
|
||||
'tsup.config.ts',
|
||||
// TODO: remove these
|
||||
'*.js',
|
||||
],
|
||||
|
||||
plugins: [
|
||||
/**
|
||||
* Plugin with lint rules for import/export syntax
|
||||
* https://github.com/import-js/eslint-plugin-import
|
||||
*/
|
||||
'eslint-plugin-import',
|
||||
|
||||
/**
|
||||
* @typescript-eslint/eslint-plugin is required by eslint-config-airbnb-typescript
|
||||
* See step 2: https://github.com/iamturns/eslint-config-airbnb-typescript#2-install-eslint-plugins
|
||||
*/
|
||||
'@typescript-eslint',
|
||||
|
||||
/*
|
||||
* Plugin to allow specifying local ESLint rules.
|
||||
* https://github.com/ivov/eslint-plugin-n8n-local-rules
|
||||
*/
|
||||
'eslint-plugin-n8n-local-rules',
|
||||
|
||||
/** https://github.com/sweepline/eslint-plugin-unused-imports */
|
||||
'unused-imports',
|
||||
|
||||
/** https://github.com/sindresorhus/eslint-plugin-unicorn */
|
||||
'eslint-plugin-unicorn',
|
||||
|
||||
/** https://github.com/wix-incubator/eslint-plugin-lodash */
|
||||
'eslint-plugin-lodash',
|
||||
],
|
||||
|
||||
extends: [
|
||||
/**
|
||||
* Config for typescript-eslint recommended ruleset (without type checking)
|
||||
*
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/1c1b572c3000d72cfe665b7afbada0ec415e7855/packages/eslint-plugin/src/configs/recommended.ts
|
||||
*/
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
|
||||
/**
|
||||
* Config for typescript-eslint recommended ruleset (with type checking)
|
||||
*
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/1c1b572c3000d72cfe665b7afbada0ec415e7855/packages/eslint-plugin/src/configs/recommended-requiring-type-checking.ts
|
||||
*/
|
||||
'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
||||
|
||||
/**
|
||||
* Config for Airbnb style guide for TS, /base to remove React rules
|
||||
*
|
||||
* https://github.com/iamturns/eslint-config-airbnb-typescript
|
||||
* https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb-base/rules
|
||||
*/
|
||||
'eslint-config-airbnb-typescript/base',
|
||||
|
||||
/**
|
||||
* Config to disable ESLint rules covered by Prettier
|
||||
*
|
||||
* https://github.com/prettier/eslint-config-prettier
|
||||
*/
|
||||
'eslint-config-prettier',
|
||||
],
|
||||
|
||||
rules: {
|
||||
// ******************************************************************
|
||||
// additions to base ruleset
|
||||
// ******************************************************************
|
||||
|
||||
// ----------------------------------
|
||||
// ESLint
|
||||
// ----------------------------------
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/rules/id-denylist
|
||||
*/
|
||||
'id-denylist': [
|
||||
'error',
|
||||
'err',
|
||||
'cb',
|
||||
'callback',
|
||||
'any',
|
||||
'Number',
|
||||
'number',
|
||||
'String',
|
||||
'string',
|
||||
'Boolean',
|
||||
'boolean',
|
||||
'Undefined',
|
||||
'undefined',
|
||||
],
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/latest/rules/no-void
|
||||
*/
|
||||
'no-void': ['error', { allowAsStatement: true }],
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/latest/rules/indent
|
||||
*
|
||||
* Delegated to Prettier.
|
||||
*/
|
||||
indent: 'off',
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/latest/rules/no-constant-binary-expression
|
||||
*/
|
||||
'no-constant-binary-expression': 'error',
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/latest/rules/sort-imports
|
||||
*/
|
||||
'sort-imports': 'off', // @TECH_DEBT: Enable, prefs to be decided - N8N-5821
|
||||
|
||||
// ----------------------------------
|
||||
// @typescript-eslint
|
||||
// ----------------------------------
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/array-type.md
|
||||
*/
|
||||
'@typescript-eslint/array-type': ['error', { default: 'array-simple' }],
|
||||
|
||||
/** https://typescript-eslint.io/rules/await-thenable/ */
|
||||
'@typescript-eslint/await-thenable': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/ban-ts-comment.md
|
||||
*/
|
||||
'@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
|
||||
*/
|
||||
'@typescript-eslint/ban-types': [
|
||||
'error',
|
||||
{
|
||||
types: {
|
||||
Object: {
|
||||
message: 'Use object instead',
|
||||
fixWith: 'object',
|
||||
},
|
||||
String: {
|
||||
message: 'Use string instead',
|
||||
fixWith: 'string',
|
||||
},
|
||||
Boolean: {
|
||||
message: 'Use boolean instead',
|
||||
fixWith: 'boolean',
|
||||
},
|
||||
Number: {
|
||||
message: 'Use number instead',
|
||||
fixWith: 'number',
|
||||
},
|
||||
Symbol: {
|
||||
message: 'Use symbol instead',
|
||||
fixWith: 'symbol',
|
||||
},
|
||||
Function: {
|
||||
message: [
|
||||
'The `Function` type accepts any function-like value.',
|
||||
'It provides no type safety when calling the function, which can be a common source of bugs.',
|
||||
'It also accepts things like class declarations, which will throw at runtime as they will not be called with `new`.',
|
||||
'If you are expecting the function to accept certain arguments, you should explicitly define the function shape.',
|
||||
].join('\n'),
|
||||
},
|
||||
},
|
||||
extendDefaults: false,
|
||||
},
|
||||
],
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/consistent-type-assertions.md
|
||||
*/
|
||||
'@typescript-eslint/consistent-type-assertions': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/consistent-type-imports.md
|
||||
*/
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/member-delimiter-style.md
|
||||
*/
|
||||
'@typescript-eslint/member-delimiter-style': [
|
||||
'error',
|
||||
{
|
||||
multiline: {
|
||||
delimiter: 'semi',
|
||||
requireLast: true,
|
||||
},
|
||||
singleline: {
|
||||
delimiter: 'semi',
|
||||
requireLast: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/naming-convention.md
|
||||
*/
|
||||
'@typescript-eslint/naming-convention': [
|
||||
'error',
|
||||
{
|
||||
selector: 'default',
|
||||
format: ['camelCase'],
|
||||
},
|
||||
{
|
||||
selector: 'variable',
|
||||
format: ['camelCase', 'snake_case', 'UPPER_CASE', 'PascalCase'],
|
||||
leadingUnderscore: 'allowSingleOrDouble',
|
||||
trailingUnderscore: 'allowSingleOrDouble',
|
||||
},
|
||||
{
|
||||
selector: 'property',
|
||||
format: ['camelCase', 'snake_case', 'UPPER_CASE'],
|
||||
leadingUnderscore: 'allowSingleOrDouble',
|
||||
trailingUnderscore: 'allowSingleOrDouble',
|
||||
},
|
||||
{
|
||||
selector: 'typeLike',
|
||||
format: ['PascalCase'],
|
||||
},
|
||||
{
|
||||
selector: ['method', 'function', 'parameter'],
|
||||
format: ['camelCase'],
|
||||
leadingUnderscore: 'allowSingleOrDouble',
|
||||
},
|
||||
],
|
||||
|
||||
/**
|
||||
* https://github.com/import-js/eslint-plugin-import/blob/HEAD/docs/rules/no-duplicates.md
|
||||
*/
|
||||
'import/no-duplicates': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-invalid-void-type.md
|
||||
*/
|
||||
'@typescript-eslint/no-invalid-void-type': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-misused-promises.md
|
||||
*/
|
||||
'@typescript-eslint/no-misused-promises': ['error', { checksVoidReturn: false }],
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/v4.30.0/packages/eslint-plugin/docs/rules/no-floating-promises.md
|
||||
*/
|
||||
'@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: true }],
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/v4.33.0/packages/eslint-plugin/docs/rules/no-namespace.md
|
||||
*/
|
||||
'@typescript-eslint/no-namespace': 'off',
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/1.0.0/rules/no-throw-literal
|
||||
*/
|
||||
'@typescript-eslint/no-throw-literal': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unnecessary-boolean-literal-compare.md
|
||||
*/
|
||||
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unnecessary-qualifier.md
|
||||
*/
|
||||
'@typescript-eslint/no-unnecessary-qualifier': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unused-expressions.md
|
||||
*/
|
||||
'@typescript-eslint/no-unused-expressions': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.md
|
||||
*/
|
||||
'@typescript-eslint/prefer-nullish-coalescing': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/prefer-optional-chain.md
|
||||
*/
|
||||
'@typescript-eslint/prefer-optional-chain': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/promise-function-async.md
|
||||
*/
|
||||
'@typescript-eslint/promise-function-async': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/triple-slash-reference.md
|
||||
*/
|
||||
'@typescript-eslint/triple-slash-reference': 'off', // @TECH_DEBT: Enable, disallowing in all cases - N8N-5820
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/naming-convention.md
|
||||
*/
|
||||
'@typescript-eslint/naming-convention': [
|
||||
'error',
|
||||
{
|
||||
selector: 'import',
|
||||
format: ['camelCase', 'PascalCase'],
|
||||
},
|
||||
],
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/return-await.md
|
||||
*/
|
||||
'@typescript-eslint/return-await': ['error', 'always'],
|
||||
|
||||
/**
|
||||
* https://typescript-eslint.io/rules/explicit-member-accessibility/
|
||||
*/
|
||||
'@typescript-eslint/explicit-member-accessibility': ['error', { accessibility: 'no-public' }],
|
||||
|
||||
// ----------------------------------
|
||||
// eslint-plugin-import
|
||||
// ----------------------------------
|
||||
|
||||
/**
|
||||
* https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-cycle.md
|
||||
*/
|
||||
'import/no-cycle': ['error', { ignoreExternal: false, maxDepth: 3 }],
|
||||
|
||||
/**
|
||||
* https://github.com/import-js/eslint-plugin-import/blob/master/docs/rules/no-default-export.md
|
||||
*/
|
||||
'import/no-default-export': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-unresolved.md
|
||||
*/
|
||||
'import/no-unresolved': ['error', { ignore: ['^virtual:'] }],
|
||||
|
||||
/**
|
||||
* https://github.com/import-js/eslint-plugin-import/blob/master/docs/rules/order.md
|
||||
*/
|
||||
'import/order': [
|
||||
'error',
|
||||
{
|
||||
alphabetize: {
|
||||
order: 'asc',
|
||||
caseInsensitive: true,
|
||||
},
|
||||
groups: [['builtin', 'external'], 'internal', ['parent', 'index', 'sibling'], 'object'],
|
||||
'newlines-between': 'always',
|
||||
},
|
||||
],
|
||||
|
||||
// ----------------------------------
|
||||
// eslint-plugin-n8n-local-rules
|
||||
// ----------------------------------
|
||||
|
||||
'n8n-local-rules/no-uncaught-json-parse': 'error',
|
||||
|
||||
'n8n-local-rules/no-json-parse-json-stringify': 'error',
|
||||
|
||||
'n8n-local-rules/no-unneeded-backticks': 'error',
|
||||
|
||||
'n8n-local-rules/no-interpolation-in-regular-string': 'error',
|
||||
|
||||
'n8n-local-rules/no-unused-param-in-catch-clause': 'error',
|
||||
|
||||
'n8n-local-rules/no-useless-catch-throw': 'error',
|
||||
|
||||
'n8n-local-rules/no-plain-errors': 'error',
|
||||
|
||||
// ******************************************************************
|
||||
// overrides to base ruleset
|
||||
// ******************************************************************
|
||||
|
||||
// ----------------------------------
|
||||
// ESLint
|
||||
// ----------------------------------
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/rules/class-methods-use-this
|
||||
*/
|
||||
'class-methods-use-this': 'off',
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/rules/eqeqeq
|
||||
*/
|
||||
eqeqeq: 'error',
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/rules/no-plusplus
|
||||
*/
|
||||
'no-plusplus': 'off',
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/rules/object-shorthand
|
||||
*/
|
||||
'object-shorthand': 'error',
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/rules/prefer-const
|
||||
*/
|
||||
'prefer-const': 'error',
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/rules/prefer-spread
|
||||
*/
|
||||
'prefer-spread': 'error',
|
||||
|
||||
// These are tuned off since we use `noUnusedLocals` and `noUnusedParameters` now
|
||||
'no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
|
||||
/**
|
||||
* https://www.typescriptlang.org/docs/handbook/enums.html#const-enums
|
||||
*/
|
||||
'no-restricted-syntax': [
|
||||
'error',
|
||||
{
|
||||
selector: 'TSEnumDeclaration:not([const=true])',
|
||||
message:
|
||||
'Do not declare raw enums as it leads to runtime overhead. Use const enum instead. See https://www.typescriptlang.org/docs/handbook/enums.html#const-enums',
|
||||
},
|
||||
],
|
||||
|
||||
// ----------------------------------
|
||||
// import
|
||||
// ----------------------------------
|
||||
|
||||
/**
|
||||
* https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/prefer-default-export.md
|
||||
*/
|
||||
'import/prefer-default-export': 'off',
|
||||
|
||||
// ----------------------------------
|
||||
// no-unused-imports
|
||||
// ----------------------------------
|
||||
|
||||
/**
|
||||
* https://github.com/sweepline/eslint-plugin-unused-imports/blob/master/docs/rules/no-unused-imports.md
|
||||
*/
|
||||
'unused-imports/no-unused-imports': process.env.NODE_ENV === 'development' ? 'warn' : 'error',
|
||||
|
||||
/** https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unnecessary-await.md */
|
||||
'unicorn/no-unnecessary-await': 'error',
|
||||
|
||||
/** https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-promise-resolve-reject.md */
|
||||
'unicorn/no-useless-promise-resolve-reject': 'error',
|
||||
|
||||
'lodash/path-style': ['error', 'as-needed'],
|
||||
'lodash/import-scope': ['error', 'method'],
|
||||
},
|
||||
|
||||
overrides: [
|
||||
{
|
||||
files: ['test/**/*.ts', '**/__tests__/*.ts', '**/*.cy.ts'],
|
||||
rules: {
|
||||
'n8n-local-rules/no-plain-errors': 'off',
|
||||
'n8n-local-rules/no-skipped-tests':
|
||||
process.env.NODE_ENV === 'development' ? 'warn' : 'error',
|
||||
|
||||
// TODO: Remove these
|
||||
'@typescript-eslint/ban-ts-comment': 'off',
|
||||
'@typescript-eslint/naming-convention': 'off',
|
||||
'import/no-duplicates': 'off',
|
||||
'@typescript-eslint/no-empty-function': 'off',
|
||||
'@typescript-eslint/no-loop-func': 'off',
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'@typescript-eslint/no-shadow': 'off',
|
||||
'@typescript-eslint/no-throw-literal': 'off',
|
||||
'@typescript-eslint/no-unsafe-argument': 'off',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'off',
|
||||
'@typescript-eslint/no-unsafe-call': 'off',
|
||||
'@typescript-eslint/no-unsafe-member-access': 'off',
|
||||
'@typescript-eslint/no-unsafe-return': 'off',
|
||||
'@typescript-eslint/no-unused-expressions': 'off',
|
||||
'@typescript-eslint/no-use-before-define': 'off',
|
||||
'@typescript-eslint/no-var-requires': 'off',
|
||||
'@typescript-eslint/prefer-nullish-coalescing': 'off',
|
||||
'@typescript-eslint/prefer-optional-chain': 'off',
|
||||
'@typescript-eslint/restrict-plus-operands': 'off',
|
||||
'@typescript-eslint/restrict-template-expressions': 'off',
|
||||
'@typescript-eslint/unbound-method': 'off',
|
||||
'id-denylist': 'off',
|
||||
'import/no-default-export': 'off',
|
||||
'import/no-extraneous-dependencies': 'off',
|
||||
'n8n-local-rules/no-uncaught-json-parse': 'off',
|
||||
'prefer-const': 'off',
|
||||
'prefer-spread': 'off',
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -1,102 +0,0 @@
|
||||
const isCI = process.env.CI === 'true';
|
||||
|
||||
/**
|
||||
* @type {import('@types/eslint').ESLint.ConfigData}
|
||||
*/
|
||||
module.exports = {
|
||||
plugins: ['vue'],
|
||||
|
||||
extends: ['plugin:vue/vue3-recommended', '@vue/typescript', './base'],
|
||||
|
||||
env: {
|
||||
browser: true,
|
||||
es6: true,
|
||||
node: true,
|
||||
},
|
||||
|
||||
ignorePatterns: ['**/*.js', '**/*.d.ts', 'vite.config.ts', '**/*.ts.snap'],
|
||||
|
||||
overrides: [
|
||||
{
|
||||
files: ['**/*.test.ts', '**/test/**/*.ts', '**/__tests__/**/*.ts', '**/*.stories.ts'],
|
||||
rules: {
|
||||
'import/no-extraneous-dependencies': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.vue'],
|
||||
rules: {
|
||||
'vue/no-deprecated-slot-attribute': 'error',
|
||||
'vue/no-deprecated-slot-scope-attribute': 'error',
|
||||
'vue/no-multiple-template-root': 'error',
|
||||
'vue/v-slot-style': 'error',
|
||||
'vue/no-unused-components': 'error',
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'vue/component-name-in-template-casing': [
|
||||
'error',
|
||||
'PascalCase',
|
||||
{
|
||||
registeredComponentsOnly: true,
|
||||
},
|
||||
],
|
||||
'vue/no-reserved-component-names': [
|
||||
'error',
|
||||
{
|
||||
disallowVueBuiltInComponents: true,
|
||||
disallowVue3BuiltInComponents: false,
|
||||
},
|
||||
],
|
||||
'vue/prop-name-casing': ['error', 'camelCase'],
|
||||
'vue/attribute-hyphenation': ['error', 'always'],
|
||||
'vue/define-emits-declaration': ['error', 'type-literal'],
|
||||
'vue/require-macro-variable-name': [
|
||||
'error',
|
||||
{
|
||||
defineProps: 'props',
|
||||
defineEmits: 'emit',
|
||||
defineSlots: 'slots',
|
||||
useSlots: 'slots',
|
||||
useAttrs: 'attrs',
|
||||
},
|
||||
],
|
||||
'vue/block-order': [
|
||||
'error',
|
||||
{
|
||||
order: ['script', 'template', 'style'],
|
||||
},
|
||||
],
|
||||
'vue/no-v-html': 'error',
|
||||
|
||||
// TODO: remove these
|
||||
'vue/no-mutating-props': 'warn',
|
||||
'vue/no-side-effects-in-computed-properties': 'warn',
|
||||
'vue/no-v-text-v-html-on-component': 'warn',
|
||||
'vue/return-in-computed-property': 'warn',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
rules: {
|
||||
'no-console': 'warn',
|
||||
'no-debugger': isCI ? 'error' : 'off',
|
||||
semi: [2, 'always'],
|
||||
'comma-dangle': ['error', 'always-multiline'],
|
||||
'no-tabs': 0,
|
||||
'no-labels': 0,
|
||||
'@typescript-eslint/no-use-before-define': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'error',
|
||||
'import/no-extraneous-dependencies': 'warn',
|
||||
|
||||
// TODO: fix these
|
||||
'@typescript-eslint/no-unsafe-call': 'off',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'off',
|
||||
'@typescript-eslint/no-unsafe-argument': 'off',
|
||||
'@typescript-eslint/no-unsafe-return': 'off',
|
||||
'@typescript-eslint/restrict-template-expressions': 'off',
|
||||
'@typescript-eslint/unbound-method': 'off',
|
||||
'@typescript-eslint/no-unsafe-member-access': 'off',
|
||||
|
||||
// TODO: remove these
|
||||
'n8n-local-rules/no-plain-errors': 'off',
|
||||
},
|
||||
};
|
||||
@@ -1,2 +0,0 @@
|
||||
/** @type {import('jest').Config} */
|
||||
module.exports = require('../../../jest.config');
|
||||
@@ -1,465 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* This file contains any locally defined ESLint rules. They are picked up by
|
||||
* eslint-plugin-n8n-local-rules and exposed as 'n8n-local-rules/<rule-name>'.
|
||||
*/
|
||||
module.exports = {
|
||||
/**
|
||||
* A rule to detect calls to JSON.parse() that are not wrapped inside try/catch blocks.
|
||||
*
|
||||
* Valid:
|
||||
* ```js
|
||||
* try { JSON.parse(foo) } catch(err) { baz() }
|
||||
* ```
|
||||
*
|
||||
* Invalid:
|
||||
* ```js
|
||||
* JSON.parse(foo)
|
||||
* ```
|
||||
*
|
||||
* The pattern where an object is cloned with JSON.parse(JSON.stringify()) is allowed
|
||||
* (abundant in the n8n codebase):
|
||||
*
|
||||
* Valid:
|
||||
* ```js
|
||||
* JSON.parse(JSON.stringify(foo))
|
||||
* ```
|
||||
*/
|
||||
'no-uncaught-json-parse': {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'Calls to `JSON.parse()` must be replaced with `jsonParse()` from `n8n-workflow` or surrounded with a try/catch block.',
|
||||
recommended: 'error',
|
||||
},
|
||||
schema: [],
|
||||
messages: {
|
||||
noUncaughtJsonParse:
|
||||
'Use `jsonParse()` from `n8n-workflow` or surround the `JSON.parse()` call with a try/catch block.',
|
||||
},
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
return {
|
||||
CallExpression(node) {
|
||||
if (!isJsonParseCall(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isJsonStringifyCall(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.getAncestors().find((node) => node.type === 'TryStatement') !== undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Found a JSON.parse() call not wrapped into a try/catch, so report it
|
||||
context.report({
|
||||
messageId: 'noUncaughtJsonParse',
|
||||
node,
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
'no-json-parse-json-stringify': {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'Calls to `JSON.parse(JSON.stringify(arg))` must be replaced with `deepCopy(arg)` from `n8n-workflow`.',
|
||||
recommended: 'error',
|
||||
},
|
||||
messages: {
|
||||
noJsonParseJsonStringify: 'Replace with `deepCopy({{ argText }})`',
|
||||
},
|
||||
fixable: 'code',
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
CallExpression(node) {
|
||||
if (isJsonParseCall(node) && isJsonStringifyCall(node)) {
|
||||
const [callExpression] = node.arguments;
|
||||
|
||||
const { arguments: args } = callExpression;
|
||||
|
||||
if (!Array.isArray(args) || args.length !== 1) return;
|
||||
|
||||
const [arg] = args;
|
||||
|
||||
if (!arg) return;
|
||||
|
||||
const argText = context.getSourceCode().getText(arg);
|
||||
|
||||
context.report({
|
||||
messageId: 'noJsonParseJsonStringify',
|
||||
node,
|
||||
data: { argText },
|
||||
fix: (fixer) => fixer.replaceText(node, `deepCopy(${argText})`),
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
'no-unneeded-backticks': {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'Template literal backticks may only be used for string interpolation or multiline strings.',
|
||||
recommended: 'error',
|
||||
},
|
||||
messages: {
|
||||
noUneededBackticks: 'Use single or double quotes, not backticks',
|
||||
},
|
||||
fixable: 'code',
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
TemplateLiteral(node) {
|
||||
if (node.expressions.length > 0) return;
|
||||
if (node.quasis.every((q) => q.loc.start.line !== q.loc.end.line)) return;
|
||||
|
||||
node.quasis.forEach((q) => {
|
||||
const escaped = q.value.raw.replace(/(?<!\\)'/g, "\\'");
|
||||
|
||||
context.report({
|
||||
messageId: 'noUneededBackticks',
|
||||
node,
|
||||
fix: (fixer) => fixer.replaceText(q, `'${escaped}'`),
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
'no-unused-param-in-catch-clause': {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Unused param in catch clause must be omitted.',
|
||||
recommended: 'error',
|
||||
},
|
||||
messages: {
|
||||
removeUnusedParam: 'Remove unused param in catch clause',
|
||||
},
|
||||
fixable: 'code',
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
CatchClause(node) {
|
||||
if (node.param?.name?.startsWith('_')) {
|
||||
const start = node.range[0] + 'catch '.length;
|
||||
const end = node.param.range[1] + '()'.length;
|
||||
|
||||
context.report({
|
||||
messageId: 'removeUnusedParam',
|
||||
node,
|
||||
fix: (fixer) => fixer.removeRange([start, end]),
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
'no-useless-catch-throw': {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Disallow `try-catch` blocks where the `catch` only contains a `throw error`.',
|
||||
recommended: 'error',
|
||||
},
|
||||
messages: {
|
||||
noUselessCatchThrow: 'Remove useless `catch` block.',
|
||||
},
|
||||
fixable: 'code',
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
CatchClause(node) {
|
||||
if (
|
||||
node.body.body.length === 1 &&
|
||||
node.body.body[0].type === 'ThrowStatement' &&
|
||||
node.body.body[0].argument.type === 'Identifier' &&
|
||||
node.body.body[0].argument.name === node.param.name
|
||||
) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'noUselessCatchThrow',
|
||||
fix(fixer) {
|
||||
const tryStatement = node.parent;
|
||||
const tryBlock = tryStatement.block;
|
||||
const sourceCode = context.getSourceCode();
|
||||
const tryBlockText = sourceCode.getText(tryBlock);
|
||||
const tryBlockTextWithoutBraces = tryBlockText.slice(1, -1).trim();
|
||||
const indentedTryBlockText = tryBlockTextWithoutBraces
|
||||
.split('\n')
|
||||
.map((line) => line.replace(/\t/, ''))
|
||||
.join('\n');
|
||||
return fixer.replaceText(tryStatement, indentedTryBlockText);
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
'no-skipped-tests': {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Tests must not be skipped.',
|
||||
recommended: 'error',
|
||||
},
|
||||
messages: {
|
||||
removeSkip: 'Remove `.skip()` call',
|
||||
removeOnly: 'Remove `.only()` call',
|
||||
removeXPrefix: 'Remove `x` prefix',
|
||||
},
|
||||
fixable: 'code',
|
||||
},
|
||||
create(context) {
|
||||
const TESTING_FUNCTIONS = new Set(['test', 'it', 'describe']);
|
||||
const SKIPPING_METHODS = new Set(['skip', 'only']);
|
||||
const PREFIXED_TESTING_FUNCTIONS = new Set(['xtest', 'xit', 'xdescribe']);
|
||||
const toMessageId = (s) => 'remove' + s.charAt(0).toUpperCase() + s.slice(1);
|
||||
|
||||
return {
|
||||
MemberExpression(node) {
|
||||
if (
|
||||
node.object.type === 'Identifier' &&
|
||||
TESTING_FUNCTIONS.has(node.object.name) &&
|
||||
node.property.type === 'Identifier' &&
|
||||
SKIPPING_METHODS.has(node.property.name)
|
||||
) {
|
||||
context.report({
|
||||
messageId: toMessageId(node.property.name),
|
||||
node,
|
||||
fix: (fixer) => {
|
||||
const [start, end] = node.property.range;
|
||||
return fixer.removeRange([start - '.'.length, end]);
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
CallExpression(node) {
|
||||
if (
|
||||
node.callee.type === 'Identifier' &&
|
||||
PREFIXED_TESTING_FUNCTIONS.has(node.callee.name)
|
||||
) {
|
||||
context.report({
|
||||
messageId: 'removeXPrefix',
|
||||
node,
|
||||
fix: (fixer) => fixer.replaceText(node.callee, 'test'),
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
'no-interpolation-in-regular-string': {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'String interpolation `${...}` requires backticks, not single or double quotes.',
|
||||
recommended: 'error',
|
||||
},
|
||||
messages: {
|
||||
useBackticks: 'Use backticks to interpolate',
|
||||
},
|
||||
fixable: 'code',
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
Literal(node) {
|
||||
if (typeof node.value !== 'string') return;
|
||||
|
||||
if (/\$\{/.test(node.value)) {
|
||||
context.report({
|
||||
messageId: 'useBackticks',
|
||||
node,
|
||||
fix: (fixer) => fixer.replaceText(node, `\`${node.value}\``),
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
'no-plain-errors': {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'Only `ApplicationError` (from the `workflow` package) or its child classes must be thrown. This ensures the error will be normalized when reported to Sentry, if applicable.',
|
||||
recommended: 'error',
|
||||
},
|
||||
messages: {
|
||||
useApplicationError:
|
||||
'Throw an `ApplicationError` (from the `workflow` package) or its child classes.',
|
||||
},
|
||||
fixable: 'code',
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
ThrowStatement(node) {
|
||||
if (!node.argument) return;
|
||||
|
||||
const isNewError =
|
||||
node.argument.type === 'NewExpression' && node.argument.callee.name === 'Error';
|
||||
|
||||
const isNewlessError =
|
||||
node.argument.type === 'CallExpression' && node.argument.callee.name === 'Error';
|
||||
|
||||
if (isNewError || isNewlessError) {
|
||||
return context.report({
|
||||
messageId: 'useApplicationError',
|
||||
node,
|
||||
fix: (fixer) =>
|
||||
fixer.replaceText(
|
||||
node,
|
||||
`throw new ApplicationError(${node.argument.arguments
|
||||
.map((arg) => arg.raw)
|
||||
.join(', ')})`,
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
'no-dynamic-import-template': {
|
||||
meta: {
|
||||
type: 'error',
|
||||
docs: {
|
||||
description:
|
||||
'Disallow non-relative imports in template string argument to `await import()`, because `tsc-alias` as of 1.8.7 is unable to resolve aliased paths in this scenario.',
|
||||
recommended: true,
|
||||
},
|
||||
},
|
||||
create: function (context) {
|
||||
return {
|
||||
'AwaitExpression > ImportExpression TemplateLiteral'(node) {
|
||||
const templateValue = node.quasis[0].value.cooked;
|
||||
|
||||
if (!templateValue?.startsWith('@/')) return;
|
||||
|
||||
context.report({
|
||||
node,
|
||||
message:
|
||||
'Use relative imports in template string argument to `await import()`, because `tsc-alias` as of 1.8.7 is unable to resolve aliased paths in this scenario.',
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
'misplaced-n8n-typeorm-import': {
|
||||
meta: {
|
||||
type: 'error',
|
||||
docs: {
|
||||
description: 'Ensure `@n8n/typeorm` is imported only from within the `@n8n/db` package.',
|
||||
recommended: 'error',
|
||||
},
|
||||
messages: {
|
||||
moveImport: 'Please move this import to `@n8n/db`.',
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
ImportDeclaration(node) {
|
||||
if (node.source.value === '@n8n/typeorm' && !context.getFilename().includes('@n8n/db')) {
|
||||
context.report({ node, messageId: 'moveImport' });
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
'no-type-unsafe-event-emitter': {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Disallow extending from `EventEmitter`, which is not type-safe.',
|
||||
recommended: 'error',
|
||||
},
|
||||
messages: {
|
||||
noExtendsEventEmitter: 'Extend from the type-safe `TypedEmitter` class instead.',
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
ClassDeclaration(node) {
|
||||
if (
|
||||
node.superClass &&
|
||||
node.superClass.type === 'Identifier' &&
|
||||
node.superClass.name === 'EventEmitter' &&
|
||||
node.id.name !== 'TypedEmitter'
|
||||
) {
|
||||
context.report({
|
||||
node: node.superClass,
|
||||
messageId: 'noExtendsEventEmitter',
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
'no-untyped-config-class-field': {
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Enforce explicit typing of config class fields',
|
||||
recommended: 'error',
|
||||
},
|
||||
messages: {
|
||||
noUntypedConfigClassField:
|
||||
'Class field must have an explicit type annotation, e.g. `field: type = value`. See: https://github.com/n8n-io/n8n/pull/10433',
|
||||
},
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
PropertyDefinition(node) {
|
||||
if (!node.typeAnnotation) {
|
||||
context.report({ node: node.key, messageId: 'noUntypedConfigClassField' });
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const isJsonParseCall = (node) =>
|
||||
node.callee.type === 'MemberExpression' &&
|
||||
node.callee.object.type === 'Identifier' &&
|
||||
node.callee.object.name === 'JSON' &&
|
||||
node.callee.property.type === 'Identifier' &&
|
||||
node.callee.property.name === 'parse';
|
||||
|
||||
const isJsonStringifyCall = (node) => {
|
||||
const parseArg = node.arguments?.[0];
|
||||
return (
|
||||
parseArg !== undefined &&
|
||||
parseArg.type === 'CallExpression' &&
|
||||
parseArg.callee.type === 'MemberExpression' &&
|
||||
parseArg.callee.object.type === 'Identifier' &&
|
||||
parseArg.callee.object.name === 'JSON' &&
|
||||
parseArg.callee.property.type === 'Identifier' &&
|
||||
parseArg.callee.property.name === 'stringify'
|
||||
);
|
||||
};
|
||||
@@ -1,83 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const rules = require('./local-rules'),
|
||||
RuleTester = require('eslint').RuleTester;
|
||||
|
||||
const ruleTester = new RuleTester();
|
||||
|
||||
ruleTester.run('no-uncaught-json-parse', rules['no-uncaught-json-parse'], {
|
||||
valid: [
|
||||
{
|
||||
code: 'try { JSON.parse(foo) } catch (e) {}',
|
||||
},
|
||||
{
|
||||
code: 'JSON.parse(JSON.stringify(foo))',
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
code: 'JSON.parse(foo)',
|
||||
errors: [{ messageId: 'noUncaughtJsonParse' }],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
ruleTester.run('no-json-parse-json-stringify', rules['no-json-parse-json-stringify'], {
|
||||
valid: [
|
||||
{
|
||||
code: 'deepCopy(foo)',
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
code: 'JSON.parse(JSON.stringify(foo))',
|
||||
errors: [{ messageId: 'noJsonParseJsonStringify' }],
|
||||
output: 'deepCopy(foo)',
|
||||
},
|
||||
{
|
||||
code: 'JSON.parse(JSON.stringify(foo.bar))',
|
||||
errors: [{ messageId: 'noJsonParseJsonStringify' }],
|
||||
output: 'deepCopy(foo.bar)',
|
||||
},
|
||||
{
|
||||
code: 'JSON.parse(JSON.stringify(foo.bar.baz))',
|
||||
errors: [{ messageId: 'noJsonParseJsonStringify' }],
|
||||
output: 'deepCopy(foo.bar.baz)',
|
||||
},
|
||||
{
|
||||
code: 'JSON.parse(JSON.stringify(foo.bar[baz]))',
|
||||
errors: [{ messageId: 'noJsonParseJsonStringify' }],
|
||||
output: 'deepCopy(foo.bar[baz])',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
ruleTester.run('no-useless-catch-throw', rules['no-useless-catch-throw'], {
|
||||
valid: [
|
||||
{
|
||||
code: 'try { foo(); } catch (e) { console.error(e); }',
|
||||
},
|
||||
{
|
||||
code: 'try { foo(); } catch (e) { throw new Error("Custom error"); }',
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
code: `
|
||||
try {
|
||||
// Some comment
|
||||
if (foo) {
|
||||
bar();
|
||||
}
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}`,
|
||||
errors: [{ messageId: 'noUselessCatchThrow' }],
|
||||
output: `
|
||||
// Some comment
|
||||
if (foo) {
|
||||
bar();
|
||||
}`,
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -1,11 +0,0 @@
|
||||
/**
|
||||
* @type {import('@types/eslint').ESLint.ConfigData}
|
||||
*/
|
||||
module.exports = {
|
||||
extends: ['./base'],
|
||||
|
||||
env: {
|
||||
es6: true,
|
||||
node: true,
|
||||
},
|
||||
};
|
||||
@@ -1,33 +1,57 @@
|
||||
{
|
||||
"name": "@n8n/eslint-config",
|
||||
"private": true,
|
||||
"name": "@n8n/eslint-config",
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"exports": {
|
||||
"./base": "./base.js",
|
||||
"./frontend": "./frontend.js",
|
||||
"./local-rules": "./local-rules.js",
|
||||
"./node": "./node.js",
|
||||
"./shared": "./shared.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/eslint": "^8.56.5",
|
||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||
"@typescript-eslint/parser": "^7.2.0",
|
||||
"@vue/eslint-config-typescript": "^13.0.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-airbnb-typescript": "^18.0.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-import-resolver-typescript": "^3.6.1",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-lodash": "^7.4.0",
|
||||
"eslint-plugin-n8n-local-rules": "^1.0.0",
|
||||
"eslint-plugin-unicorn": "^51.0.1",
|
||||
"eslint-plugin-unused-imports": "^3.1.0",
|
||||
"eslint-plugin-vue": "^9.23.0",
|
||||
"vue-eslint-parser": "^9.4.2"
|
||||
"./base": {
|
||||
"default": "./dist/configs/base.js",
|
||||
"types": "./dist/configs/base.d.js"
|
||||
},
|
||||
"./frontend": {
|
||||
"default": "./dist/configs/frontend.js",
|
||||
"types": "./dist/configs/frontend.d.js"
|
||||
},
|
||||
"./node": {
|
||||
"default": "./dist/configs/node.js",
|
||||
"types": "./dist/configs/node.d.js"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf .turbo",
|
||||
"test": "jest"
|
||||
"build": "tsc",
|
||||
"clean": "rimraf dist .turbo",
|
||||
"dev": "pnpm watch",
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome ci .",
|
||||
"test": "vitest run",
|
||||
"test:dev": "vitest",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"watch": "tsc --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.29.0",
|
||||
"@n8n/typescript-config": "workspace:*",
|
||||
"@n8n/vitest-config": "workspace:*",
|
||||
"@stylistic/eslint-plugin": "^5.0.0",
|
||||
"@types/eslint": "^9.6.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.35.0",
|
||||
"@typescript-eslint/rule-tester": "^8.35.0",
|
||||
"@typescript-eslint/utils": "^8.35.0",
|
||||
"eslint-config-prettier": "^10.1.5",
|
||||
"eslint-import-resolver-typescript": "^4.4.3",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-import-x": "^4.15.2",
|
||||
"eslint-plugin-lodash": "^8.0.0",
|
||||
"eslint-plugin-unicorn": "^59.0.1",
|
||||
"eslint-plugin-unused-imports": "^4.1.4",
|
||||
"eslint-plugin-vue": "^10.2.0",
|
||||
"globals": "^16.2.0",
|
||||
"tsup": "catalog:",
|
||||
"typescript": "catalog:",
|
||||
"typescript-eslint": "^8.35.0",
|
||||
"vitest": "catalog:"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"eslint": ">= 9"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/**
|
||||
* @type {(dir: string, mode: 'frontend' | undefined) => import('@types/eslint').ESLint.ConfigData}
|
||||
*/
|
||||
module.exports = (tsconfigRootDir, mode) => {
|
||||
const isFrontend = mode === 'frontend';
|
||||
const parser = isFrontend ? 'vue-eslint-parser' : '@typescript-eslint/parser';
|
||||
const extraParserOptions = isFrontend
|
||||
? {
|
||||
extraFileExtensions: ['.vue'],
|
||||
parser: {
|
||||
ts: '@typescript-eslint/parser',
|
||||
js: '@typescript-eslint/parser',
|
||||
vue: 'vue-eslint-parser',
|
||||
template: 'vue-eslint-parser',
|
||||
},
|
||||
}
|
||||
: {};
|
||||
|
||||
const settings = {
|
||||
'import/parsers': {
|
||||
'@typescript-eslint/parser': ['.ts'],
|
||||
},
|
||||
|
||||
'import/resolver': {
|
||||
typescript: {
|
||||
tsconfigRootDir,
|
||||
project: './tsconfig.json',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
parser,
|
||||
parserOptions: {
|
||||
tsconfigRootDir,
|
||||
project: ['./tsconfig.json'],
|
||||
...extraParserOptions,
|
||||
},
|
||||
settings,
|
||||
};
|
||||
};
|
||||
423
packages/@n8n/eslint-config/src/configs/base.ts
Normal file
423
packages/@n8n/eslint-config/src/configs/base.ts
Normal file
@@ -0,0 +1,423 @@
|
||||
import { globalIgnores } from 'eslint/config';
|
||||
import eslint from '@eslint/js';
|
||||
import importPlugin from 'eslint-plugin-import-x';
|
||||
import typescriptPlugin from '@typescript-eslint/eslint-plugin';
|
||||
import unusedImportsPlugin from 'eslint-plugin-unused-imports';
|
||||
import stylisticPlugin from '@stylistic/eslint-plugin';
|
||||
import unicornPlugin from 'eslint-plugin-unicorn';
|
||||
import lodashPlugin from 'eslint-plugin-lodash';
|
||||
import { localRulesPlugin } from '../plugin.js';
|
||||
import tseslint from 'typescript-eslint';
|
||||
import eslintConfigPrettier from 'eslint-config-prettier/flat';
|
||||
import { createTypeScriptImportResolver } from 'eslint-import-resolver-typescript';
|
||||
|
||||
// Slowest rules are disabled locally to improve performance in development
|
||||
// They are enabled in CI to ensure code quality
|
||||
const runAllRules = process.env.CI === 'true' || process.env.INCLUDE_SLOW_RULES === 'true';
|
||||
|
||||
export const baseConfig = tseslint.config(
|
||||
globalIgnores([
|
||||
'node_modules/**',
|
||||
'dist/**',
|
||||
'eslint.config.mjs',
|
||||
'tsup.config.ts',
|
||||
'jest.config.js',
|
||||
'cypress.config.js',
|
||||
]),
|
||||
eslint.configs.recommended,
|
||||
tseslint.configs.recommended,
|
||||
tseslint.configs.recommendedTypeChecked,
|
||||
importPlugin.flatConfigs.recommended,
|
||||
importPlugin.flatConfigs.typescript,
|
||||
eslintConfigPrettier,
|
||||
localRulesPlugin.configs.recommended,
|
||||
{
|
||||
plugins: {
|
||||
'unused-imports': unusedImportsPlugin,
|
||||
'@stylistic': stylisticPlugin,
|
||||
lodash: lodashPlugin,
|
||||
unicorn: unicornPlugin,
|
||||
'@typescript-eslint': typescriptPlugin,
|
||||
},
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
projectService: true,
|
||||
},
|
||||
},
|
||||
settings: {
|
||||
'import-x/resolver-next': [createTypeScriptImportResolver()],
|
||||
},
|
||||
rules: {
|
||||
// ******************************************************************
|
||||
// additions to base ruleset
|
||||
// ******************************************************************
|
||||
|
||||
// ----------------------------------
|
||||
// ESLint
|
||||
// ----------------------------------
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/rules/id-denylist
|
||||
*/
|
||||
'id-denylist': [
|
||||
'error',
|
||||
'err',
|
||||
'cb',
|
||||
'callback',
|
||||
'any',
|
||||
'Number',
|
||||
'number',
|
||||
'String',
|
||||
'string',
|
||||
'Boolean',
|
||||
'boolean',
|
||||
'Undefined',
|
||||
'undefined',
|
||||
],
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/latest/rules/no-void
|
||||
*/
|
||||
'no-void': ['error', { allowAsStatement: true }],
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/latest/rules/indent
|
||||
*
|
||||
* Delegated to Prettier.
|
||||
*/
|
||||
indent: 'off',
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/latest/rules/no-constant-binary-expression
|
||||
*/
|
||||
'no-constant-binary-expression': 'error',
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/latest/rules/sort-imports
|
||||
*/
|
||||
'sort-imports': 'off', // @TECH_DEBT: Enable, prefs to be decided - N8N-5821
|
||||
|
||||
// ----------------------------------
|
||||
// @typescript-eslint
|
||||
// ----------------------------------
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/array-type.md
|
||||
*/
|
||||
'@typescript-eslint/array-type': ['error', { default: 'array-simple' }],
|
||||
|
||||
/** https://typescript-eslint.io/rules/await-thenable/ */
|
||||
'@typescript-eslint/await-thenable': runAllRules ? 'error' : 'off',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/ban-ts-comment.md
|
||||
*/
|
||||
'@typescript-eslint/ban-ts-comment': ['error', { 'ts-ignore': true }],
|
||||
|
||||
/**
|
||||
* https://typescript-eslint.io/rules/no-restricted-types
|
||||
*/
|
||||
'@typescript-eslint/no-restricted-types': [
|
||||
'error',
|
||||
{
|
||||
types: {
|
||||
Object: {
|
||||
message: 'Use object instead',
|
||||
fixWith: 'object',
|
||||
},
|
||||
String: {
|
||||
message: 'Use string instead',
|
||||
fixWith: 'string',
|
||||
},
|
||||
Boolean: {
|
||||
message: 'Use boolean instead',
|
||||
fixWith: 'boolean',
|
||||
},
|
||||
Number: {
|
||||
message: 'Use number instead',
|
||||
fixWith: 'number',
|
||||
},
|
||||
Symbol: {
|
||||
message: 'Use symbol instead',
|
||||
fixWith: 'symbol',
|
||||
},
|
||||
Function: {
|
||||
message: [
|
||||
'The `Function` type accepts any function-like value.',
|
||||
'It provides no type safety when calling the function, which can be a common source of bugs.',
|
||||
'It also accepts things like class declarations, which will throw at runtime as they will not be called with `new`.',
|
||||
'If you are expecting the function to accept certain arguments, you should explicitly define the function shape.',
|
||||
].join('\n'),
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/consistent-type-assertions.md
|
||||
*/
|
||||
'@typescript-eslint/consistent-type-assertions': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/consistent-type-imports.md
|
||||
*/
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/member-delimiter-style.md
|
||||
*/
|
||||
'@stylistic/member-delimiter-style': [
|
||||
'error',
|
||||
{
|
||||
multiline: {
|
||||
delimiter: 'semi',
|
||||
requireLast: true,
|
||||
},
|
||||
singleline: {
|
||||
delimiter: 'semi',
|
||||
requireLast: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
// Not needed because we use Biome formatting
|
||||
'@stylistic/ident': 'off',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/naming-convention.md
|
||||
*/
|
||||
'@typescript-eslint/naming-convention': [
|
||||
'error',
|
||||
{
|
||||
selector: 'default',
|
||||
format: ['camelCase'],
|
||||
},
|
||||
{
|
||||
selector: 'import',
|
||||
format: ['camelCase', 'PascalCase'],
|
||||
},
|
||||
{
|
||||
selector: 'variable',
|
||||
format: ['camelCase', 'snake_case', 'UPPER_CASE', 'PascalCase'],
|
||||
leadingUnderscore: 'allowSingleOrDouble',
|
||||
trailingUnderscore: 'allowSingleOrDouble',
|
||||
},
|
||||
{
|
||||
selector: 'property',
|
||||
format: ['camelCase', 'snake_case', 'UPPER_CASE'],
|
||||
leadingUnderscore: 'allowSingleOrDouble',
|
||||
trailingUnderscore: 'allowSingleOrDouble',
|
||||
},
|
||||
{
|
||||
selector: 'typeLike',
|
||||
format: ['PascalCase'],
|
||||
},
|
||||
{
|
||||
selector: ['method', 'function', 'parameter'],
|
||||
format: ['camelCase'],
|
||||
leadingUnderscore: 'allowSingleOrDouble',
|
||||
},
|
||||
],
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-invalid-void-type.md
|
||||
*/
|
||||
'@typescript-eslint/no-invalid-void-type': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-misused-promises.md
|
||||
*/
|
||||
'@typescript-eslint/no-misused-promises': runAllRules
|
||||
? ['error', { checksVoidReturn: false }]
|
||||
: 'off',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/v4.30.0/packages/eslint-plugin/docs/rules/no-floating-promises.md
|
||||
*/
|
||||
'@typescript-eslint/no-floating-promises': runAllRules
|
||||
? ['error', { ignoreVoid: true }]
|
||||
: 'off',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/v4.33.0/packages/eslint-plugin/docs/rules/no-namespace.md
|
||||
*/
|
||||
'@typescript-eslint/no-namespace': 'off',
|
||||
|
||||
/**
|
||||
* https://typescript-eslint.io/rules/only-throw-error/
|
||||
*/
|
||||
'@typescript-eslint/only-throw-error': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unnecessary-boolean-literal-compare.md
|
||||
*/
|
||||
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unnecessary-qualifier.md
|
||||
*/
|
||||
'@typescript-eslint/no-unnecessary-qualifier': runAllRules ? 'error' : 'off',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unused-expressions.md
|
||||
*/
|
||||
'@typescript-eslint/no-unused-expressions': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.md
|
||||
*/
|
||||
'@typescript-eslint/prefer-nullish-coalescing': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/prefer-optional-chain.md
|
||||
*/
|
||||
'@typescript-eslint/prefer-optional-chain': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/promise-function-async.md
|
||||
*/
|
||||
'@typescript-eslint/promise-function-async': runAllRules ? 'error' : 'off',
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/triple-slash-reference.md
|
||||
*/
|
||||
'@typescript-eslint/triple-slash-reference': 'off', // @TECH_DEBT: Enable, disallowing in all cases - N8N-5820
|
||||
|
||||
/**
|
||||
* https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/return-await.md
|
||||
*/
|
||||
'@typescript-eslint/return-await': ['error', 'always'],
|
||||
|
||||
/**
|
||||
* https://typescript-eslint.io/rules/explicit-member-accessibility/
|
||||
*/
|
||||
'@typescript-eslint/explicit-member-accessibility': ['error', { accessibility: 'no-public' }],
|
||||
|
||||
// ----------------------------------
|
||||
// eslint-plugin-import
|
||||
// ----------------------------------
|
||||
|
||||
/**
|
||||
* https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-cycle.md
|
||||
*/
|
||||
'import-x/no-cycle': runAllRules ? ['error', { ignoreExternal: false, maxDepth: 3 }] : 'off',
|
||||
|
||||
/**
|
||||
* https://github.com/import-js/eslint-plugin-import/blob/master/docs/rules/no-default-export.md
|
||||
*/
|
||||
'import-x/no-default-export': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/import-js/eslint-plugin-import/blob/master/docs/rules/order.md
|
||||
*/
|
||||
'import-x/order': [
|
||||
'error',
|
||||
{
|
||||
alphabetize: {
|
||||
order: 'asc',
|
||||
caseInsensitive: true,
|
||||
},
|
||||
groups: [['builtin', 'external'], 'internal', ['parent', 'index', 'sibling'], 'object'],
|
||||
'newlines-between': 'always',
|
||||
},
|
||||
],
|
||||
|
||||
/**
|
||||
* https://github.com/import-js/eslint-plugin-import/blob/HEAD/docs/rules/no-duplicates.md
|
||||
*/
|
||||
'import-x/no-duplicates': 'error',
|
||||
|
||||
/**
|
||||
* https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/prefer-default-export.md
|
||||
*/
|
||||
'import-x/prefer-default-export': 'off',
|
||||
|
||||
// These rules are not needed as TypeScript handles them
|
||||
'import-x/named': 'off',
|
||||
'import-x/namespace': 'off',
|
||||
'import-x/default': 'off',
|
||||
'import-x/no-named-as-default-member': 'off',
|
||||
'import-x/no-unresolved': 'off',
|
||||
|
||||
// ******************************************************************
|
||||
// overrides to base ruleset
|
||||
// ******************************************************************
|
||||
|
||||
// ----------------------------------
|
||||
// ESLint
|
||||
// ----------------------------------
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/rules/class-methods-use-this
|
||||
*/
|
||||
'class-methods-use-this': 'off',
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/rules/eqeqeq
|
||||
*/
|
||||
eqeqeq: 'error',
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/rules/no-plusplus
|
||||
*/
|
||||
'no-plusplus': 'off',
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/rules/object-shorthand
|
||||
*/
|
||||
'object-shorthand': 'error',
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/rules/prefer-const
|
||||
*/
|
||||
'prefer-const': 'error',
|
||||
|
||||
/**
|
||||
* https://eslint.org/docs/rules/prefer-spread
|
||||
*/
|
||||
'prefer-spread': 'error',
|
||||
|
||||
// These are tuned off since we use `noUnusedLocals` and `noUnusedParameters` now
|
||||
'no-unused-vars': 'off',
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
|
||||
/**
|
||||
* https://www.typescriptlang.org/docs/handbook/enums.html#const-enums
|
||||
*/
|
||||
'no-restricted-syntax': [
|
||||
'error',
|
||||
{
|
||||
selector: 'TSEnumDeclaration:not([const=true])',
|
||||
message:
|
||||
'Do not declare raw enums as it leads to runtime overhead. Use const enum instead. See https://www.typescriptlang.org/docs/handbook/enums.html#const-enums',
|
||||
},
|
||||
],
|
||||
|
||||
// ----------------------------------
|
||||
// no-unused-imports
|
||||
// ----------------------------------
|
||||
|
||||
/**
|
||||
* https://github.com/sweepline/eslint-plugin-unused-imports/blob/master/docs/rules/no-unused-imports.md
|
||||
*/
|
||||
'unused-imports/no-unused-imports': process.env.NODE_ENV === 'development' ? 'warn' : 'error',
|
||||
|
||||
/** https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-unnecessary-await.md */
|
||||
'unicorn/no-unnecessary-await': 'error',
|
||||
|
||||
/** https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-useless-promise-resolve-reject.md */
|
||||
'unicorn/no-useless-promise-resolve-reject': 'error',
|
||||
|
||||
'lodash/path-style': ['error', 'as-needed'],
|
||||
'lodash/import-scope': ['error', 'method'],
|
||||
},
|
||||
},
|
||||
{
|
||||
// Rules for unit tests
|
||||
files: ['test/**/*.ts', '**/__tests__/*.ts', '**/*.test.ts', '**/*.cy.ts'],
|
||||
rules: {
|
||||
'n8n-local-rules/no-plain-errors': 'off',
|
||||
'n8n-local-rules/no-skipped-tests': process.env.NODE_ENV === 'development' ? 'warn' : 'error',
|
||||
},
|
||||
},
|
||||
);
|
||||
101
packages/@n8n/eslint-config/src/configs/frontend.ts
Normal file
101
packages/@n8n/eslint-config/src/configs/frontend.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { globalIgnores } from 'eslint/config';
|
||||
import tseslint from 'typescript-eslint';
|
||||
import VuePlugin from 'eslint-plugin-vue';
|
||||
import globals from 'globals';
|
||||
import { baseConfig } from './base.js';
|
||||
|
||||
const isCI = process.env.CI === 'true';
|
||||
const extraFileExtensions = ['.vue'];
|
||||
const allGlobals = { NodeJS: true, ...globals.node, ...globals.browser };
|
||||
|
||||
export const frontendConfig = tseslint.config(
|
||||
globalIgnores(['**/*.js', '**/*.d.ts', 'vite.config.ts', '**/*.ts.snap']),
|
||||
baseConfig,
|
||||
VuePlugin.configs['flat/recommended'],
|
||||
{
|
||||
rules: {
|
||||
'no-console': 'warn',
|
||||
'no-debugger': isCI ? 'error' : 'off',
|
||||
semi: [2, 'always'],
|
||||
'comma-dangle': ['error', 'always-multiline'],
|
||||
'@typescript-eslint/no-use-before-define': 'warn',
|
||||
'@typescript-eslint/no-explicit-any': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.ts'],
|
||||
languageOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
globals: allGlobals,
|
||||
parser: tseslint.parser,
|
||||
parserOptions: { projectService: true, extraFileExtensions },
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.test.ts', '**/test/**/*.ts', '**/__tests__/**/*.ts', '**/*.stories.ts'],
|
||||
rules: {
|
||||
'import-x/no-extraneous-dependencies': 'warn',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.vue'],
|
||||
languageOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module',
|
||||
globals: allGlobals,
|
||||
parserOptions: {
|
||||
parser: tseslint.parser,
|
||||
extraFileExtensions,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
'vue/no-deprecated-slot-attribute': 'error',
|
||||
'vue/no-deprecated-slot-scope-attribute': 'error',
|
||||
'vue/no-multiple-template-root': 'error',
|
||||
'vue/v-slot-style': 'error',
|
||||
'vue/no-unused-components': 'error',
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'vue/component-name-in-template-casing': [
|
||||
'error',
|
||||
'PascalCase',
|
||||
{
|
||||
registeredComponentsOnly: true,
|
||||
},
|
||||
],
|
||||
'vue/no-reserved-component-names': [
|
||||
'error',
|
||||
{
|
||||
disallowVueBuiltInComponents: true,
|
||||
disallowVue3BuiltInComponents: false,
|
||||
},
|
||||
],
|
||||
'vue/prop-name-casing': ['error', 'camelCase'],
|
||||
'vue/attribute-hyphenation': ['error', 'always'],
|
||||
'vue/define-emits-declaration': ['error', 'type-literal'],
|
||||
'vue/require-macro-variable-name': [
|
||||
'error',
|
||||
{
|
||||
defineProps: 'props',
|
||||
defineEmits: 'emit',
|
||||
defineSlots: 'slots',
|
||||
useSlots: 'slots',
|
||||
useAttrs: 'attrs',
|
||||
},
|
||||
],
|
||||
'vue/block-order': [
|
||||
'error',
|
||||
{
|
||||
order: ['script', 'template', 'style'],
|
||||
},
|
||||
],
|
||||
'vue/no-v-html': 'error',
|
||||
|
||||
// TODO: remove these
|
||||
'vue/no-mutating-props': 'warn',
|
||||
'vue/no-side-effects-in-computed-properties': 'warn',
|
||||
'vue/no-v-text-v-html-on-component': 'warn',
|
||||
'vue/return-in-computed-property': 'warn',
|
||||
},
|
||||
},
|
||||
);
|
||||
10
packages/@n8n/eslint-config/src/configs/node.ts
Normal file
10
packages/@n8n/eslint-config/src/configs/node.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import tseslint from 'typescript-eslint';
|
||||
import globals from 'globals';
|
||||
import { baseConfig } from './base.js';
|
||||
|
||||
export const nodeConfig = tseslint.config(baseConfig, {
|
||||
languageOptions: {
|
||||
ecmaVersion: 2024,
|
||||
globals: globals.node,
|
||||
},
|
||||
});
|
||||
30
packages/@n8n/eslint-config/src/plugin.ts
Normal file
30
packages/@n8n/eslint-config/src/plugin.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import type { ESLint } from 'eslint';
|
||||
import { rules } from './rules/index.js';
|
||||
|
||||
const plugin = {
|
||||
meta: {
|
||||
name: 'n8n-local-rules',
|
||||
},
|
||||
configs: {},
|
||||
// @ts-expect-error Rules type does not match for typescript-eslint and eslint
|
||||
rules: rules as ESLint.Plugin['rules'],
|
||||
} satisfies ESLint.Plugin;
|
||||
|
||||
export const localRulesPlugin = {
|
||||
...plugin,
|
||||
configs: {
|
||||
recommended: {
|
||||
plugins: {
|
||||
'n8n-local-rules': plugin,
|
||||
},
|
||||
rules: {
|
||||
'n8n-local-rules/no-uncaught-json-parse': 'error',
|
||||
'n8n-local-rules/no-json-parse-json-stringify': 'error',
|
||||
'n8n-local-rules/no-unneeded-backticks': 'error',
|
||||
'n8n-local-rules/no-interpolation-in-regular-string': 'error',
|
||||
'n8n-local-rules/no-unused-param-in-catch-clause': 'error',
|
||||
'n8n-local-rules/no-useless-catch-throw': 'error',
|
||||
},
|
||||
},
|
||||
},
|
||||
} satisfies ESLint.Plugin;
|
||||
1
packages/@n8n/eslint-config/src/plugins.d.ts
vendored
Normal file
1
packages/@n8n/eslint-config/src/plugins.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
declare module 'eslint-plugin-lodash';
|
||||
28
packages/@n8n/eslint-config/src/rules/index.ts
Normal file
28
packages/@n8n/eslint-config/src/rules/index.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { NoJsonParseJsonStringifyRule } from './no-json-parse-json-stringify.js';
|
||||
import { NoUncaughtJsonParseRule } from './no-uncaught-json-parse.js';
|
||||
import { NoUnneededBackticksRule } from './no-unneeded-backticks.js';
|
||||
import { NoUnusedParamInCatchClauseRule } from './no-unused-param-catch-clause.js';
|
||||
import { NoUselessCatchThrowRule } from './no-useless-catch-throw.js';
|
||||
import { NoSkippedTestsRule } from './no-skipped-tests.js';
|
||||
import { NoInterpolationInRegularStringRule } from './no-interpolation-in-regular-string.js';
|
||||
import { NoPlainErrorsRule } from './no-plain-errors.js';
|
||||
import { NoDynamicImportTemplateRule } from './no-dynamic-import-template.js';
|
||||
import { MisplacedN8nTypeormImportRule } from './misplaced-n8n-typeorm-import.js';
|
||||
import { NoTypeUnsafeEventEmitterRule } from './no-type-unsafe-event-emitter.js';
|
||||
import { NoUntypedConfigClassFieldRule } from './no-untyped-config-class-field.js';
|
||||
import type { AnyRuleModule } from '@typescript-eslint/utils/ts-eslint';
|
||||
|
||||
export const rules = {
|
||||
'no-uncaught-json-parse': NoUncaughtJsonParseRule,
|
||||
'no-json-parse-json-stringify': NoJsonParseJsonStringifyRule,
|
||||
'no-unneeded-backticks': NoUnneededBackticksRule,
|
||||
'no-unused-param-in-catch-clause': NoUnusedParamInCatchClauseRule,
|
||||
'no-useless-catch-throw': NoUselessCatchThrowRule,
|
||||
'no-skipped-tests': NoSkippedTestsRule,
|
||||
'no-interpolation-in-regular-string': NoInterpolationInRegularStringRule,
|
||||
'no-plain-errors': NoPlainErrorsRule,
|
||||
'no-dynamic-import-template': NoDynamicImportTemplateRule,
|
||||
'misplaced-n8n-typeorm-import': MisplacedN8nTypeormImportRule,
|
||||
'no-type-unsafe-event-emitter': NoTypeUnsafeEventEmitterRule,
|
||||
'no-untyped-config-class-field': NoUntypedConfigClassFieldRule,
|
||||
} satisfies Record<string, AnyRuleModule>;
|
||||
@@ -0,0 +1,24 @@
|
||||
import { ESLintUtils } from '@typescript-eslint/utils';
|
||||
|
||||
export const MisplacedN8nTypeormImportRule = ESLintUtils.RuleCreator.withoutDocs({
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Ensure `@n8n/typeorm` is imported only from within the `@n8n/db` package.',
|
||||
},
|
||||
messages: {
|
||||
moveImport: 'Please move this import to `@n8n/db`.',
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
return {
|
||||
ImportDeclaration(node) {
|
||||
if (node.source.value === '@n8n/typeorm' && !context.filename.includes('@n8n/db')) {
|
||||
context.report({ node, messageId: 'moveImport' });
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
import { ESLintUtils, type TSESTree } from '@typescript-eslint/utils';
|
||||
|
||||
export const NoDynamicImportTemplateRule = ESLintUtils.RuleCreator.withoutDocs({
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'Disallow non-relative imports in template string argument to `await import()`, because `tsc-alias` as of 1.8.7 is unable to resolve aliased paths in this scenario.',
|
||||
},
|
||||
schema: [],
|
||||
messages: {
|
||||
noDynamicImportTemplate:
|
||||
'Use relative imports in template string argument to `await import()`, because `tsc-alias` as of 1.8.7 is unable to resolve aliased paths in this scenario.',
|
||||
},
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
return {
|
||||
'AwaitExpression > ImportExpression TemplateLiteral'(node: TSESTree.TemplateLiteral) {
|
||||
const templateValue = node.quasis[0].value.cooked;
|
||||
|
||||
if (!templateValue?.startsWith('@/')) return;
|
||||
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'noDynamicImportTemplate',
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
import { ESLintUtils } from '@typescript-eslint/utils';
|
||||
|
||||
export const NoInterpolationInRegularStringRule = ESLintUtils.RuleCreator.withoutDocs({
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'String interpolation `${...}` requires backticks, not single or double quotes.',
|
||||
},
|
||||
messages: {
|
||||
useBackticks: 'Use backticks to interpolate',
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [],
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
return {
|
||||
Literal(node) {
|
||||
if (typeof node.value !== 'string') return;
|
||||
|
||||
if (/\$\{/.test(node.value)) {
|
||||
context.report({
|
||||
messageId: 'useBackticks',
|
||||
node,
|
||||
fix: (fixer) => fixer.replaceText(node, `\`${node.value}\``),
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
import { RuleTester } from '@typescript-eslint/rule-tester';
|
||||
import { NoJsonParseJsonStringifyRule } from './no-json-parse-json-stringify.js';
|
||||
|
||||
const ruleTester = new RuleTester();
|
||||
|
||||
ruleTester.run('no-json-parse-json-stringify', NoJsonParseJsonStringifyRule, {
|
||||
valid: [
|
||||
{
|
||||
code: 'deepCopy(foo)',
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
code: 'JSON.parse(JSON.stringify(foo))',
|
||||
errors: [{ messageId: 'noJsonParseJsonStringify' }],
|
||||
output: 'deepCopy(foo)',
|
||||
},
|
||||
{
|
||||
code: 'JSON.parse(JSON.stringify(foo.bar))',
|
||||
errors: [{ messageId: 'noJsonParseJsonStringify' }],
|
||||
output: 'deepCopy(foo.bar)',
|
||||
},
|
||||
{
|
||||
code: 'JSON.parse(JSON.stringify(foo.bar.baz))',
|
||||
errors: [{ messageId: 'noJsonParseJsonStringify' }],
|
||||
output: 'deepCopy(foo.bar.baz)',
|
||||
},
|
||||
{
|
||||
code: 'JSON.parse(JSON.stringify(foo.bar[baz]))',
|
||||
errors: [{ messageId: 'noJsonParseJsonStringify' }],
|
||||
output: 'deepCopy(foo.bar[baz])',
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,48 @@
|
||||
import { isJsonParseCall, isJsonStringifyCall } from '../utils/json.js';
|
||||
import { ESLintUtils, TSESTree } from '@typescript-eslint/utils';
|
||||
|
||||
export const NoJsonParseJsonStringifyRule = ESLintUtils.RuleCreator.withoutDocs({
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'Calls to `JSON.parse(JSON.stringify(arg))` must be replaced with `deepCopy(arg)` from `n8n-workflow`.',
|
||||
},
|
||||
schema: [],
|
||||
messages: {
|
||||
noJsonParseJsonStringify: 'Replace with `deepCopy({{ argText }})`',
|
||||
},
|
||||
fixable: 'code',
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
return {
|
||||
CallExpression(node) {
|
||||
if (isJsonParseCall(node) && isJsonStringifyCall(node)) {
|
||||
const [callExpression] = node.arguments;
|
||||
|
||||
if (callExpression.type !== TSESTree.AST_NODE_TYPES.CallExpression) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { arguments: args } = callExpression;
|
||||
|
||||
if (!Array.isArray(args) || args.length !== 1) return;
|
||||
|
||||
const [arg] = args;
|
||||
|
||||
if (!arg) return;
|
||||
|
||||
const argText = context.sourceCode.getText(arg);
|
||||
|
||||
context.report({
|
||||
messageId: 'noJsonParseJsonStringify',
|
||||
node,
|
||||
data: { argText },
|
||||
fix: (fixer) => fixer.replaceText(node, `deepCopy(${argText})`),
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
49
packages/@n8n/eslint-config/src/rules/no-plain-errors.ts
Normal file
49
packages/@n8n/eslint-config/src/rules/no-plain-errors.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { ESLintUtils, TSESTree } from '@typescript-eslint/utils';
|
||||
|
||||
export const NoPlainErrorsRule = ESLintUtils.RuleCreator.withoutDocs({
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'Only `ApplicationError` (from the `workflow` package) or its child classes must be thrown. This ensures the error will be normalized when reported to Sentry, if applicable.',
|
||||
},
|
||||
messages: {
|
||||
useApplicationError:
|
||||
'Throw an `ApplicationError` (from the `workflow` package) or its child classes.',
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [],
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
return {
|
||||
ThrowStatement(node) {
|
||||
if (!node.argument) return;
|
||||
|
||||
const isNewError =
|
||||
node.argument.type === TSESTree.AST_NODE_TYPES.NewExpression &&
|
||||
node.argument.callee.type === TSESTree.AST_NODE_TYPES.Identifier &&
|
||||
node.argument.callee.name === 'Error';
|
||||
|
||||
const isNewlessError =
|
||||
node.argument.type === TSESTree.AST_NODE_TYPES.CallExpression &&
|
||||
node.argument.callee.type === TSESTree.AST_NODE_TYPES.Identifier &&
|
||||
node.argument.callee.name === 'Error';
|
||||
|
||||
if (isNewError || isNewlessError) {
|
||||
return context.report({
|
||||
messageId: 'useApplicationError',
|
||||
node,
|
||||
fix: (fixer) =>
|
||||
fixer.replaceText(
|
||||
node,
|
||||
`throw new ApplicationError(${(node.argument as TSESTree.CallExpression).arguments
|
||||
.map((arg) => context.sourceCode.getText(arg))
|
||||
.join(', ')})`,
|
||||
),
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
57
packages/@n8n/eslint-config/src/rules/no-skipped-tests.ts
Normal file
57
packages/@n8n/eslint-config/src/rules/no-skipped-tests.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { ESLintUtils } from '@typescript-eslint/utils';
|
||||
|
||||
export const NoSkippedTestsRule = ESLintUtils.RuleCreator.withoutDocs({
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Tests must not be skipped.',
|
||||
},
|
||||
messages: {
|
||||
removeSkip: 'Remove `.skip()` call',
|
||||
removeOnly: 'Remove `.only()` call',
|
||||
removeXPrefix: 'Remove `x` prefix',
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [],
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
const TESTING_FUNCTIONS = new Set(['test', 'it', 'describe']);
|
||||
const SKIPPING_METHODS = new Set(['skip', 'only']);
|
||||
const PREFIXED_TESTING_FUNCTIONS = new Set(['xtest', 'xit', 'xdescribe']);
|
||||
const toMessageId = (s: string) =>
|
||||
('remove' + s.charAt(0).toUpperCase() + s.slice(1)) as
|
||||
| 'removeSkip'
|
||||
| 'removeOnly'
|
||||
| 'removeXPrefix';
|
||||
|
||||
return {
|
||||
MemberExpression(node) {
|
||||
if (
|
||||
node.object.type === 'Identifier' &&
|
||||
TESTING_FUNCTIONS.has(node.object.name) &&
|
||||
node.property.type === 'Identifier' &&
|
||||
SKIPPING_METHODS.has(node.property.name)
|
||||
) {
|
||||
context.report({
|
||||
messageId: toMessageId(node.property.name),
|
||||
node,
|
||||
fix: (fixer) => {
|
||||
const [start, end] = node.property.range;
|
||||
return fixer.removeRange([start - '.'.length, end]);
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
CallExpression(node) {
|
||||
if (node.callee.type === 'Identifier' && PREFIXED_TESTING_FUNCTIONS.has(node.callee.name)) {
|
||||
context.report({
|
||||
messageId: 'removeXPrefix',
|
||||
node,
|
||||
fix: (fixer) => fixer.replaceText(node.callee, 'test'),
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
import { ESLintUtils } from '@typescript-eslint/utils';
|
||||
|
||||
export const NoTypeUnsafeEventEmitterRule = ESLintUtils.RuleCreator.withoutDocs({
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Disallow extending from `EventEmitter`, which is not type-safe.',
|
||||
},
|
||||
messages: {
|
||||
noExtendsEventEmitter: 'Extend from the type-safe `TypedEmitter` class instead.',
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
return {
|
||||
ClassDeclaration(node) {
|
||||
if (
|
||||
node.superClass &&
|
||||
node.superClass.type === 'Identifier' &&
|
||||
node.superClass.name === 'EventEmitter' &&
|
||||
node.id?.name !== 'TypedEmitter'
|
||||
) {
|
||||
context.report({
|
||||
node: node.superClass,
|
||||
messageId: 'noExtendsEventEmitter',
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
import { RuleTester } from '@typescript-eslint/rule-tester';
|
||||
import { NoUncaughtJsonParseRule } from './no-uncaught-json-parse.js';
|
||||
|
||||
const ruleTester = new RuleTester();
|
||||
|
||||
ruleTester.run('no-uncaught-json-parse', NoUncaughtJsonParseRule, {
|
||||
valid: [
|
||||
{
|
||||
code: 'try { JSON.parse(foo) } catch (e) {}',
|
||||
},
|
||||
{
|
||||
code: 'JSON.parse(JSON.stringify(foo))',
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
code: 'JSON.parse(foo)',
|
||||
errors: [{ messageId: 'noUncaughtJsonParse' }],
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,44 @@
|
||||
import { ESLintUtils } from '@typescript-eslint/utils';
|
||||
import { isJsonParseCall, isJsonStringifyCall } from '../utils/json.js';
|
||||
|
||||
export const NoUncaughtJsonParseRule = ESLintUtils.RuleCreator.withoutDocs({
|
||||
meta: {
|
||||
type: 'problem',
|
||||
hasSuggestions: true,
|
||||
docs: {
|
||||
description:
|
||||
'Calls to `JSON.parse()` must be replaced with `jsonParse()` from `n8n-workflow` or surrounded with a try/catch block.',
|
||||
},
|
||||
schema: [],
|
||||
messages: {
|
||||
noUncaughtJsonParse:
|
||||
'Use `jsonParse()` from `n8n-workflow` or surround the `JSON.parse()` call with a try/catch block.',
|
||||
},
|
||||
},
|
||||
defaultOptions: [],
|
||||
create({ report, sourceCode }) {
|
||||
return {
|
||||
CallExpression(node) {
|
||||
if (!isJsonParseCall(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isJsonStringifyCall(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
sourceCode.getAncestors(node).find((node) => node.type === 'TryStatement') !== undefined
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Found a JSON.parse() call not wrapped into a try/catch, so report it
|
||||
report({
|
||||
messageId: 'noUncaughtJsonParse',
|
||||
node,
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
import { ESLintUtils } from '@typescript-eslint/utils';
|
||||
|
||||
export const NoUnneededBackticksRule = ESLintUtils.RuleCreator.withoutDocs({
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description:
|
||||
'Template literal backticks may only be used for string interpolation or multiline strings.',
|
||||
},
|
||||
messages: {
|
||||
noUnneededBackticks: 'Use single or double quotes, not backticks',
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [],
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
return {
|
||||
TemplateLiteral(node) {
|
||||
if (node.expressions.length > 0) return;
|
||||
if (node.quasis.every((q) => q.loc.start.line !== q.loc.end.line)) return;
|
||||
|
||||
node.quasis.forEach((q) => {
|
||||
const escaped = q.value.raw.replace(/(?<!\\)'/g, "\\'");
|
||||
|
||||
context.report({
|
||||
messageId: 'noUnneededBackticks',
|
||||
node,
|
||||
fix: (fixer) => fixer.replaceText(q, `'${escaped}'`),
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
import { ESLintUtils } from '@typescript-eslint/utils';
|
||||
|
||||
export const NoUntypedConfigClassFieldRule = ESLintUtils.RuleCreator.withoutDocs({
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Enforce explicit typing of config class fields',
|
||||
},
|
||||
messages: {
|
||||
noUntypedConfigClassField:
|
||||
'Class field must have an explicit type annotation, e.g. `field: type = value`. See: https://github.com/n8n-io/n8n/pull/10433',
|
||||
},
|
||||
schema: [],
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
return {
|
||||
PropertyDefinition(node) {
|
||||
if (!node.typeAnnotation) {
|
||||
context.report({ node: node.key, messageId: 'noUntypedConfigClassField' });
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
import { ESLintUtils } from '@typescript-eslint/utils';
|
||||
|
||||
export const NoUnusedParamInCatchClauseRule = ESLintUtils.RuleCreator.withoutDocs({
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Unused param in catch clause must be omitted.',
|
||||
},
|
||||
messages: {
|
||||
removeUnusedParam: 'Remove unused param in catch clause',
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [],
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
return {
|
||||
CatchClause(node) {
|
||||
if (node.param?.type === 'Identifier' && node.param.name.startsWith('_')) {
|
||||
const start = node.range[0] + 'catch '.length;
|
||||
const end = node.param.range[1] + '()'.length;
|
||||
|
||||
context.report({
|
||||
messageId: 'removeUnusedParam',
|
||||
node,
|
||||
fix: (fixer) => fixer.removeRange([start, end]),
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
import { RuleTester } from '@typescript-eslint/rule-tester';
|
||||
import { NoUselessCatchThrowRule } from './no-useless-catch-throw.js';
|
||||
|
||||
const ruleTester = new RuleTester();
|
||||
|
||||
ruleTester.run('no-useless-catch-throw', NoUselessCatchThrowRule, {
|
||||
valid: [
|
||||
{
|
||||
code: 'try { foo(); } catch (e) { console.error(e); }',
|
||||
},
|
||||
{
|
||||
code: 'try { foo(); } catch (e) { throw new Error("Custom error"); }',
|
||||
},
|
||||
],
|
||||
invalid: [
|
||||
{
|
||||
code: `
|
||||
try {
|
||||
// Some comment
|
||||
if (foo) {
|
||||
bar();
|
||||
}
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}`,
|
||||
errors: [{ messageId: 'noUselessCatchThrow' }],
|
||||
output: `
|
||||
// Some comment
|
||||
if (foo) {
|
||||
bar();
|
||||
}`,
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
import { ESLintUtils } from '@typescript-eslint/utils';
|
||||
|
||||
export const NoUselessCatchThrowRule = ESLintUtils.RuleCreator.withoutDocs({
|
||||
meta: {
|
||||
type: 'problem',
|
||||
docs: {
|
||||
description: 'Disallow `try-catch` blocks where the `catch` only contains a `throw error`.',
|
||||
},
|
||||
messages: {
|
||||
noUselessCatchThrow: 'Remove useless `catch` block.',
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [],
|
||||
},
|
||||
defaultOptions: [],
|
||||
create(context) {
|
||||
return {
|
||||
CatchClause(node) {
|
||||
if (
|
||||
node.body.body.length === 1 &&
|
||||
node.body.body[0].type === 'ThrowStatement' &&
|
||||
node.body.body[0].argument.type === 'Identifier' &&
|
||||
node.param?.type === 'Identifier' &&
|
||||
node.body.body[0].argument.name === node.param.name
|
||||
) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'noUselessCatchThrow',
|
||||
fix(fixer) {
|
||||
const tryStatement = node.parent;
|
||||
const tryBlock = tryStatement.block;
|
||||
const sourceCode = context.sourceCode;
|
||||
const tryBlockText = sourceCode.getText(tryBlock);
|
||||
const tryBlockTextWithoutBraces = tryBlockText.slice(1, -1).trim();
|
||||
const indentedTryBlockText = tryBlockTextWithoutBraces
|
||||
.split('\n')
|
||||
.map((line) => line.replace(/\t/, ''))
|
||||
.join('\n');
|
||||
return fixer.replaceText(tryStatement, indentedTryBlockText);
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
21
packages/@n8n/eslint-config/src/utils/json.ts
Normal file
21
packages/@n8n/eslint-config/src/utils/json.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import type { TSESTree } from '@typescript-eslint/utils';
|
||||
|
||||
export const isJsonParseCall = (node: TSESTree.CallExpression) =>
|
||||
node.callee.type === 'MemberExpression' &&
|
||||
node.callee.object.type === 'Identifier' &&
|
||||
node.callee.object.name === 'JSON' &&
|
||||
node.callee.property.type === 'Identifier' &&
|
||||
node.callee.property.name === 'parse';
|
||||
|
||||
export const isJsonStringifyCall = (node: TSESTree.CallExpression) => {
|
||||
const parseArg = node.arguments?.[0];
|
||||
return (
|
||||
parseArg !== undefined &&
|
||||
parseArg.type === 'CallExpression' &&
|
||||
parseArg.callee.type === 'MemberExpression' &&
|
||||
parseArg.callee.object.type === 'Identifier' &&
|
||||
parseArg.callee.object.name === 'JSON' &&
|
||||
parseArg.callee.property.type === 'Identifier' &&
|
||||
parseArg.callee.property.name === 'stringify'
|
||||
);
|
||||
};
|
||||
13
packages/@n8n/eslint-config/tsconfig.json
Normal file
13
packages/@n8n/eslint-config/tsconfig.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"extends": "@n8n/typescript-config/tsconfig.common.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"rootDir": "src",
|
||||
"outDir": "dist",
|
||||
"types": ["vitest/globals"],
|
||||
"esModuleInterop": true,
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "nodenext"
|
||||
},
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
4
packages/@n8n/eslint-config/vite.config.ts
Normal file
4
packages/@n8n/eslint-config/vite.config.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { defineConfig, mergeConfig } from 'vite';
|
||||
import { vitestConfig } from '@n8n/vitest-config/node';
|
||||
|
||||
export default mergeConfig(defineConfig({}), vitestConfig);
|
||||
14
packages/@n8n/extension-sdk/eslint.config.mjs
Normal file
14
packages/@n8n/extension-sdk/eslint.config.mjs
Normal file
@@ -0,0 +1,14 @@
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import { baseConfig } from '@n8n/eslint-config/base';
|
||||
|
||||
export default defineConfig(baseConfig, {
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
|
||||
// TODO: Remove this
|
||||
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 'warn',
|
||||
'@typescript-eslint/prefer-nullish-coalescing': 'warn',
|
||||
'@typescript-eslint/no-floating-promises': 'warn',
|
||||
'import-x/order': 'warn',
|
||||
},
|
||||
});
|
||||
@@ -32,6 +32,7 @@
|
||||
"scripts": {
|
||||
"clean": "rimraf dist",
|
||||
"dev": "tsup --watch",
|
||||
"lint": "eslint . --quiet",
|
||||
"typecheck:frontend": "vue-tsc --noEmit --project tsconfig.frontend.json",
|
||||
"typecheck:backend": "tsc --noEmit --project tsconfig.backend.json",
|
||||
"build": "pnpm \"/^typecheck:.+/\" && pnpm clean && tsup && pnpm create-json-schema",
|
||||
@@ -47,7 +48,7 @@
|
||||
"@vitejs/plugin-vue": "catalog:frontend",
|
||||
"@vue/tsconfig": "catalog:frontend",
|
||||
"rimraf": "catalog:",
|
||||
"vite": "catalog:frontend",
|
||||
"vite": "catalog:",
|
||||
"vue": "catalog:frontend",
|
||||
"vue-router": "catalog:frontend",
|
||||
"vue-tsc": "catalog:frontend",
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
const sharedOptions = require('@n8n/eslint-config/shared');
|
||||
|
||||
/**
|
||||
* @type {import('@types/eslint').ESLint.ConfigData}
|
||||
*/
|
||||
module.exports = {
|
||||
extends: ['@n8n/eslint-config/base'],
|
||||
|
||||
...sharedOptions(__dirname),
|
||||
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
'n8n-local-rules/no-plain-errors': 'off',
|
||||
},
|
||||
};
|
||||
16
packages/@n8n/imap/eslint.config.mjs
Normal file
16
packages/@n8n/imap/eslint.config.mjs
Normal file
@@ -0,0 +1,16 @@
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import { baseConfig } from '@n8n/eslint-config/base';
|
||||
|
||||
export default defineConfig(baseConfig, {
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
'@typescript-eslint/consistent-type-imports': 'error',
|
||||
'n8n-local-rules/no-plain-errors': 'off',
|
||||
|
||||
// TODO: Remove this
|
||||
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 'warn',
|
||||
'@typescript-eslint/prefer-nullish-coalescing': 'warn',
|
||||
'@typescript-eslint/no-floating-promises': 'warn',
|
||||
'import-x/order': 'warn',
|
||||
},
|
||||
});
|
||||
@@ -1,21 +0,0 @@
|
||||
const sharedOptions = require('@n8n/eslint-config/shared');
|
||||
|
||||
/**
|
||||
* @type {import('@types/eslint').ESLint.ConfigData}
|
||||
*/
|
||||
module.exports = {
|
||||
extends: ['@n8n/eslint-config/node'],
|
||||
|
||||
...sharedOptions(__dirname),
|
||||
|
||||
ignorePatterns: ['jest.config.js'],
|
||||
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
'@typescript-eslint/no-duplicate-imports': 'off',
|
||||
'import/no-cycle': 'off',
|
||||
'n8n-local-rules/no-plain-errors': 'off',
|
||||
|
||||
complexity: 'error',
|
||||
},
|
||||
};
|
||||
26
packages/@n8n/json-schema-to-zod/eslint.config.mjs
Normal file
26
packages/@n8n/json-schema-to-zod/eslint.config.mjs
Normal file
@@ -0,0 +1,26 @@
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import { nodeConfig } from '@n8n/eslint-config/node';
|
||||
|
||||
export default defineConfig(
|
||||
nodeConfig,
|
||||
{
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
'@typescript-eslint/no-duplicate-imports': 'off',
|
||||
'import-x/no-cycle': 'off',
|
||||
complexity: 'error',
|
||||
|
||||
// TODO: Remove this
|
||||
'no-constant-condition': 'warn',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.test.ts'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-unused-expressions': 'warn',
|
||||
'@typescript-eslint/naming-convention': 'warn',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'warn',
|
||||
'@typescript-eslint/ban-ts-comment': ['warn', { 'ts-ignore': true }],
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -21,11 +21,11 @@
|
||||
"dev": "tsc -w",
|
||||
"format": "biome format --write src",
|
||||
"format:check": "biome ci src",
|
||||
"lint": "eslint . --quiet",
|
||||
"lintfix": "eslint . --fix",
|
||||
"lint": "eslint src --quiet",
|
||||
"lintfix": "eslint src --fix",
|
||||
"build:types": "tsc -p tsconfig.types.json",
|
||||
"build:cjs": "tsc -p tsconfig.cjs.json && node postcjs.js",
|
||||
"build:esm": "tsc -p tsconfig.esm.json && node postesm.js",
|
||||
"build:cjs": "tsc -p tsconfig.cjs.json && node postcjs.cjs",
|
||||
"build:esm": "tsc -p tsconfig.esm.json && node postesm.cjs",
|
||||
"build": "rimraf ./dist && pnpm run build:types && pnpm run build:cjs && pnpm run build:esm",
|
||||
"dry": "pnpm run build && pnpm pub --dry-run",
|
||||
"test": "jest",
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
const sharedOptions = require('@n8n/eslint-config/shared');
|
||||
|
||||
/**
|
||||
* @type {import('@types/eslint').ESLint.ConfigData}
|
||||
*/
|
||||
module.exports = {
|
||||
extends: ['@n8n/eslint-config/node'],
|
||||
|
||||
...sharedOptions(__dirname),
|
||||
|
||||
ignorePatterns: ['index.js', '**/package.json'],
|
||||
|
||||
rules: {
|
||||
// TODO: remove all the following rules
|
||||
eqeqeq: 'warn',
|
||||
'id-denylist': 'warn',
|
||||
'import/extensions': 'warn',
|
||||
'prefer-spread': 'warn',
|
||||
|
||||
'@typescript-eslint/naming-convention': ['error', { selector: 'memberLike', format: null }],
|
||||
'@typescript-eslint/no-explicit-any': 'warn', //812 warnings, better to fix in separate PR
|
||||
'@typescript-eslint/no-non-null-assertion': 'warn', //665 errors, better to fix in separate PR
|
||||
'@typescript-eslint/no-unsafe-assignment': 'warn', //7084 problems, better to fix in separate PR
|
||||
'@typescript-eslint/no-unsafe-call': 'warn', //541 errors, better to fix in separate PR
|
||||
'@typescript-eslint/no-unsafe-member-access': 'warn', //4591 errors, better to fix in separate PR
|
||||
'@typescript-eslint/no-unsafe-return': 'warn', //438 errors, better to fix in separate PR
|
||||
'@typescript-eslint/no-unused-expressions': ['error', { allowTernary: true }],
|
||||
'@typescript-eslint/restrict-template-expressions': 'warn', //1152 errors, better to fix in separate PR
|
||||
'@typescript-eslint/unbound-method': 'warn',
|
||||
'@typescript-eslint/ban-ts-comment': ['warn', { 'ts-ignore': true }],
|
||||
'@typescript-eslint/prefer-nullish-coalescing': 'warn',
|
||||
'@typescript-eslint/no-base-to-string': 'warn',
|
||||
'@typescript-eslint/no-redundant-type-constituents': 'warn',
|
||||
'@typescript-eslint/no-unsafe-argument': 'warn',
|
||||
'@typescript-eslint/prefer-optional-chain': 'warn',
|
||||
'@typescript-eslint/restrict-plus-operands': 'warn',
|
||||
},
|
||||
|
||||
overrides: [
|
||||
{
|
||||
files: ['./credentials/*.ts'],
|
||||
plugins: ['eslint-plugin-n8n-nodes-base'],
|
||||
rules: {
|
||||
'n8n-nodes-base/cred-class-field-authenticate-type-assertion': 'error',
|
||||
'n8n-nodes-base/cred-class-field-display-name-missing-oauth2': 'error',
|
||||
'n8n-nodes-base/cred-class-field-display-name-miscased': 'error',
|
||||
'n8n-nodes-base/cred-class-field-documentation-url-missing': 'error',
|
||||
'n8n-nodes-base/cred-class-field-name-missing-oauth2': 'error',
|
||||
'n8n-nodes-base/cred-class-field-name-unsuffixed': 'error',
|
||||
'n8n-nodes-base/cred-class-field-name-uppercase-first-char': 'error',
|
||||
'n8n-nodes-base/cred-class-field-properties-assertion': 'error',
|
||||
'n8n-nodes-base/cred-class-field-type-options-password-missing': 'error',
|
||||
'n8n-nodes-base/cred-class-name-missing-oauth2-suffix': 'error',
|
||||
'n8n-nodes-base/cred-class-name-unsuffixed': 'error',
|
||||
'n8n-nodes-base/cred-filename-against-convention': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['./nodes/**/*.ts'],
|
||||
plugins: ['eslint-plugin-n8n-nodes-base'],
|
||||
rules: {
|
||||
'n8n-nodes-base/node-class-description-credentials-name-unsuffixed': 'error',
|
||||
'n8n-nodes-base/node-class-description-display-name-unsuffixed-trigger-node': 'error',
|
||||
'n8n-nodes-base/node-class-description-empty-string': 'error',
|
||||
'n8n-nodes-base/node-class-description-icon-not-svg': 'error',
|
||||
'n8n-nodes-base/node-class-description-inputs-wrong-regular-node': 'off',
|
||||
'n8n-nodes-base/node-class-description-outputs-wrong': 'off',
|
||||
'n8n-nodes-base/node-class-description-inputs-wrong-trigger-node': 'error',
|
||||
'n8n-nodes-base/node-class-description-missing-subtitle': 'error',
|
||||
'n8n-nodes-base/node-class-description-non-core-color-present': 'error',
|
||||
'n8n-nodes-base/node-class-description-name-miscased': 'error',
|
||||
'n8n-nodes-base/node-class-description-name-unsuffixed-trigger-node': 'error',
|
||||
'n8n-nodes-base/node-dirname-against-convention': 'error',
|
||||
'n8n-nodes-base/node-execute-block-double-assertion-for-items': 'error',
|
||||
'n8n-nodes-base/node-execute-block-wrong-error-thrown': 'error',
|
||||
'n8n-nodes-base/node-filename-against-convention': 'error',
|
||||
'n8n-nodes-base/node-param-array-type-assertion': 'error',
|
||||
'n8n-nodes-base/node-param-color-type-unused': 'error',
|
||||
'n8n-nodes-base/node-param-default-missing': 'error',
|
||||
'n8n-nodes-base/node-param-default-wrong-for-boolean': 'error',
|
||||
'n8n-nodes-base/node-param-default-wrong-for-collection': 'error',
|
||||
'n8n-nodes-base/node-param-default-wrong-for-fixed-collection': 'error',
|
||||
'n8n-nodes-base/node-param-default-wrong-for-fixed-collection': 'error',
|
||||
'n8n-nodes-base/node-param-default-wrong-for-multi-options': 'error',
|
||||
'n8n-nodes-base/node-param-default-wrong-for-number': 'error',
|
||||
'n8n-nodes-base/node-param-default-wrong-for-simplify': 'error',
|
||||
'n8n-nodes-base/node-param-default-wrong-for-string': 'error',
|
||||
'n8n-nodes-base/node-param-description-boolean-without-whether': 'error',
|
||||
'n8n-nodes-base/node-param-description-comma-separated-hyphen': 'error',
|
||||
'n8n-nodes-base/node-param-description-empty-string': 'error',
|
||||
'n8n-nodes-base/node-param-description-excess-final-period': 'error',
|
||||
'n8n-nodes-base/node-param-description-excess-inner-whitespace': 'error',
|
||||
'n8n-nodes-base/node-param-description-identical-to-display-name': 'error',
|
||||
'n8n-nodes-base/node-param-description-line-break-html-tag': 'error',
|
||||
'n8n-nodes-base/node-param-description-lowercase-first-char': 'error',
|
||||
'n8n-nodes-base/node-param-description-miscased-id': 'error',
|
||||
'n8n-nodes-base/node-param-description-miscased-json': 'error',
|
||||
'n8n-nodes-base/node-param-description-miscased-url': 'error',
|
||||
'n8n-nodes-base/node-param-description-missing-final-period': 'error',
|
||||
'n8n-nodes-base/node-param-description-missing-for-ignore-ssl-issues': 'error',
|
||||
'n8n-nodes-base/node-param-description-missing-for-return-all': 'error',
|
||||
'n8n-nodes-base/node-param-description-missing-for-simplify': 'error',
|
||||
'n8n-nodes-base/node-param-description-missing-from-dynamic-multi-options': 'error',
|
||||
'n8n-nodes-base/node-param-description-missing-from-dynamic-options': 'error',
|
||||
'n8n-nodes-base/node-param-description-missing-from-limit': 'error',
|
||||
'n8n-nodes-base/node-param-description-unencoded-angle-brackets': 'error',
|
||||
'n8n-nodes-base/node-param-description-unneeded-backticks': 'error',
|
||||
'n8n-nodes-base/node-param-description-untrimmed': 'error',
|
||||
'n8n-nodes-base/node-param-description-url-missing-protocol': 'error',
|
||||
'n8n-nodes-base/node-param-description-weak': 'error',
|
||||
'n8n-nodes-base/node-param-description-wrong-for-dynamic-multi-options': 'error',
|
||||
'n8n-nodes-base/node-param-description-wrong-for-dynamic-options': 'error',
|
||||
'n8n-nodes-base/node-param-description-wrong-for-ignore-ssl-issues': 'error',
|
||||
'n8n-nodes-base/node-param-description-wrong-for-limit': 'error',
|
||||
'n8n-nodes-base/node-param-description-wrong-for-return-all': 'error',
|
||||
'n8n-nodes-base/node-param-description-wrong-for-simplify': 'error',
|
||||
'n8n-nodes-base/node-param-description-wrong-for-upsert': 'error',
|
||||
'n8n-nodes-base/node-param-display-name-excess-inner-whitespace': 'error',
|
||||
'n8n-nodes-base/node-param-display-name-miscased-id': 'error',
|
||||
'n8n-nodes-base/node-param-display-name-miscased': 'error',
|
||||
'n8n-nodes-base/node-param-display-name-not-first-position': 'error',
|
||||
'n8n-nodes-base/node-param-display-name-untrimmed': 'error',
|
||||
'n8n-nodes-base/node-param-display-name-wrong-for-dynamic-multi-options': 'error',
|
||||
'n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options': 'error',
|
||||
'n8n-nodes-base/node-param-display-name-wrong-for-simplify': 'error',
|
||||
'n8n-nodes-base/node-param-display-name-wrong-for-update-fields': 'error',
|
||||
'n8n-nodes-base/node-param-min-value-wrong-for-limit': 'error',
|
||||
'n8n-nodes-base/node-param-multi-options-type-unsorted-items': 'error',
|
||||
'n8n-nodes-base/node-param-name-untrimmed': 'error',
|
||||
'n8n-nodes-base/node-param-operation-option-action-wrong-for-get-many': 'error',
|
||||
'n8n-nodes-base/node-param-operation-option-description-wrong-for-get-many': 'error',
|
||||
'n8n-nodes-base/node-param-operation-option-without-action': 'error',
|
||||
'n8n-nodes-base/node-param-operation-without-no-data-expression': 'error',
|
||||
'n8n-nodes-base/node-param-option-description-identical-to-name': 'error',
|
||||
'n8n-nodes-base/node-param-option-name-containing-star': 'error',
|
||||
'n8n-nodes-base/node-param-option-name-duplicate': 'error',
|
||||
'n8n-nodes-base/node-param-option-name-wrong-for-get-many': 'error',
|
||||
'n8n-nodes-base/node-param-option-name-wrong-for-upsert': 'error',
|
||||
'n8n-nodes-base/node-param-option-value-duplicate': 'error',
|
||||
'n8n-nodes-base/node-param-options-type-unsorted-items': 'error',
|
||||
'n8n-nodes-base/node-param-placeholder-miscased-id': 'error',
|
||||
'n8n-nodes-base/node-param-placeholder-missing-email': 'error',
|
||||
'n8n-nodes-base/node-param-required-false': 'error',
|
||||
'n8n-nodes-base/node-param-resource-with-plural-option': 'error',
|
||||
'n8n-nodes-base/node-param-resource-without-no-data-expression': 'error',
|
||||
'n8n-nodes-base/node-param-type-options-missing-from-limit': 'error',
|
||||
'n8n-nodes-base/node-param-type-options-password-missing': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.test.ts', '**/test/**/*.ts'],
|
||||
rules: {
|
||||
'import/no-extraneous-dependencies': 'off',
|
||||
'n8n-nodes-base/node-filename-against-convention': 'off',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
164
packages/@n8n/nodes-langchain/eslint.config.mjs
Normal file
164
packages/@n8n/nodes-langchain/eslint.config.mjs
Normal file
@@ -0,0 +1,164 @@
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import { nodeConfig } from '@n8n/eslint-config/node';
|
||||
import nodesBasePlugin from 'eslint-plugin-n8n-nodes-base';
|
||||
|
||||
export default defineConfig(
|
||||
nodeConfig,
|
||||
{
|
||||
rules: {
|
||||
// TODO: remove all the following rules
|
||||
eqeqeq: 'warn',
|
||||
'id-denylist': 'warn',
|
||||
'import-x/extensions': 'warn',
|
||||
'prefer-spread': 'warn',
|
||||
'no-case-declarations': 'warn',
|
||||
'no-extra-boolean-cast': 'warn',
|
||||
'no-empty': 'warn',
|
||||
'no-prototype-builtins': 'warn',
|
||||
'import-x/order': 'warn',
|
||||
'@typescript-eslint/no-unnecessary-type-assertion': 'warn',
|
||||
'no-async-promise-executor': 'warn',
|
||||
'no-useless-escape': 'warn',
|
||||
|
||||
'@typescript-eslint/naming-convention': ['error', { selector: 'memberLike', format: null }],
|
||||
'@typescript-eslint/no-explicit-any': 'warn', //812 warnings, better to fix in separate PR
|
||||
'@typescript-eslint/no-non-null-assertion': 'warn', //665 errors, better to fix in separate PR
|
||||
'@typescript-eslint/no-unsafe-assignment': 'warn', //7084 problems, better to fix in separate PR
|
||||
'@typescript-eslint/no-unsafe-call': 'warn', //541 errors, better to fix in separate PR
|
||||
'@typescript-eslint/no-unsafe-member-access': 'warn', //4591 errors, better to fix in separate PR
|
||||
'@typescript-eslint/no-unsafe-return': 'warn', //438 errors, better to fix in separate PR
|
||||
'@typescript-eslint/no-unused-expressions': ['error', { allowTernary: true }],
|
||||
'@typescript-eslint/restrict-template-expressions': 'warn', //1152 errors, better to fix in separate PR
|
||||
'@typescript-eslint/unbound-method': 'warn',
|
||||
'@typescript-eslint/prefer-nullish-coalescing': 'warn',
|
||||
'@typescript-eslint/no-base-to-string': 'warn',
|
||||
'@typescript-eslint/no-redundant-type-constituents': 'warn',
|
||||
'@typescript-eslint/no-unsafe-argument': 'warn',
|
||||
'@typescript-eslint/prefer-optional-chain': 'warn',
|
||||
'@typescript-eslint/restrict-plus-operands': 'warn',
|
||||
'@typescript-eslint/no-duplicate-type-constituents': 'warn',
|
||||
'@typescript-eslint/require-await': 'warn',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['./credentials/*.ts'],
|
||||
plugins: {
|
||||
'n8n-nodes-base': nodesBasePlugin,
|
||||
},
|
||||
rules: {
|
||||
'n8n-nodes-base/cred-class-field-authenticate-type-assertion': 'error',
|
||||
'n8n-nodes-base/cred-class-field-display-name-missing-oauth2': 'error',
|
||||
'n8n-nodes-base/cred-class-field-display-name-miscased': 'error',
|
||||
'n8n-nodes-base/cred-class-field-documentation-url-missing': 'error',
|
||||
'n8n-nodes-base/cred-class-field-name-missing-oauth2': 'error',
|
||||
'n8n-nodes-base/cred-class-field-name-unsuffixed': 'error',
|
||||
'n8n-nodes-base/cred-class-field-name-uppercase-first-char': 'error',
|
||||
'n8n-nodes-base/cred-class-field-properties-assertion': 'error',
|
||||
'n8n-nodes-base/cred-class-field-type-options-password-missing': 'error',
|
||||
'n8n-nodes-base/cred-class-name-missing-oauth2-suffix': 'error',
|
||||
'n8n-nodes-base/cred-class-name-unsuffixed': 'error',
|
||||
'n8n-nodes-base/cred-filename-against-convention': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['./nodes/**/*.ts'],
|
||||
plugins: {
|
||||
'n8n-nodes-base': nodesBasePlugin,
|
||||
},
|
||||
rules: {
|
||||
'n8n-nodes-base/node-class-description-credentials-name-unsuffixed': 'error',
|
||||
'n8n-nodes-base/node-class-description-display-name-unsuffixed-trigger-node': 'error',
|
||||
'n8n-nodes-base/node-class-description-empty-string': 'error',
|
||||
'n8n-nodes-base/node-class-description-icon-not-svg': 'error',
|
||||
'n8n-nodes-base/node-class-description-inputs-wrong-regular-node': 'off',
|
||||
'n8n-nodes-base/node-class-description-outputs-wrong': 'off',
|
||||
'n8n-nodes-base/node-class-description-inputs-wrong-trigger-node': 'error',
|
||||
'n8n-nodes-base/node-class-description-missing-subtitle': 'error',
|
||||
'n8n-nodes-base/node-class-description-non-core-color-present': 'error',
|
||||
'n8n-nodes-base/node-class-description-name-miscased': 'error',
|
||||
'n8n-nodes-base/node-class-description-name-unsuffixed-trigger-node': 'error',
|
||||
'n8n-nodes-base/node-dirname-against-convention': 'error',
|
||||
'n8n-nodes-base/node-execute-block-double-assertion-for-items': 'error',
|
||||
'n8n-nodes-base/node-execute-block-wrong-error-thrown': 'error',
|
||||
'n8n-nodes-base/node-filename-against-convention': 'error',
|
||||
'n8n-nodes-base/node-param-array-type-assertion': 'error',
|
||||
'n8n-nodes-base/node-param-color-type-unused': 'error',
|
||||
'n8n-nodes-base/node-param-default-missing': 'error',
|
||||
'n8n-nodes-base/node-param-default-wrong-for-boolean': 'error',
|
||||
'n8n-nodes-base/node-param-default-wrong-for-collection': 'error',
|
||||
'n8n-nodes-base/node-param-default-wrong-for-fixed-collection': 'error',
|
||||
'n8n-nodes-base/node-param-default-wrong-for-fixed-collection': 'error',
|
||||
'n8n-nodes-base/node-param-default-wrong-for-multi-options': 'error',
|
||||
'n8n-nodes-base/node-param-default-wrong-for-number': 'error',
|
||||
'n8n-nodes-base/node-param-default-wrong-for-simplify': 'error',
|
||||
'n8n-nodes-base/node-param-default-wrong-for-string': 'error',
|
||||
'n8n-nodes-base/node-param-description-boolean-without-whether': 'error',
|
||||
'n8n-nodes-base/node-param-description-comma-separated-hyphen': 'error',
|
||||
'n8n-nodes-base/node-param-description-empty-string': 'error',
|
||||
'n8n-nodes-base/node-param-description-excess-final-period': 'error',
|
||||
'n8n-nodes-base/node-param-description-excess-inner-whitespace': 'error',
|
||||
'n8n-nodes-base/node-param-description-identical-to-display-name': 'error',
|
||||
'n8n-nodes-base/node-param-description-line-break-html-tag': 'error',
|
||||
'n8n-nodes-base/node-param-description-lowercase-first-char': 'error',
|
||||
'n8n-nodes-base/node-param-description-miscased-id': 'error',
|
||||
'n8n-nodes-base/node-param-description-miscased-json': 'error',
|
||||
'n8n-nodes-base/node-param-description-miscased-url': 'error',
|
||||
'n8n-nodes-base/node-param-description-missing-final-period': 'error',
|
||||
'n8n-nodes-base/node-param-description-missing-for-ignore-ssl-issues': 'error',
|
||||
'n8n-nodes-base/node-param-description-missing-for-return-all': 'error',
|
||||
'n8n-nodes-base/node-param-description-missing-for-simplify': 'error',
|
||||
'n8n-nodes-base/node-param-description-missing-from-dynamic-multi-options': 'error',
|
||||
'n8n-nodes-base/node-param-description-missing-from-dynamic-options': 'error',
|
||||
'n8n-nodes-base/node-param-description-missing-from-limit': 'error',
|
||||
'n8n-nodes-base/node-param-description-unencoded-angle-brackets': 'error',
|
||||
'n8n-nodes-base/node-param-description-unneeded-backticks': 'error',
|
||||
'n8n-nodes-base/node-param-description-untrimmed': 'error',
|
||||
'n8n-nodes-base/node-param-description-url-missing-protocol': 'error',
|
||||
'n8n-nodes-base/node-param-description-weak': 'error',
|
||||
'n8n-nodes-base/node-param-description-wrong-for-dynamic-multi-options': 'error',
|
||||
'n8n-nodes-base/node-param-description-wrong-for-dynamic-options': 'error',
|
||||
'n8n-nodes-base/node-param-description-wrong-for-ignore-ssl-issues': 'error',
|
||||
'n8n-nodes-base/node-param-description-wrong-for-limit': 'error',
|
||||
'n8n-nodes-base/node-param-description-wrong-for-return-all': 'error',
|
||||
'n8n-nodes-base/node-param-description-wrong-for-simplify': 'error',
|
||||
'n8n-nodes-base/node-param-description-wrong-for-upsert': 'error',
|
||||
'n8n-nodes-base/node-param-display-name-excess-inner-whitespace': 'error',
|
||||
'n8n-nodes-base/node-param-display-name-miscased-id': 'error',
|
||||
'n8n-nodes-base/node-param-display-name-miscased': 'error',
|
||||
'n8n-nodes-base/node-param-display-name-not-first-position': 'error',
|
||||
'n8n-nodes-base/node-param-display-name-untrimmed': 'error',
|
||||
'n8n-nodes-base/node-param-display-name-wrong-for-dynamic-multi-options': 'error',
|
||||
'n8n-nodes-base/node-param-display-name-wrong-for-dynamic-options': 'error',
|
||||
'n8n-nodes-base/node-param-display-name-wrong-for-simplify': 'error',
|
||||
'n8n-nodes-base/node-param-display-name-wrong-for-update-fields': 'error',
|
||||
'n8n-nodes-base/node-param-min-value-wrong-for-limit': 'error',
|
||||
'n8n-nodes-base/node-param-multi-options-type-unsorted-items': 'error',
|
||||
'n8n-nodes-base/node-param-name-untrimmed': 'error',
|
||||
'n8n-nodes-base/node-param-operation-option-action-wrong-for-get-many': 'error',
|
||||
'n8n-nodes-base/node-param-operation-option-description-wrong-for-get-many': 'error',
|
||||
'n8n-nodes-base/node-param-operation-option-without-action': 'error',
|
||||
'n8n-nodes-base/node-param-operation-without-no-data-expression': 'error',
|
||||
'n8n-nodes-base/node-param-option-description-identical-to-name': 'error',
|
||||
'n8n-nodes-base/node-param-option-name-containing-star': 'error',
|
||||
'n8n-nodes-base/node-param-option-name-duplicate': 'error',
|
||||
'n8n-nodes-base/node-param-option-name-wrong-for-get-many': 'error',
|
||||
'n8n-nodes-base/node-param-option-name-wrong-for-upsert': 'error',
|
||||
'n8n-nodes-base/node-param-option-value-duplicate': 'error',
|
||||
'n8n-nodes-base/node-param-options-type-unsorted-items': 'error',
|
||||
'n8n-nodes-base/node-param-placeholder-miscased-id': 'error',
|
||||
'n8n-nodes-base/node-param-placeholder-missing-email': 'error',
|
||||
'n8n-nodes-base/node-param-required-false': 'error',
|
||||
'n8n-nodes-base/node-param-resource-with-plural-option': 'error',
|
||||
'n8n-nodes-base/node-param-resource-without-no-data-expression': 'error',
|
||||
'n8n-nodes-base/node-param-type-options-missing-from-limit': 'error',
|
||||
'n8n-nodes-base/node-param-type-options-password-missing': 'error',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.test.ts', '**/test/**/*.ts', '**/__test__/**/*.ts', '**/__tests__/**/*.ts'],
|
||||
rules: {
|
||||
'import-x/no-extraneous-dependencies': 'warn',
|
||||
'n8n-local-rules/no-uncaught-json-parse': 'warn',
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -12,7 +12,7 @@
|
||||
"build": "tsup --tsconfig tsconfig.build.json && pnpm copy-nodes-json && tsc-alias -p tsconfig.build.json && pnpm copy-tokenizer-json && pnpm n8n-copy-static-files && pnpm n8n-generate-metadata",
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome ci .",
|
||||
"lint": "eslint nodes credentials utils --quiet",
|
||||
"lint": "eslint nodes credentials utils",
|
||||
"lintfix": "eslint nodes credentials utils --fix",
|
||||
"watch": "tsup --watch --tsconfig tsconfig.build.json --onSuccess \"pnpm copy-nodes-json && tsc-alias -p tsconfig.build.json && pnpm n8n-generate-metadata\"",
|
||||
"test": "jest",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||
import type { TiktokenEncoding } from 'js-tiktoken/lite';
|
||||
import { Tiktoken } from 'js-tiktoken/lite';
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
const sharedOptions = require('@n8n/eslint-config/shared');
|
||||
|
||||
/** @type {import('@types/eslint').ESLint.ConfigData} */
|
||||
module.exports = {
|
||||
extends: ['@n8n/eslint-config/base'],
|
||||
...sharedOptions(__dirname),
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
},
|
||||
};
|
||||
12
packages/@n8n/permissions/eslint.config.mjs
Normal file
12
packages/@n8n/permissions/eslint.config.mjs
Normal file
@@ -0,0 +1,12 @@
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import { baseConfig } from '@n8n/eslint-config/base';
|
||||
|
||||
export default defineConfig(baseConfig, {
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
|
||||
// TODO: Remove this
|
||||
'import-x/order': 'warn',
|
||||
'@typescript-eslint/naming-convention': 'warn',
|
||||
},
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
const sharedOptions = require('@n8n/eslint-config/shared');
|
||||
|
||||
/**
|
||||
* @type {import('@types/eslint').ESLint.ConfigData}
|
||||
*/
|
||||
module.exports = {
|
||||
extends: ['@n8n/eslint-config/node'],
|
||||
|
||||
...sharedOptions(__dirname),
|
||||
|
||||
ignorePatterns: ['jest.config.js'],
|
||||
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
// '@typescript-eslint/no-duplicate-imports': 'off',
|
||||
|
||||
complexity: 'error',
|
||||
},
|
||||
};
|
||||
28
packages/@n8n/task-runner/eslint.config.mjs
Normal file
28
packages/@n8n/task-runner/eslint.config.mjs
Normal file
@@ -0,0 +1,28 @@
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import { baseConfig } from '@n8n/eslint-config/base';
|
||||
|
||||
export default defineConfig(
|
||||
baseConfig,
|
||||
{
|
||||
rules: {
|
||||
'unicorn/filename-case': ['error', { case: 'kebabCase' }],
|
||||
complexity: 'error',
|
||||
|
||||
// TODO: Remove this
|
||||
'@typescript-eslint/naming-convention': 'warn',
|
||||
'@typescript-eslint/no-require-imports': 'warn',
|
||||
'@typescript-eslint/require-await': 'warn',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['**/*.test.ts'],
|
||||
rules: {
|
||||
'n8n-local-rules/no-uncaught-json-parse': 'warn',
|
||||
'import-x/no-duplicates': 'warn',
|
||||
'@typescript-eslint/unbound-method': 'warn',
|
||||
'@typescript-eslint/no-unsafe-argument': 'warn',
|
||||
'@typescript-eslint/no-unsafe-member-access': 'warn',
|
||||
'@typescript-eslint/no-unsafe-assignment': 'warn',
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -1,10 +0,0 @@
|
||||
const sharedOptions = require('@n8n/eslint-config/shared');
|
||||
|
||||
/**
|
||||
* @type {import('@types/eslint').ESLint.ConfigData}
|
||||
*/
|
||||
module.exports = {
|
||||
extends: ['@n8n/eslint-config/node'],
|
||||
|
||||
...sharedOptions(__dirname),
|
||||
};
|
||||
10
packages/@n8n/utils/eslint.config.mjs
Normal file
10
packages/@n8n/utils/eslint.config.mjs
Normal file
@@ -0,0 +1,10 @@
|
||||
import { defineConfig } from 'eslint/config';
|
||||
import { nodeConfig } from '@n8n/eslint-config/node';
|
||||
|
||||
export default defineConfig(nodeConfig, {
|
||||
rules: {
|
||||
// TODO: Remove this
|
||||
'no-prototype-builtins': 'warn',
|
||||
'@typescript-eslint/require-await': 'warn',
|
||||
},
|
||||
});
|
||||
@@ -24,8 +24,8 @@
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "vitest run",
|
||||
"test:dev": "vitest --silent=false",
|
||||
"lint": "eslint src --ext .js,.ts,.vue --quiet",
|
||||
"lintfix": "eslint src --ext .js,.ts,.vue --fix",
|
||||
"lint": "eslint src --quiet",
|
||||
"lintfix": "eslint src --fix",
|
||||
"format": "biome format --write . && prettier --write . --ignore-path ../../../.prettierignore",
|
||||
"format:check": "biome ci . && prettier --check . --ignore-path ../../../.prettierignore"
|
||||
},
|
||||
@@ -36,9 +36,9 @@
|
||||
"@testing-library/jest-dom": "catalog:frontend",
|
||||
"@testing-library/user-event": "catalog:frontend",
|
||||
"tsup": "catalog:",
|
||||
"typescript": "catalog:frontend",
|
||||
"vite": "catalog:frontend",
|
||||
"vitest": "catalog:frontend"
|
||||
"typescript": "catalog:",
|
||||
"vite": "catalog:",
|
||||
"vitest": "catalog:"
|
||||
},
|
||||
"license": "See LICENSE.md file in the root of the repository"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
export type CallbackFn = Function;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export type CallbackFn = (...args: any[]) => any;
|
||||
|
||||
type Payloads<ListenerMap> = {
|
||||
[E in keyof ListenerMap]: unknown;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user