UNPKG

@appium/eslint-config-appium-ts

Version:

Shared ESLint config for Appium projects (TypeScript version)

229 lines (218 loc) 7.63 kB
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/**', ], } ];