@wise/eslint-config
Version:
A modular ESLint config used at Wise.
651 lines (650 loc) • 22.7 kB
JavaScript
import js from '@eslint/js';
import comments from '@eslint-community/eslint-plugin-eslint-comments/configs';
import stylistic from '@stylistic/eslint-plugin';
import parser from '@typescript-eslint/parser';
import functional from 'eslint-plugin-functional';
import importPlugin from 'eslint-plugin-import';
import * as regexpPlugin from 'eslint-plugin-regexp';
import unicorn from 'eslint-plugin-unicorn';
import globals from 'globals';
import tseslint from 'typescript-eslint';
import { defineConfig } from './_defineConfig.js';
export default defineConfig([
js.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.stylisticTypeChecked,
importPlugin.flatConfigs.recommended,
importPlugin.flatConfigs.typescript,
regexpPlugin.configs['flat/recommended'],
comments.recommended,
{
plugins: {
'@stylistic': stylistic,
functional,
unicorn,
},
languageOptions: {
globals: {
...globals.browser,
...globals.node,
...globals.es2024,
},
parser,
parserOptions: {
projectService: true,
},
},
settings: {
'import/resolver': {
typescript: {},
},
},
rules: {
'array-callback-return': 'error',
'no-constant-binary-expression': 'error',
'no-constructor-return': 'error',
'no-duplicate-imports': 'off',
'no-inner-declarations': 'off',
'no-new-native-nonconstructor': 'error',
'no-promise-executor-return': 'error',
'no-self-compare': 'error',
'no-template-curly-in-string': 'error',
'no-unmodified-loop-condition': 'error',
'no-unreachable-loop': 'error',
'no-unsafe-optional-chaining': [
'error',
{
disallowArithmeticOperators: true,
},
],
'no-unused-private-class-members': 'warn',
'@typescript-eslint/no-unused-vars': [
'warn',
{
destructuredArrayIgnorePattern: '^_',
ignoreRestSiblings: true,
},
],
'no-unused-vars': 'off',
'@typescript-eslint/no-use-before-define': [
'error',
{
functions: false,
variables: false,
},
],
'no-use-before-define': 'off',
'require-atomic-updates': 'error',
'use-isnan': [
'error',
{
enforceForIndexOf: true,
},
],
'valid-typeof': [
'error',
{
requireStringLiterals: true,
},
],
'block-scoped-var': 'error',
camelcase: [
'warn',
{
properties: 'never',
},
],
'consistent-return': 'off',
'default-case-last': 'error',
'@typescript-eslint/default-param-last': 'error',
'default-param-last': 'off',
'@typescript-eslint/dot-notation': 'warn',
'dot-notation': 'off',
eqeqeq: [
'error',
'always',
{
null: 'ignore',
},
],
'func-names': ['warn', 'as-needed'],
'grouped-accessor-pairs': ['warn', 'getBeforeSet'],
'guard-for-in': 'error',
'logical-assignment-operators': [
'warn',
'always',
{
enforceForIfStatements: false,
},
],
'new-cap': [
'error',
{
capIsNew: false,
},
],
'no-alert': 'error',
'@typescript-eslint/no-array-constructor': 'error',
'no-array-constructor': 'off',
'no-bitwise': 'warn',
'no-caller': 'error',
'no-console': 'warn',
'no-continue': 'error',
'no-else-return': [
'warn',
{
allowElseIf: false,
},
],
'no-empty': [
'warn',
{
allowEmptyCatch: true,
},
],
'@typescript-eslint/no-empty-function': 'off',
'no-empty-function': 'off',
'no-empty-static-block': 'warn',
'no-eval': 'error',
'no-extend-native': 'error',
'no-extra-bind': 'warn',
'no-extra-boolean-cast': [
'warn',
{
enforceForLogicalOperands: true,
},
],
'no-extra-label': 'warn',
'no-implicit-coercion': [
'warn',
{
disallowTemplateShorthand: true,
allow: ['!!'],
},
],
'@typescript-eslint/no-implied-eval': 'error',
'no-implied-eval': 'off',
'no-invalid-this': 'error',
'no-iterator': 'error',
'no-label-var': 'error',
'no-labels': 'error',
'no-lone-blocks': 'warn',
'no-lonely-if': 'warn',
'@typescript-eslint/no-loop-func': 'error',
'no-loop-func': 'off',
'no-multi-assign': 'error',
'no-multi-str': 'error',
'no-nested-ternary': 'off',
'no-new': 'warn',
'no-new-func': 'error',
'no-new-wrappers': 'error',
'no-object-constructor': 'error',
'no-octal-escape': 'error',
'no-param-reassign': [
'error',
{
props: true,
},
],
'no-plusplus': 'error',
'no-proto': 'error',
'no-restricted-exports': [
'error',
{
restrictedNamedExports: ['then'],
restrictDefaultExports: {
named: true,
namespaceFrom: true,
},
},
],
'no-restricted-globals': [
'error',
'addEventListener',
'blur',
'close',
'closed',
'confirm',
'defaultStatus',
'defaultstatus',
'event',
'external',
'find',
'focus',
'frameElement',
'frames',
'history',
'innerHeight',
'innerWidth',
'length',
'location',
'locationbar',
'menubar',
'moveBy',
'moveTo',
'name',
'onblur',
'onerror',
'onfocus',
'onload',
'onresize',
'onunload',
'open',
'opener',
'opera',
'outerHeight',
'outerWidth',
'pageXOffset',
'pageYOffset',
'parent',
'print',
'removeEventListener',
'resizeBy',
'resizeTo',
'screen',
'screenLeft',
'screenTop',
'screenX',
'screenY',
'scroll',
'scrollbars',
'scrollBy',
'scrollTo',
'scrollX',
'scrollY',
'self',
'status',
'statusbar',
'stop',
'toolbar',
'top',
],
'@typescript-eslint/no-restricted-imports': [
'warn',
{
name: 'enzyme',
message: 'Use @testing-library/react instead.',
},
{
name: 'retranslate',
message: 'Use react-intl instead.',
},
],
'no-restricted-imports': 'off',
'no-restricted-properties': [
'error',
{
property: '__defineGetter__',
message: 'Use Object.defineProperty instead.',
},
{
property: '__defineSetter__',
message: 'Use Object.defineProperty instead.',
},
{
property: '__lookupGetter__',
message: 'Use Object.getOwnPropertyDescriptor instead.',
},
{
property: '__lookupSetter__',
message: 'Use Object.getOwnPropertyDescriptor instead.',
},
],
'no-restricted-syntax': [
'warn',
{
selector: 'ForInStatement',
message: 'Use for-of instead, as for-in iterates over the entire prototype chain which is rarely what one wants.',
},
],
'no-return-assign': ['error', 'always'],
'@typescript-eslint/return-await': 'warn',
'no-return-await': 'off',
'no-script-url': 'error',
'no-sequences': [
'error',
{
allowInParentheses: false,
},
],
'@typescript-eslint/no-shadow': 'error',
'no-shadow': 'off',
'@typescript-eslint/only-throw-error': [
'error',
{
allowThrowingUnknown: true,
},
],
'no-throw-literal': 'off',
'no-undef-init': 'warn',
'no-underscore-dangle': [
'warn',
{
allowAfterThis: true,
allowInObjectDestructuring: false,
allowFunctionParams: false,
},
],
'no-unneeded-ternary': [
'warn',
{
defaultAssignment: false,
},
],
'@typescript-eslint/no-unused-expressions': [
'error',
{
enforceForJSX: true,
},
],
'no-unused-expressions': 'off',
'no-useless-call': 'error',
'no-useless-computed-key': [
'warn',
{
enforceForClassMembers: true,
},
],
'no-useless-concat': 'warn',
'@typescript-eslint/no-useless-constructor': 'warn',
'no-useless-constructor': 'off',
'no-useless-rename': 'warn',
'no-useless-return': 'warn',
'no-var': 'error',
'no-void': [
'error',
{
allowAsStatement: true,
},
],
'object-shorthand': [
'warn',
'always',
{
avoidQuotes: true,
},
],
'one-var': ['warn', 'never'],
'operator-assignment': 'warn',
'prefer-arrow-callback': [
'warn',
{
allowNamedFunctions: true,
},
],
'prefer-const': 'warn',
'@typescript-eslint/prefer-destructuring': [
'warn',
{
VariableDeclarator: {
array: false,
object: true,
},
AssignmentExpression: {
array: false,
object: false,
},
},
],
'prefer-destructuring': 'off',
'prefer-exponentiation-operator': 'warn',
'prefer-numeric-literals': 'warn',
'prefer-object-has-own': 'off',
'prefer-object-spread': 'warn',
'@typescript-eslint/prefer-promise-reject-errors': 'error',
'prefer-promise-reject-errors': 'off',
'prefer-regex-literals': [
'warn',
{
disallowRedundantWrapping: true,
},
],
'prefer-rest-params': 'error',
'prefer-spread': 'error',
'prefer-template': 'warn',
radix: 'error',
'@typescript-eslint/require-await': 'off',
'require-await': 'off',
'@stylistic/spaced-comment': [
'warn',
'always',
{
line: {
exceptions: ['-', '+'],
},
block: {
exceptions: ['*'],
markers: ['!'],
balanced: true,
},
},
],
strict: ['error', 'never'],
'symbol-description': 'warn',
'vars-on-top': 'error',
yoda: 'warn',
'@typescript-eslint/array-type': 'warn',
'@typescript-eslint/class-literal-property-style': ['error', 'getters'],
'@typescript-eslint/consistent-generic-constructors': 'warn',
'@typescript-eslint/consistent-indexed-object-style': 'off',
'@typescript-eslint/consistent-type-definitions': 'off',
'@typescript-eslint/explicit-member-accessibility': [
'warn',
{
accessibility: 'no-public',
},
],
'@typescript-eslint/method-signature-style': 'error',
'@typescript-eslint/no-array-delete': 'error',
'@typescript-eslint/no-base-to-string': [
'error',
{ ignoredTypeNames: ['Error', 'RegExp', 'URL', 'URLSearchParams', 'ReactNode'] },
],
'@typescript-eslint/no-confusing-void-expression': [
'error',
{
ignoreArrowShorthand: true,
},
],
'@typescript-eslint/no-duplicate-type-constituents': 'off',
'@typescript-eslint/no-dynamic-delete': 'error',
'@typescript-eslint/no-empty-interface': [
'warn',
{
allowSingleExtends: true,
},
],
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/no-extraneous-class': [
'warn',
{
allowWithDecorator: true,
},
],
'@typescript-eslint/no-import-type-side-effects': 'error',
'@typescript-eslint/no-invalid-void-type': [
'error',
{
allowAsThisParameter: true,
},
],
'@typescript-eslint/no-meaningless-void-operator': 'warn',
'@typescript-eslint/no-misused-promises': [
'error',
{
checksVoidReturn: {
arguments: false,
attributes: false,
},
},
],
'@typescript-eslint/no-mixed-enums': 'error',
'@typescript-eslint/no-non-null-asserted-nullish-coalescing': 'error',
'@typescript-eslint/no-non-null-assertion': 'warn',
'@typescript-eslint/no-redundant-type-constituents': 'off',
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 'warn',
'@typescript-eslint/no-unnecessary-qualifier': 'warn',
'@typescript-eslint/no-unnecessary-type-arguments': 'warn',
'@typescript-eslint/no-unnecessary-type-assertion': 'warn',
'@typescript-eslint/no-unsafe-enum-comparison': 'off',
'@typescript-eslint/no-unsafe-unary-minus': 'warn',
'@typescript-eslint/no-unnecessary-template-expression': 'warn',
'@typescript-eslint/prefer-enum-initializers': 'warn',
'@typescript-eslint/prefer-find': 'warn',
'@typescript-eslint/prefer-for-of': 'warn',
'@typescript-eslint/prefer-function-type': 'warn',
'@typescript-eslint/prefer-includes': 'warn',
'@typescript-eslint/prefer-literal-enum-member': [
'error',
{
allowBitwiseExpressions: true,
},
],
'@typescript-eslint/prefer-nullish-coalescing': [
'warn',
{
ignoreTernaryTests: true,
ignorePrimitives: {
string: true,
},
},
],
'@typescript-eslint/prefer-optional-chain': 'warn',
'@typescript-eslint/prefer-readonly': 'warn',
'@typescript-eslint/prefer-reduce-type-parameter': 'warn',
'@typescript-eslint/prefer-regexp-exec': 'warn',
'@typescript-eslint/prefer-return-this-type': 'warn',
'@typescript-eslint/prefer-string-starts-ends-with': 'warn',
'@typescript-eslint/prefer-ts-expect-error': 'error',
'@typescript-eslint/promise-function-async': 'warn',
'@typescript-eslint/require-array-sort-compare': 'error',
'@typescript-eslint/restrict-plus-operands': [
'error',
{
allowAny: false,
allowBoolean: false,
allowNullish: false,
allowNumberAndString: false,
allowRegExp: false,
},
],
'@typescript-eslint/switch-exhaustiveness-check': [
'error',
{
considerDefaultExhaustiveForUnions: true,
},
],
'@typescript-eslint/unbound-method': 'off',
'@typescript-eslint/unified-signatures': 'warn',
'import/default': 'off',
'import/extensions': [
'error',
'always',
{
js: 'never',
jsx: 'never',
mjs: 'never',
cjs: 'never',
ts: 'never',
tsx: 'never',
mts: 'never',
cts: 'never',
},
],
'import/first': 'error',
'import/named': 'off',
'import/namespace': 'off',
'import/newline-after-import': 'warn',
'import/no-absolute-path': 'error',
'import/no-cycle': [
'off',
{
ignoreExternal: true,
},
],
'import/no-deprecated': 'off',
'import/no-dynamic-require': 'error',
'import/no-empty-named-blocks': 'warn',
'import/no-import-module-exports': 'error',
'import/no-mutable-exports': 'error',
'import/no-named-as-default-member': 'off',
'import/no-named-default': 'warn',
'import/no-relative-packages': 'error',
'import/no-self-import': 'error',
'import/no-unresolved': 'off',
'import/no-useless-path-segments': 'warn',
'import/no-webpack-loader-syntax': 'error',
'regexp/letter-case': [
'warn',
{
caseInsensitive: 'ignore',
},
],
'regexp/no-control-character': 'error',
'no-control-regex': 'off',
'regexp/no-invisible-character': 'off',
'regexp/no-misleading-capturing-group': [
'error',
{
reportBacktrackingEnds: false,
},
],
'no-misleading-character-class': 'off',
'regexp/no-standalone-backslash': 'error',
'regexp/no-super-linear-move': 'error',
'regexp/prefer-escape-replacement-dollar-char': 'warn',
'regexp/prefer-lookaround': [
'warn',
{
lookbehind: false,
},
],
'regexp/prefer-named-backreference': 'warn',
'regexp/prefer-named-replacement': 'warn',
'regexp/prefer-quantifier': 'warn',
'regexp/prefer-regexp-test': 'warn',
'regexp/prefer-result-array-groups': 'warn',
'@eslint-community/eslint-comments/disable-enable-pair': [
'error',
{
allowWholeFile: true,
},
],
'functional/immutable-data': [
'error',
{
ignoreClasses: 'fieldsOnly',
ignoreMapsAndSets: true,
ignoreAccessorPattern: [
'globalThis.*',
'module.exports',
'exports.*',
'*.current',
'*.contextType',
'*.defaultProps',
'*.displayName',
'*.propTypes',
],
},
],
'unicorn/no-await-in-promise-methods': 'error',
'unicorn/prefer-number-properties': [
'error',
{
checkNaN: false,
},
],
curly: 'warn',
},
},
{
files: ['**/*.js', '**/*.jsx', '**/*.mjs', '**/*.cjs'],
...tseslint.configs.disableTypeChecked,
},
{
files: ['**/*.js', '**/*.jsx', '**/*.mjs', '**/*.cjs'],
rules: {
'@typescript-eslint/no-var-requires': 'off',
},
},
]);