@appium/eslint-config-appium-ts
Version:
Shared ESLint config for Appium projects (TypeScript version)
229 lines (218 loc) • 7.63 kB
JavaScript
import path from 'node:path';
import fs from 'node:fs';
import {includeIgnoreFile} from '@eslint/compat';
import js from '@eslint/js';
import eslintConfigPrettier from 'eslint-config-prettier';
import globals from 'globals';
import pluginPromise from 'eslint-plugin-promise';
import importPlugin from 'eslint-plugin-import';
import mochaPlugin from 'eslint-plugin-mocha';
import {configs as tsConfigs, parser as tsParser, plugin as tsPlugin} from 'typescript-eslint';
const gitignorePath = path.resolve(process.cwd(), '.gitignore');
export default [
js.configs.recommended,
eslintConfigPrettier,
pluginPromise.configs['flat/recommended'],
importPlugin.flatConfigs.recommended,
...tsConfigs.recommended,
{
name: 'Script Files',
files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'],
languageOptions: {
ecmaVersion: 2022,
sourceType: 'module',
parser: tsParser,
globals: {
...globals.node,
NodeJS: 'readonly',
BufferEncoding: 'readonly',
},
},
plugins: {
'@typescript-eslint': tsPlugin,
},
settings: {
/**
* This stuff enables `eslint-plugin-import` to resolve TS modules.
*/
'import/parsers': {
'@typescript-eslint/parser': ['.ts', '.tsx', '.mtsx'],
},
'import/resolver': {
typescript: {
project: ['tsconfig.json', './packages/*/tsconfig.json'],
},
},
},
rules: {
/**
* This rule is configured to warn if a `@ts-ignore` or `@ts-expect-error` directive is used
* without explanation.
* @remarks It's good practice to explain why things break!
*/
'@typescript-eslint/ban-ts-comment': [
'warn',
{
'ts-expect-error': 'allow-with-description',
'ts-ignore': 'allow-with-description',
},
],
/**
* Empty functions are allowed.
* @remarks This is disabled because I need someone to explain to me why empty functions are bad. I suppose they _could_ be bugs, but so could literally any line of code.
*/
'@typescript-eslint/no-empty-function': 'off',
/**
* Empty interfaces are allowed.
* @remarks This is because empty interfaces have a use case in declaration merging. Otherwise,
* an empty interface can be a type alias, e.g., `type Foo = Bar` where `Bar` is an interface.
*/
'@typescript-eslint/no-empty-interface': 'off',
'@typescript-eslint/no-empty-object-type': 'off',
/**
* Explicit `any` types are allowed.
* @remarks Eventually this should be a warning, and finally an error, as we fully type the codebases.
*/
'@typescript-eslint/no-explicit-any': 'off',
/**
* Warns if a non-null assertion (`!`) is used.
* @remarks Generally, a non-null assertion should be replaced by a proper type guard or
* type-safe function, if possible. For example, `Set.prototype.has(x)` is not type-safe, and
* does not imply that `Set.prototype.get(x)` is not `undefined` (I do not know why this is, but
* I'm sure there's a good reason for it). In this case, a non-null assertion is appropriate.
* Often a simple `typeof x === 'y'` conditional is sufficient to narrow the type and avoid the
* non-null assertion.
*/
'@typescript-eslint/no-non-null-assertion': 'warn',
'@typescript-eslint/no-require-imports': 'off',
/**
* Sometimes we want unused variables to be present in base class method declarations.
*/
'@typescript-eslint/no-unused-vars': 'warn',
'@typescript-eslint/no-var-requires': 'off',
'import/export': 2,
'import/named': 'warn',
'import/no-duplicates': 2,
'import/no-unresolved': 2,
'promise/catch-or-return': 1,
/**
* Allow native `Promise`s.
* @remarks Originally, this was so that we could use [bluebird](https://npm.im/bluebird)
* everywhere, but this is not strictly necessary.
*/
'promise/no-native': 'off',
'promise/no-return-wrap': 1,
'promise/prefer-await-to-callbacks': 1,
'promise/prefer-await-to-then': 1,
'promise/param-names': 1,
'array-bracket-spacing': 2,
'arrow-body-style': [1, 'as-needed'],
'arrow-parens': [1, 'always'],
'arrow-spacing': 2,
/**
* Disables the `brace-style` rule.
* @remarks Due to the way `prettier` sometimes formats extremely verbose types, sometimes it is necessary
* to indent in a way that is not allowed by the default `brace-style` rule.
*/
'brace-style': 'off',
'comma-dangle': 0,
'comma-spacing': [
2,
{
before: false,
after: true,
},
],
'curly': [2, 'all'],
'dot-notation': 2,
'eqeqeq': [2, 'smart'],
'key-spacing': [
2,
{
mode: 'strict',
beforeColon: false,
afterColon: true,
},
],
'keyword-spacing': 2,
'no-buffer-constructor': 1,
'no-console': 2,
'no-dupe-class-members': 'off',
'no-empty': 0,
'no-multi-spaces': 2,
'no-prototype-builtins': 1,
'no-redeclare': 'off',
'no-trailing-spaces': 2,
'no-var': 2,
'no-whitespace-before-property': 2,
'object-shorthand': 2,
'quotes': [
2,
'single',
{
avoidEscape: true,
allowTemplateLiterals: true,
},
],
'radix': [2, 'always'],
'require-atomic-updates': 0,
/**
* Allow `async` functions without `await`.
* @remarks Originally, this was to be more clear about the return value of a function, but with
* the addition of types, this is no longer necessary. Further, both `return somePromise` and
* `return await somePromise` have their own use-cases.
*/
'require-await': 'off',
'semi': [2, 'always'],
'space-before-blocks': [2, 'always'],
'space-in-parens': [2, 'never'],
'space-infix-ops': 2,
'space-unary-ops': [
2,
{
words: true,
nonwords: false,
},
],
}
},
{
...mochaPlugin.configs.flat.recommended,
name: 'Test Files',
files: ['**/test/**', '*.spec.*js', '-specs.*js', '*.spec.ts'],
rules: {
...mochaPlugin.configs.flat.recommended.rules,
/**
* Both `@ts-expect-error` and `@ts-ignore` are allowed to be used with impunity in tests.
* @remarks We often test things which explicitly violate types.
*/
'@typescript-eslint/ban-ts-comment': 'off',
/**
* Allow non-null assertions in tests; do not even warn.
* @remarks The idea is that the assertions themselves will be written in such a way that if
* the non-null assertion was invalid, the assertion would fail.
*/
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-unused-expressions': 'off',
'import/no-named-as-default-member': 'off',
'mocha/consistent-spacing-between-blocks': 'off',
'mocha/max-top-level-suites': 'off',
'mocha/no-exclusive-tests': 2,
'mocha/no-exports': 'off',
'mocha/no-mocha-arrows': 2,
'mocha/no-setup-in-describe': 'off',
'mocha/no-skipped-tests': 'off',
},
},
{
name: 'Ignores',
ignores: [
...(fs.existsSync(gitignorePath) ? includeIgnoreFile(gitignorePath).ignores : []),
'**/.*',
'**/*-d.ts',
'**/*.min.js',
'**/build/**',
'**/coverage/**',
],
}
];