@ssh/eslint-config
Version:
Slingshot's ESLint configuration for JavaScript, TypeScript, and React projects with ESLint 9 flat config support
384 lines (341 loc) • 17.3 kB
JavaScript
import { rules as baseBestPracticesRules } from '../../airbnb/best-practices.js';
import { rules as baseES6Rules } from '../../airbnb/es6.js';
import typescriptEslint from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
// Plugin configuration for flat config
export const plugins = {
'@typescript-eslint': typescriptEslint,
};
// Language options for flat config
export const languageOptions = {
parser: tsParser,
};
// Settings for flat config
export const settings = {
// Apply special parsing for TypeScript files
'import/parsers': {
'@typescript-eslint/parser': ['.ts', '.tsx', '.d.ts'],
},
// Append 'ts' extensions to Airbnb 'import/resolver' setting
// Original: ['.mjs', '.js', '.json']
'import/resolver': {
node: {
extensions: ['.mjs', '.js', '.json', '.ts', '.d.ts'],
},
},
// Append 'ts' extensions to Airbnb 'import/extensions' setting
// Original: ['.js', '.mjs', '.jsx']
'import/extensions': ['.js', '.mjs', '.jsx', '.ts', '.tsx', '.d.ts'],
// Resolve type definition packages
'import/external-module-folders': ['node_modules', 'node_modules/@types'],
};
export const rules = {
// Replace Airbnb 'brace-style' rule with '@stylistic' version
// https://eslint.style/rules/ts/brace-style
'brace-style': 'off',
'@stylistic/brace-style': baseBestPracticesRules['@stylistic/brace-style'] || ['error', '1tbs', { allowSingleLine: true }],
// Replace Airbnb 'camelcase' rule with '@typescript-eslint/naming-convention'
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/naming-convention.md
camelcase: 'off',
// The `@typescript-eslint/naming-convention` rule allows `leadingUnderscore` and `trailingUnderscore`
// settings. However, the existing `no-underscore-dangle` rule already takes care of this.
'@typescript-eslint/naming-convention': [
'error',
// Allow camelCase variables (23.2), PascalCase variables (23.8), and UPPER_CASE variables (23.10)
{
selector: 'variable',
format: ['camelCase', 'PascalCase', 'UPPER_CASE'],
},
// Allow camelCase functions (23.2), and PascalCase functions (23.8)
{
selector: 'function',
format: ['camelCase', 'PascalCase'],
},
// Airbnb recommends PascalCase for classes (23.3), and although Airbnb does not make TypeScript
// recommendations, we are assuming this rule would similarly apply to anything "type like", including
// interfaces, type aliases, and enums
{
selector: 'typeLike',
format: ['PascalCase'],
},
],
// Replace Airbnb 'comma-dangle' rule with '@stylistic' version
// https://eslint.style/rules/ts/comma-dangle
'comma-dangle': 'off',
'@stylistic/comma-dangle': [
'error',
{
arrays: 'always-multiline',
objects: 'always-multiline',
imports: 'always-multiline',
exports: 'always-multiline',
functions: 'always-multiline',
enums: 'always-multiline',
generics: 'always-multiline',
tuples: 'always-multiline',
},
],
// Replace Airbnb 'comma-spacing' rule with '@stylistic' version
// https://eslint.style/rules/ts/comma-spacing
'comma-spacing': 'off',
'@stylistic/comma-spacing': ['error', { before: false, after: true }],
// Replace Airbnb 'default-param-last' rule with '@typescript-eslint' version
// https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/default-param-last.md
'default-param-last': 'off',
'@typescript-eslint/default-param-last': baseBestPracticesRules['default-param-last'],
// Replace Airbnb 'dot-notation' rule with '@typescript-eslint' version
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/dot-notation.md
'dot-notation': 'off',
'@typescript-eslint/dot-notation': baseBestPracticesRules['dot-notation'],
// Replace Airbnb 'func-call-spacing' rule with '@stylistic' version
// https://eslint.style/rules/ts/function-call-spacing
'func-call-spacing': 'off',
'@stylistic/function-call-spacing': ['error', 'never'],
// Replace Airbnb 'indent' rule with '@stylistic' version
// https://eslint.style/rules/ts/indent
indent: 'off',
'@stylistic/indent': ['error', 4, {
SwitchCase: 1,
VariableDeclarator: 1,
outerIIFEBody: 1,
FunctionDeclaration: { parameters: 1, body: 1 },
FunctionExpression: { parameters: 1, body: 1 },
CallExpression: { arguments: 1 },
ArrayExpression: 1,
ObjectExpression: 1,
ImportDeclaration: 1,
flatTernaryExpressions: false,
ignoredNodes: ['JSXElement', 'JSXElement > *', 'JSXAttribute', 'JSXIdentifier', 'JSXNamespacedName', 'JSXMemberExpression', 'JSXSpreadAttribute', 'JSXExpressionContainer', 'JSXOpeningElement', 'JSXClosingElement', 'JSXFragment', 'JSXOpeningFragment', 'JSXClosingFragment', 'JSXText', 'JSXEmptyExpression', 'JSXSpreadChild'],
ignoreComments: false
}],
// Replace Airbnb 'keyword-spacing' rule with '@stylistic' version
// https://eslint.style/rules/ts/keyword-spacing
'keyword-spacing': 'off',
'@stylistic/keyword-spacing': ['error', {
before: true,
after: true,
overrides: {
return: { after: true },
throw: { after: true },
case: { after: true }
}
}],
// Replace Airbnb 'lines-between-class-members' rule with '@stylistic' version
// https://eslint.style/rules/ts/lines-between-class-members
'lines-between-class-members': 'off',
'@stylistic/lines-between-class-members': ['error', 'always', { exceptAfterSingleLine: false }],
// Replace Airbnb 'no-array-constructor' rule with '@typescript-eslint' version
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-array-constructor.md
'no-array-constructor': 'off',
'@typescript-eslint/no-array-constructor': 'error',
// Replace Airbnb 'no-dupe-class-members' rule with '@typescript-eslint' version
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-dupe-class-members.md
'no-dupe-class-members': 'off',
'@typescript-eslint/no-dupe-class-members': baseES6Rules['no-dupe-class-members'],
// Replace Airbnb 'no-empty-function' rule with '@typescript-eslint' version
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-empty-function.md
'no-empty-function': 'off',
'@typescript-eslint/no-empty-function': ['error', {
allow: [
'arrowFunctions',
'functions',
'methods',
]
}],
// Replace Airbnb 'no-extra-parens' rule with '@stylistic' version
// https://eslint.style/rules/ts/no-extra-parens
'no-extra-parens': 'off',
'@stylistic/no-extra-parens': ['off', 'all', {
conditionalAssign: true,
nestedBinaryExpressions: false,
returnAssign: false,
ignoreJSX: 'all',
enforceForArrowConditionals: false,
}],
// Replace Airbnb 'no-extra-semi' rule with '@stylistic' version
// https://eslint.style/rules/ts/no-extra-semi
'no-extra-semi': 'off',
'@stylistic/no-extra-semi': 'error',
// Replace Airbnb 'no-implied-eval' and 'no-new-func' rules with '@typescript-eslint' version
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-implied-eval.md
'no-implied-eval': 'off',
'no-new-func': 'off',
'@typescript-eslint/no-implied-eval': 'error',
// Replace Airbnb 'no-loss-of-precision' rule with '@typescript-eslint' version
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-loss-of-precision.md
'no-loss-of-precision': 'off',
'@typescript-eslint/no-loss-of-precision': 'error',
// Replace Airbnb 'no-loop-func' rule with '@typescript-eslint' version
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-loop-func.md
'no-loop-func': 'off',
'@typescript-eslint/no-loop-func': 'error',
// Replace Airbnb 'no-magic-numbers' rule with '@typescript-eslint' version
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-magic-numbers.md
'no-magic-numbers': 'off',
'@typescript-eslint/no-magic-numbers': ['off', {
ignore: [],
ignoreArrayIndexes: true,
enforceConst: true,
detectObjects: false,
}],
// Replace Airbnb 'no-redeclare' rule with '@typescript-eslint' version
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-redeclare.md
'no-redeclare': 'off',
'@typescript-eslint/no-redeclare': 'error',
// Replace Airbnb 'no-shadow' rule with '@typescript-eslint' version
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-shadow.md
'no-shadow': 'off',
'@typescript-eslint/no-shadow': 'error',
// Replace Airbnb 'space-before-blocks' rule with '@stylistic' version
// https://eslint.style/rules/ts/space-before-blocks
'space-before-blocks': 'off',
'@stylistic/space-before-blocks': 'error',
// Replace Airbnb 'no-throw-literal' rule with '@typescript-eslint' version
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/only-throw-error.md
'no-throw-literal': 'off',
'@typescript-eslint/only-throw-error': 'error',
// Replace Airbnb 'no-unused-expressions' rule with '@typescript-eslint' version
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unused-expressions.md
'no-unused-expressions': 'off',
'@typescript-eslint/no-unused-expressions': ['error', {
allowShortCircuit: false,
allowTernary: false,
allowTaggedTemplates: false,
}],
// Replace Airbnb 'no-unused-vars' rule with '@typescript-eslint' version
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-unused-vars.md
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': ['error', { vars: 'all', args: 'after-used', ignoreRestSiblings: true }],
// Replace Airbnb 'no-use-before-define' rule with '@typescript-eslint' version
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-use-before-define.md
'no-use-before-define': 'off',
'@typescript-eslint/no-use-before-define': ['error', { functions: true, classes: true, variables: true }],
// Replace Airbnb 'no-useless-constructor' rule with '@typescript-eslint' version
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-useless-constructor.md
'no-useless-constructor': 'off',
'@typescript-eslint/no-useless-constructor': 'error',
// Replace Airbnb 'quotes' rule with '@stylistic' version
// https://eslint.style/rules/ts/quotes
quotes: 'off',
'@stylistic/quotes': ['error', 'single', { avoidEscape: true }],
// Replace Airbnb 'semi' rule with '@stylistic' version
// https://eslint.style/rules/ts/semi
semi: 'off',
'@stylistic/semi': ['error', 'always'],
// Replace Airbnb 'space-before-function-paren' rule with '@stylistic' version
// https://eslint.style/rules/ts/space-before-function-paren
'space-before-function-paren': 'off',
'@stylistic/space-before-function-paren': ['error', {
anonymous: 'always',
named: 'never',
asyncArrow: 'always'
}],
// Replace Airbnb 'require-await' rule with '@typescript-eslint' version
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/require-await.md
'require-await': 'off',
'@typescript-eslint/require-await': 'off',
// Replace Airbnb 'no-return-await' rule with '@typescript-eslint' version
// https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/return-await.md
'no-return-await': 'off',
'@typescript-eslint/return-await': ['error', 'in-try-catch'],
// Replace Airbnb 'space-infix-ops' rule with '@stylistic' version
// https://eslint.style/rules/ts/space-infix-ops
'space-infix-ops': 'off',
'@stylistic/space-infix-ops': 'error',
// Replace Airbnb 'object-curly-spacing' rule with '@stylistic' version
// https://eslint.style/rules/ts/object-curly-spacing
'object-curly-spacing': 'off',
'@stylistic/object-curly-spacing': ['error', 'always'],
// Slingshot TypeScript-specific rule
'@typescript-eslint/consistent-type-imports': 'error',
// Append 'ts' and 'tsx' to Airbnb 'import/extensions' rule
// https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/extensions.md
'import/extensions': [
'error',
'ignorePackages',
{
js: 'never',
mjs: 'never',
jsx: 'never',
ts: 'never',
tsx: 'never',
},
],
// Append 'ts' and 'tsx' extensions to Airbnb 'import/no-extraneous-dependencies' rule
// https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-extraneous-dependencies.md
'import/no-extraneous-dependencies': [
'error',
{
devDependencies: [
'test/**', // tape, common npm pattern
'tests/**', // also common npm pattern
'spec/**', // mocha, rspec-like pattern
'**/__tests__/**', // jest pattern
'**/__mocks__/**', // jest pattern
'test.{js,jsx,ts,tsx}', // repos with a single test file
'test-*.{js,jsx,ts,tsx}', // repos with multiple top-level test files
'**/*{.,_}{test,spec}.{js,jsx,ts,tsx}', // tests where the extension or filename suffix denotes that it is a test
'**/jest.config.js', // jest config
'**/jest.setup.js', // jest setup
'**/vue.config.js', // vue-cli config
'**/webpack.config.js', // webpack config
'**/webpack.config.*.js', // webpack config
'**/rollup.config.js', // rollup config
'**/rollup.config.*.js', // rollup config
'**/gulpfile.js', // gulp config
'**/gulpfile.*.js', // gulp config
'**/Gruntfile{,.js}', // grunt config
'**/protractor.conf.js', // protractor config
'**/protractor.conf.*.js', // protractor config
'**/karma.conf.js', // karma config
'**/.eslintrc.js' // eslint config
],
optionalDependencies: false,
},
],
};
export const overrides = [
{
name: 'ssh_typescript_overrides',
files: ['**/*.ts', '**/*.tsx'],
rules: {
// The following rules are enabled in Airbnb config, but are already checked (more thoroughly) by the
// TypeScript compiler Some of the rules also fail in TypeScript files, for example:
// https://github.com/typescript-eslint/typescript-eslint/issues/662#issuecomment-507081586 Rules are
// inspired by:
// https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/eslint-recommended.ts
'constructor-super': 'off',
'getter-return': 'off',
'no-const-assign': 'off',
'no-dupe-args': 'off',
'no-dupe-class-members': 'off',
'no-dupe-keys': 'off',
'no-func-assign': 'off',
'no-import-assign': 'off',
'no-new-symbol': 'off',
'no-obj-calls': 'off',
'no-redeclare': 'off',
'no-setter-return': 'off',
'no-this-before-super': 'off',
'no-undef': 'off',
'no-unreachable': 'off',
'no-unsafe-negation': 'off',
'valid-typeof': 'off',
// The following rules are enabled in Airbnb config, but are recommended to be disabled within
// TypeScript projects See:
// https://github.com/typescript-eslint/typescript-eslint/blob/13583e65f5973da2a7ae8384493c5e00014db51b/docs/linting/TROUBLESHOOTING.md#eslint-plugin-import
'import/named': 'off',
'import/no-named-as-default-member': 'off',
// Disable `import/no-unresolved`, see README.md for details
'import/no-unresolved': 'off',
},
},
];
// Default export for compatibility
export default {
plugins,
languageOptions,
settings,
rules,
overrides,
};