diff --git a/@typescript-eslint.js b/@typescript-eslint.js new file mode 100644 index 00000000..c2162d10 --- /dev/null +++ b/@typescript-eslint.js @@ -0,0 +1,95 @@ +module.exports = { + parser: '@typescript-eslint/parser', + parserOptions: { sourceType: 'module' }, + plugins: ['@typescript-eslint'], + extends: [ + 'plugin:@typescript-eslint/eslint-recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:@typescript-eslint/recommended-requiring-type-checking', + 'prettier/@typescript-eslint' + ], + rules: { + '@typescript-eslint/array-type': ['error', { default: 'array-simple' }], + // eslint-disable-next-line local/prefer-valid-rules + '@typescript-eslint/camelcase': ['error', { allow: ['child_process'] }], + '@typescript-eslint/consistent-type-definitions': 'error', + '@typescript-eslint/default-param-last': 'error', + '@typescript-eslint/explicit-member-accessibility': 'error', + // eslint-disable-next-line local/prefer-valid-rules + '@typescript-eslint/generic-type-naming': [ + 'error', + /^T([A-Z][a-zA-Z]+)$|^[A-Z]$/u.toString().slice(1, -2) + ], + // eslint-disable-next-line local/prefer-valid-rules + '@typescript-eslint/member-naming': [ + 'warn', + { private: '^_', protected: '^_' } + ], + '@typescript-eslint/no-dynamic-delete': 'error', + '@typescript-eslint/no-extra-non-null-assertion': 'error', + '@typescript-eslint/no-extraneous-class': 'error', + '@typescript-eslint/no-floating-promises': 'error', + '@typescript-eslint/no-namespace': [ + 'off', // todo: need to audit existing codebase to see if declare is fine + { + allowDeclarations: true, + allowDefinitionFiles: true + } + ], + '@typescript-eslint/no-parameter-properties': 'error', + '@typescript-eslint/no-require-imports': 'error', + '@typescript-eslint/no-this-alias': ['error', { allowDestructuring: true }], + '@typescript-eslint/no-throw-literal': 'error', + '@typescript-eslint/no-unnecessary-condition': [ + 'error', + // todo: remove once https://github.com/typescript-eslint/typescript-eslint/pull/1163 is merged + { ignoreRhs: true } + ], + '@typescript-eslint/no-unnecessary-qualifier': 'error', + '@typescript-eslint/no-unnecessary-type-arguments': 'error', + '@typescript-eslint/explicit-module-boundary-types': 'error', + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + '@typescript-eslint/no-use-before-define': [ + 'error', // Purely stylistic b/c of TS + { typedefs: false, variables: false } + ], + '@typescript-eslint/no-useless-constructor': 'error', + '@typescript-eslint/prefer-for-of': 'error', + '@typescript-eslint/prefer-function-type': 'error', + '@typescript-eslint/prefer-nullish-coalescing': 'error', + '@typescript-eslint/prefer-optional-chain': 'error', + '@typescript-eslint/prefer-readonly': 'warn', + '@typescript-eslint/prefer-regexp-exec': 'warn', + '@typescript-eslint/prefer-string-starts-ends-with': 'warn', + '@typescript-eslint/promise-function-async': 'error', + '@typescript-eslint/require-array-sort-compare': 'warn', + '@typescript-eslint/restrict-plus-operands': 'error', + '@typescript-eslint/restrict-template-expressions': [ + 'error', + { + allowBoolean: true, + allowNumber: true + } + ], + // yes: with types, this is actually useful and correct + '@typescript-eslint/return-await': 'error', + '@typescript-eslint/unbound-method': 'warn', // can be a bit wrong + '@typescript-eslint/unified-signatures': 'warn', // can be a bit wrong + + 'array-callback-return': 'off', + 'block-scoped-var': 'off', + 'consistent-return': 'off', // via --noImplicitReturns + 'default-param-last': 'off', + 'guard-for-in': 'off', + 'init-declarations': 'off', // handled by TS & --noImplicitAny + 'no-import-assign': 'off', + 'no-invalid-this': 'off', + 'no-iterator': 'off', + 'no-proto': 'off', // TS2339 + 'no-setter-return': 'off', // TS2408 + 'no-throw-literal': 'off', // @typescript-eslint + 'no-underscore-dangle': 'off', + 'no-useless-constructor': 'off', // @typescript-eslint + 'strict': 'off' // via --alwaysStrict + } +}; diff --git a/README.md b/README.md index 1b9298ef..88673c9d 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,22 @@ Install this package: npm install --save-dev eslint-config-ackama +### Additional Setup + +#### @typescript-eslint + +The `@typescript-eslint` configuration requires type checking to be setup. + +You can do this by making a `tsconfig.eslint.json` with the following: + +```json +{ + "extends": "./tsconfig.json", + "exclude": ["node_modules", "coverage", "public", "build", "dist", "lib"], + "include": ["bin", "src", "types", "test", "*.ts", "*.tsx", "*.js", "*.jsx"] +} +``` + ### Environments ESLint uses the toplevel `env` property to track what variables are available @@ -29,6 +45,35 @@ In general, the primary ones to know about are You'll find a full list of the envs & their use-cases [here](https://eslint.org/docs/user-guide/configuring#specifying-environments). +### Notes & Considerations + +While the majority of rules enabled by these configurations are sound, a few +have edge cases or are potentially not as suitable as initially hoped. + +Some of these edge cases are already well-known, and may have possible fixes in +the future; the details of these rules are documented below. + +In general, we are more acceptance of rules that don't catch everything than +rules that report too many false positives. + +#### `@typescript-eslint/unbound-method` reports methods as unbound (`console` in particular) + +This rule is promising, but needs to be battle tested in real-world code to +determine how accurate it actually is. + +One common pattern that is already known to be flagged is with `Console`: + +``` +Promise.reject().catch(console.error); +``` + +This will be incorrectly flagged as being unbound. This is because currently the +`Console` methods are not typed as being bound. + +There is an open issue tracking implementing an exclusion for `Console` to the +rule on +[`@typescript-eslint`](https://github.com/typescript-eslint/typescript-eslint/issues/1085). + ### Releasing Releases are handled using diff --git a/package-lock.json b/package-lock.json index 5f1af9d5..8add3fad 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1540,12 +1540,12 @@ "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.16.0.tgz", - "integrity": "sha512-TKWbeFAKRPrvKiR9GNxErQ8sELKqg1ZvXi6uho07mcKShBnCnqNpDQWP01FEvWKf0bxM2g7uQEI5MNjSNqvUpQ==", + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.17.0.tgz", + "integrity": "sha512-tg/OMOtPeXlvk0ES8mZzEZ4gd1ruSE03nsKcK+teJhxYv5CPCXK6Mb/OK6NpB4+CqGTHs4MVeoSZXNFqpT1PyQ==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "2.16.0", + "@typescript-eslint/experimental-utils": "2.17.0", "eslint-utils": "^1.4.3", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.0.0", @@ -1561,32 +1561,32 @@ } }, "@typescript-eslint/experimental-utils": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.16.0.tgz", - "integrity": "sha512-bXTmAztXpqxliDKZgvWkl+5dHeRN+jqXVZ16peKKFzSXVzT6mz8kgBpHiVzEKO2NZ8OCU7dG61K9sRS/SkUUFQ==", + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.17.0.tgz", + "integrity": "sha512-2bNf+mZ/3mj5/3CP56v+ldRK3vFy9jOvmCPs/Gr2DeSJh+asPZrhFniv4QmQsHWQFPJFWhFHgkGgJeRmK4m8iQ==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "2.16.0", + "@typescript-eslint/typescript-estree": "2.17.0", "eslint-scope": "^5.0.0" } }, "@typescript-eslint/parser": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.16.0.tgz", - "integrity": "sha512-+w8dMaYETM9v6il1yYYkApMSiwgnqXWJbXrA94LAWN603vXHACsZTirJduyeBOJjA9wT6xuXe5zZ1iCUzoxCfw==", + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.17.0.tgz", + "integrity": "sha512-k1g3gRQ4fwfJoIfgUpz78AovicSWKFANmvTfkAHP24MgJHjWfZI6ya7tsQZt1sLczvP4G9BE5G5MgADHdmJB/w==", "dev": true, "requires": { "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "2.16.0", - "@typescript-eslint/typescript-estree": "2.16.0", + "@typescript-eslint/experimental-utils": "2.17.0", + "@typescript-eslint/typescript-estree": "2.17.0", "eslint-visitor-keys": "^1.1.0" } }, "@typescript-eslint/typescript-estree": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.16.0.tgz", - "integrity": "sha512-hyrCYjFHISos68Bk5KjUAXw0pP/455qq9nxqB1KkT67Pxjcfw+r6Yhcmqnp8etFL45UexCHUMrADHH7dI/m2WQ==", + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.17.0.tgz", + "integrity": "sha512-g0eVRULGnEEUakxRfJO0s0Hr1LLQqsI6OrkiCLpdHtdJJek+wyd8mb00vedqAoWldeDcOcP8plqw8/jx9Gr3Lw==", "dev": true, "requires": { "debug": "^4.1.1", diff --git a/package.json b/package.json index e6e7cdaf..44d27817 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "license": "ISC", "author": "Gareth Jones", "files": [ + "@typescript-eslint.js", "flowtype.js", "index.js", "jest.js" @@ -53,9 +54,9 @@ "@types/eslint": "^6.1.3", "@types/jest": "^24.9.0", "@types/node": "^12.12.25", - "@typescript-eslint/eslint-plugin": "^2.16.0", - "@typescript-eslint/experimental-utils": "^2.16.0", - "@typescript-eslint/parser": "^2.16.0", + "@typescript-eslint/eslint-plugin": "^2.17.0", + "@typescript-eslint/experimental-utils": "^2.17.0", + "@typescript-eslint/parser": "^2.17.0", "babel-eslint": "^10.0.3", "eslint": "^6.8.0", "eslint-plugin-eslint-comments": "^3.1.2",