From 5e4dda264a7d6a6a1626848e7599faea1ac34922 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Mon, 15 Jun 2020 18:54:38 -0700 Subject: [PATCH 01/10] fix(experimental-utils): correct types for TS versions older than 3.8 (#2217) --- packages/experimental-utils/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/experimental-utils/package.json b/packages/experimental-utils/package.json index e94079f0996e..5ed24642f447 100644 --- a/packages/experimental-utils/package.json +++ b/packages/experimental-utils/package.json @@ -57,7 +57,7 @@ "typesVersions": { "<3.8": { "*": [ - "ts3.4/*" + "_ts3.4/*" ] } } From 535b0f2ddd82efa6a2c40307a61c480f4b3cdea3 Mon Sep 17 00:00:00 2001 From: YeonJuan Date: Tue, 16 Jun 2020 11:21:38 +0900 Subject: [PATCH 02/10] feat(eslint-plugin): add extension rule `no-loss-of-precision` (#2196) Co-authored-by: Brad Zacher --- package.json | 2 +- packages/eslint-plugin/README.md | 1 + .../docs/rules/no-loss-of-precision.md | 19 +++++++ packages/eslint-plugin/src/configs/all.ts | 2 + packages/eslint-plugin/src/rules/index.ts | 2 + .../src/rules/no-loss-of-precision.ts | 53 +++++++++++++++++++ .../tests/rules/no-loss-of-precision.test.ts | 36 +++++++++++++ .../eslint-plugin/typings/eslint-rules.d.ts | 13 +++++ yarn.lock | 41 +++++++++----- 9 files changed, 154 insertions(+), 15 deletions(-) create mode 100644 packages/eslint-plugin/docs/rules/no-loss-of-precision.md create mode 100644 packages/eslint-plugin/src/rules/no-loss-of-precision.ts create mode 100644 packages/eslint-plugin/tests/rules/no-loss-of-precision.test.ts diff --git a/package.json b/package.json index a3ffa851516a..e01a0ed0c896 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "cspell": "^4.0.61", "cz-conventional-changelog": "^3.2.0", "downlevel-dts": "^0.4.0", - "eslint": "^7.0.0", + "eslint": "^7.2.0", "eslint-plugin-eslint-comments": "^3.1.2", "eslint-plugin-eslint-plugin": "^2.2.1", "eslint-plugin-import": "^2.20.2", diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index 53b8cbb94129..cc2bbc078996 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -191,6 +191,7 @@ In these cases, we create what we call an extension rule; a rule within our plug | [`@typescript-eslint/no-extra-parens`](./docs/rules/no-extra-parens.md) | Disallow unnecessary parentheses | | :wrench: | | | [`@typescript-eslint/no-extra-semi`](./docs/rules/no-extra-semi.md) | Disallow unnecessary semicolons | :heavy_check_mark: | :wrench: | | | [`@typescript-eslint/no-invalid-this`](./docs/rules/no-invalid-this.md) | disallow `this` keywords outside of classes or class-like objects | | | | +| [`@typescript-eslint/no-loss-of-precision`](./docs/rules/no-loss-of-precision.md) | Disallow literal numbers that lose precision | | | | | [`@typescript-eslint/no-magic-numbers`](./docs/rules/no-magic-numbers.md) | Disallow magic numbers | | | | | [`@typescript-eslint/no-unused-expressions`](./docs/rules/no-unused-expressions.md) | Disallow unused expressions | | | | | [`@typescript-eslint/no-unused-vars`](./docs/rules/no-unused-vars.md) | Disallow unused variables | :heavy_check_mark: | | | diff --git a/packages/eslint-plugin/docs/rules/no-loss-of-precision.md b/packages/eslint-plugin/docs/rules/no-loss-of-precision.md new file mode 100644 index 000000000000..d6cf7b71c14a --- /dev/null +++ b/packages/eslint-plugin/docs/rules/no-loss-of-precision.md @@ -0,0 +1,19 @@ +# Disallow literal numbers that lose precision (`no-loss-of-precision`) + +## Rule Details + +This rule extends the base [`eslint/no-loss-of-precision`](https://eslint.org/docs/rules/no-loss-of-precision) rule. +It adds support for [numeric separators](https://github.com/tc39/proposal-numeric-separator). +Note that this rule requires ESLint v7. + +## How to use + +```jsonc +{ + // note you must disable the base rule as it can report incorrect errors + "no-loss-of-precision": "off", + "@typescript-eslint/no-loss-of-precision": ["error"] +} +``` + +Taken with ❤️ [from ESLint core](https://github.com/eslint/eslint/blob/master/docs/rules/no-loss-of-precision.md) diff --git a/packages/eslint-plugin/src/configs/all.ts b/packages/eslint-plugin/src/configs/all.ts index 25001233883d..642d6f736d07 100644 --- a/packages/eslint-plugin/src/configs/all.ts +++ b/packages/eslint-plugin/src/configs/all.ts @@ -59,6 +59,8 @@ export = { 'no-invalid-this': 'off', '@typescript-eslint/no-invalid-this': 'error', '@typescript-eslint/no-invalid-void-type': 'error', + 'no-loss-of-precision': 'off', + '@typescript-eslint/no-loss-of-precision': 'error', 'no-magic-numbers': 'off', '@typescript-eslint/no-magic-numbers': 'error', '@typescript-eslint/no-misused-new': 'error', diff --git a/packages/eslint-plugin/src/rules/index.ts b/packages/eslint-plugin/src/rules/index.ts index 05016d5705fa..37ad1da48062 100644 --- a/packages/eslint-plugin/src/rules/index.ts +++ b/packages/eslint-plugin/src/rules/index.ts @@ -96,6 +96,7 @@ import typedef from './typedef'; import unboundMethod from './unbound-method'; import unifiedSignatures from './unified-signatures'; import linesBetweenClassMembers from './lines-between-class-members'; +import noLossOfPrecision from './no-loss-of-precision'; export default { 'adjacent-overload-signatures': adjacentOverloadSignatures, @@ -196,4 +197,5 @@ export default { 'unbound-method': unboundMethod, 'unified-signatures': unifiedSignatures, 'lines-between-class-members': linesBetweenClassMembers, + 'no-loss-of-precision': noLossOfPrecision, }; diff --git a/packages/eslint-plugin/src/rules/no-loss-of-precision.ts b/packages/eslint-plugin/src/rules/no-loss-of-precision.ts new file mode 100644 index 000000000000..47ab5b1a74fa --- /dev/null +++ b/packages/eslint-plugin/src/rules/no-loss-of-precision.ts @@ -0,0 +1,53 @@ +import { TSESTree } from '@typescript-eslint/experimental-utils'; +import BaseRule from 'eslint/lib/rules/no-loss-of-precision'; +import * as util from '../util'; + +const baseRule = ((): typeof BaseRule | null => { + try { + return require('eslint/lib/rules/no-loss-of-precision'); + } catch { + /* istanbul ignore next */ + return null; + } +})(); + +type Options = util.InferOptionsTypeFromRule; +type MessageIds = util.InferMessageIdsTypeFromRule; + +export default util.createRule({ + name: 'no-loss-of-precision', + meta: { + type: 'problem', + docs: { + description: 'Disallow literal numbers that lose precision', + category: 'Possible Errors', + recommended: false, + extendsBaseRule: true, + }, + schema: [], + messages: baseRule?.meta.messages ?? { noLossOfPrecision: '' }, + }, + defaultOptions: [], + create(context) { + /* istanbul ignore if */ if (baseRule === null) { + throw new Error( + '@typescript-eslint/no-loss-of-precision requires at least ESLint v7.1.0', + ); + } + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const rules = baseRule!.create(context); + + function isSeperatedNumeric(node: TSESTree.Literal): boolean { + return typeof node.value === 'number' && node.raw.includes('_'); + } + return { + Literal(node: TSESTree.Literal): void { + rules.Literal({ + ...node, + raw: isSeperatedNumeric(node) ? node.raw.replace(/_/g, '') : node.raw, + }); + }, + }; + }, +}); diff --git a/packages/eslint-plugin/tests/rules/no-loss-of-precision.test.ts b/packages/eslint-plugin/tests/rules/no-loss-of-precision.test.ts new file mode 100644 index 000000000000..f2405bacdb6b --- /dev/null +++ b/packages/eslint-plugin/tests/rules/no-loss-of-precision.test.ts @@ -0,0 +1,36 @@ +import rule from '../../src/rules/no-loss-of-precision'; +import { RuleTester } from '../RuleTester'; + +const ruleTester = new RuleTester({ + parser: '@typescript-eslint/parser', +}); + +ruleTester.run('no-loss-of-precision', rule, { + valid: [ + 'const x = 12345;', + 'const x = 123.456;', + 'const x = -123.456;', + 'const x = 123_456;', + 'const x = 123_00_000_000_000_000_000_000_000;', + 'const x = 123.000_000_000_000_000_000_000_0;', + ], + invalid: [ + { + code: 'const x = 9007199254740993;', + errors: [{ messageId: 'noLossOfPrecision' }], + }, + { + code: 'const x = 9_007_199_254_740_993;', + errors: [{ messageId: 'noLossOfPrecision' }], + }, + { + code: 'const x = 9_007_199_254_740.993e3;', + errors: [{ messageId: 'noLossOfPrecision' }], + }, + { + code: + 'const x = 0b100_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_000_001;', + errors: [{ messageId: 'noLossOfPrecision' }], + }, + ], +}); diff --git a/packages/eslint-plugin/typings/eslint-rules.d.ts b/packages/eslint-plugin/typings/eslint-rules.d.ts index 31a752878b88..add5af1c1bbe 100644 --- a/packages/eslint-plugin/typings/eslint-rules.d.ts +++ b/packages/eslint-plugin/typings/eslint-rules.d.ts @@ -702,3 +702,16 @@ declare module 'eslint/lib/rules/dot-notation' { >; export = rule; } + +declare module 'eslint/lib/rules/no-loss-of-precision' { + import { TSESLint, TSESTree } from '@typescript-eslint/experimental-utils'; + + const rule: TSESLint.RuleModule< + 'noLossOfPrecision', + [], + { + Literal(node: TSESTree.Literal): void; + } + >; + export = rule; +} diff --git a/yarn.lock b/yarn.lock index 9b6fedc38d80..337037083ad9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1750,7 +1750,7 @@ acorn@^6.0.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== -acorn@^7.1.0, acorn@^7.1.1: +acorn@^7.1.0, acorn@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe" integrity sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ== @@ -3614,6 +3614,14 @@ eslint-scope@^5.0.0: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-scope@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.0.tgz#d0f971dfe59c69e0cada684b23d49dbf82600ce5" + integrity sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + eslint-utils@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.0.0.tgz#7be1cc70f27a72a76cd14aa698bcabed6890e1cd" @@ -3626,10 +3634,15 @@ eslint-visitor-keys@^1.1.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== -eslint@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.0.0.tgz#c35dfd04a4372110bd78c69a8d79864273919a08" - integrity sha512-qY1cwdOxMONHJfGqw52UOpZDeqXy8xmD0u8CT6jIstil72jkhURC704W8CFyTPDPllz4z4lu0Ql1+07PG/XdIg== +eslint-visitor-keys@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.2.0.tgz#74415ac884874495f78ec2a97349525344c981fa" + integrity sha512-WFb4ihckKil6hu3Dp798xdzSfddwKKU3+nGniKF6HfeW6OLd2OUDEPP7TcHtB5+QXOKg2s6B2DaMPE1Nn/kxKQ== + +eslint@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.2.0.tgz#d41b2e47804b30dbabb093a967fb283d560082e6" + integrity sha512-B3BtEyaDKC5MlfDa2Ha8/D6DsS4fju95zs0hjS3HdGazw+LNayai38A25qMppK37wWGWNYSPOR6oYzlz5MHsRQ== dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.10.0" @@ -3637,10 +3650,10 @@ eslint@^7.0.0: cross-spawn "^7.0.2" debug "^4.0.1" doctrine "^3.0.0" - eslint-scope "^5.0.0" + eslint-scope "^5.1.0" eslint-utils "^2.0.0" - eslint-visitor-keys "^1.1.0" - espree "^7.0.0" + eslint-visitor-keys "^1.2.0" + espree "^7.1.0" esquery "^1.2.0" esutils "^2.0.2" file-entry-cache "^5.0.1" @@ -3668,14 +3681,14 @@ eslint@^7.0.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.0.0.tgz#8a7a60f218e69f120a842dc24c5a88aa7748a74e" - integrity sha512-/r2XEx5Mw4pgKdyb7GNLQNsu++asx/dltf/CI8RFi9oGHxmQFgvLbc5Op4U6i8Oaj+kdslhJtVlEZeAqH5qOTw== +espree@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.1.0.tgz#a9c7f18a752056735bf1ba14cb1b70adc3a5ce1c" + integrity sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw== dependencies: - acorn "^7.1.1" + acorn "^7.2.0" acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.1.0" + eslint-visitor-keys "^1.2.0" esprima@^2.7.0: version "2.7.3" From 4c9293bd5ecfb475bfd4f2240fb6e55186ff3e55 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Tue, 16 Jun 2020 10:20:47 -0700 Subject: [PATCH 03/10] docs: update CONTRIBUTING --- CONTRIBUTING.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9cd07ba705b6..c8a732fc417b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,11 +4,16 @@ Feel free to raise an issue if you have a question, an enhancement, or a bug report. -Please ensure you use the issue search functionality to search all **_opened and closed_** issues before raising a new issue. +Use the issue search functionality to search all **_opened and closed_** issues before raising a new issue. If you raise a duplicate issue, you're just creating noise for everyone watching this repo. + +Before raising a bug, ensure you are using the latest version of our packages. We release every week, so there's a good chance your issue might have already been fixed. + +Finally, when raising a new issue, please fill out the issue template - **_please don't skip sections_**. -When raising a new issue, please fill out the issue template - please don't skip sections. Please provide **_as much information as possible_**. This project is maintained by volunteers, so the more the more information you provide, the less likely we will have to waste everyone's time in asking you for more information. +If you have a particularly complex issue - consider creating a small, self-contained reproduction repo. This will help you in figuring out the exact problem, and will help us in reproducing and diagnosing the bug. + **_Help us to help you_** ## Commenting From 9cca3a9584d5d5ef0536219c5a734f4e87efb543 Mon Sep 17 00:00:00 2001 From: Bogdan Butnaru Date: Fri, 19 Jun 2020 19:38:47 +0200 Subject: [PATCH 04/10] fix(eslint-plugin): [no-base-to-string] handle intersection types (#2170) --- .../src/rules/no-base-to-string.ts | 12 ++++++++++ .../tests/rules/no-base-to-string.test.ts | 24 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/packages/eslint-plugin/src/rules/no-base-to-string.ts b/packages/eslint-plugin/src/rules/no-base-to-string.ts index 34fa2c7d6dc0..b1593c23d8b0 100644 --- a/packages/eslint-plugin/src/rules/no-base-to-string.ts +++ b/packages/eslint-plugin/src/rules/no-base-to-string.ts @@ -112,6 +112,18 @@ export default util.createRule({ return Usefulness.Always; } + if (type.isIntersection()) { + for (const subType of type.types) { + const subtypeUsefulness = collectToStringCertainty(subType); + + if (subtypeUsefulness === Usefulness.Always) { + return Usefulness.Always; + } + } + + return Usefulness.Never; + } + if (!type.isUnion()) { return Usefulness.Never; } diff --git a/packages/eslint-plugin/tests/rules/no-base-to-string.test.ts b/packages/eslint-plugin/tests/rules/no-base-to-string.test.ts index 86babb99ae1f..542097aa9cb6 100644 --- a/packages/eslint-plugin/tests/rules/no-base-to-string.test.ts +++ b/packages/eslint-plugin/tests/rules/no-base-to-string.test.ts @@ -107,6 +107,12 @@ tag\`\${{}}\`; function tag() {} tag\`\${{}}\`; `, + ` + interface Brand {} + function test(v: string & Brand): string { + return \`\${v}\`; + } + `, ], invalid: [ { @@ -217,5 +223,23 @@ tag\`\${{}}\`; }, ], }, + { + code: ` + interface A {} + interface B {} + function test(intersection: A & B): string { + return \`\${intersection}\`; + } + `, + errors: [ + { + data: { + certainty: 'will', + name: 'intersection', + }, + messageId: 'baseToString', + }, + ], + }, ], }); From 89851fab93b7bf954f795f3ec35cd35e98d2031e Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Fri, 19 Jun 2020 11:26:39 -0700 Subject: [PATCH 05/10] chore(eslint-plugin): add a debug log when a type is an "error" any to help with investigations (#2226) --- .eslintrc.js | 10 ++++++++++ packages/eslint-plugin/package.json | 1 + .../eslint-plugin/src/rules/await-thenable.ts | 5 ++--- .../src/rules/no-throw-literal.ts | 3 ++- .../src/rules/no-unnecessary-condition.ts | 20 +++++++++---------- .../rules/restrict-template-expressions.ts | 2 +- .../src/rules/strict-boolean-expressions.ts | 4 ++-- packages/eslint-plugin/src/util/types.ts | 18 ++++++++++++++++- .../eslint-plugin/typings/typescript.d.ts | 7 +++++++ 9 files changed, 52 insertions(+), 18 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 8b4cfa2db36a..2c69c6ecfedf 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -32,6 +32,16 @@ module.exports = { // our plugin :D // + '@typescript-eslint/ban-ts-comment': [ + 'error', + { + 'ts-expect-error': 'allow-with-description', + 'ts-ignore': true, + 'ts-nocheck': true, + 'ts-check': false, + minimumDescriptionLength: 5, + }, + ], '@typescript-eslint/consistent-type-definitions': ['error', 'interface'], '@typescript-eslint/explicit-function-return-type': 'error', '@typescript-eslint/explicit-module-boundary-types': 'off', diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 8ba7451b3889..c1b56bc9f0d8 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -43,6 +43,7 @@ }, "dependencies": { "@typescript-eslint/experimental-utils": "3.3.0", + "debug": "^4.1.1", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.0.0", "semver": "^7.3.2", diff --git a/packages/eslint-plugin/src/rules/await-thenable.ts b/packages/eslint-plugin/src/rules/await-thenable.ts index 78b7ad129393..9858bad8ba2a 100644 --- a/packages/eslint-plugin/src/rules/await-thenable.ts +++ b/packages/eslint-plugin/src/rules/await-thenable.ts @@ -1,5 +1,4 @@ import * as tsutils from 'tsutils'; -import * as ts from 'typescript'; import * as util from '../util'; @@ -30,8 +29,8 @@ export default util.createRule({ const type = checker.getTypeAtLocation(originalNode.expression); if ( - !tsutils.isTypeFlagSet(type, ts.TypeFlags.Any) && - !tsutils.isTypeFlagSet(type, ts.TypeFlags.Unknown) && + !util.isTypeAnyType(type) && + !util.isTypeUnknownType(type) && !tsutils.isThenableType(checker, originalNode.expression, type) ) { context.report({ diff --git a/packages/eslint-plugin/src/rules/no-throw-literal.ts b/packages/eslint-plugin/src/rules/no-throw-literal.ts index b85e0cc742db..67ba9e52ebe5 100644 --- a/packages/eslint-plugin/src/rules/no-throw-literal.ts +++ b/packages/eslint-plugin/src/rules/no-throw-literal.ts @@ -110,7 +110,8 @@ export default util.createRule({ } if ( - type.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown) || + util.isTypeAnyType(type) || + util.isTypeUnknownType(type) || isErrorLike(type) ) { return; diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts b/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts index bed2ac82e55d..1147957a20cb 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts @@ -22,6 +22,8 @@ import { NullThrowsReasons, isMemberOrOptionalMemberExpression, isIdentifier, + isTypeAnyType, + isTypeUnknownType, } from '../util'; // Truthiness utilities @@ -181,13 +183,11 @@ export default createRule({ // Conditional is always necessary if it involves: // `any` or `unknown` or a naked type parameter if ( - unionTypeParts(type).some(part => - isTypeFlagSet( - part, - ts.TypeFlags.Any | - ts.TypeFlags.Unknown | - ts.TypeFlags.TypeParameter, - ), + unionTypeParts(type).some( + part => + isTypeAnyType(part) || + isTypeUnknownType(part) || + isTypeFlagSet(part, ts.TypeFlags.TypeParameter), ) ) { return; @@ -214,7 +214,7 @@ export default createRule({ } const type = getNodeType(node); // Conditional is always necessary if it involves `any` or `unknown` - if (isTypeFlagSet(type, ts.TypeFlags.Any | ts.TypeFlags.Unknown)) { + if (isTypeAnyType(type) || isTypeUnknownType(type)) { return; } const messageId = isTypeFlagSet(type, ts.TypeFlags.Never) @@ -469,8 +469,8 @@ export default createRule({ ? !isNullableOriginFromPrev(node) : true; return ( - isTypeFlagSet(type, ts.TypeFlags.Any) || - isTypeFlagSet(type, ts.TypeFlags.Unknown) || + isTypeAnyType(type) || + isTypeUnknownType(type) || (isNullableType(type, { allowUndefined: true }) && isOwnNullable) ); } diff --git a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts index a3cbb0b6f3bf..a4756266ffca 100644 --- a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts +++ b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts @@ -72,7 +72,7 @@ export default util.createRule({ return true; } - if (options.allowAny && util.isTypeFlagSet(type, ts.TypeFlags.Any)) { + if (options.allowAny && util.isTypeAnyType(type)) { return true; } diff --git a/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts b/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts index df2b59e12ec8..747cbefb7ebe 100644 --- a/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts +++ b/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts @@ -325,8 +325,8 @@ export default util.createRule({ } if ( - types.some(type => - tsutils.isTypeFlagSet(type, ts.TypeFlags.Any | ts.TypeFlags.Unknown), + types.some( + type => util.isTypeAnyType(type) || util.isTypeUnknownType(type), ) ) { variantTypes.add('any'); diff --git a/packages/eslint-plugin/src/util/types.ts b/packages/eslint-plugin/src/util/types.ts index 08a67cd7e5d9..2bd7e1997392 100644 --- a/packages/eslint-plugin/src/util/types.ts +++ b/packages/eslint-plugin/src/util/types.ts @@ -1,3 +1,4 @@ +import debug from 'debug'; import { isCallExpression, isJsxExpression, @@ -13,6 +14,8 @@ import { } from 'tsutils'; import * as ts from 'typescript'; +const log = debug('typescript-eslint:eslint-plugin:utils:types'); + /** * Checks if the given type is either an array type, * or a union made up solely of array types. @@ -326,11 +329,24 @@ export function getTypeArguments( return type.typeArguments ?? []; } +/** + * @returns true if the type is `unknown` + */ +export function isTypeUnknownType(type: ts.Type): boolean { + return isTypeFlagSet(type, ts.TypeFlags.Unknown); +} + /** * @returns true if the type is `any` */ export function isTypeAnyType(type: ts.Type): boolean { - return isTypeFlagSet(type, ts.TypeFlags.Any); + if (isTypeFlagSet(type, ts.TypeFlags.Any)) { + if (type.intrinsicName === 'error') { + log('Found an "error" any type'); + } + return true; + } + return false; } /** diff --git a/packages/eslint-plugin/typings/typescript.d.ts b/packages/eslint-plugin/typings/typescript.d.ts index 7c9089158b4b..73304155ee74 100644 --- a/packages/eslint-plugin/typings/typescript.d.ts +++ b/packages/eslint-plugin/typings/typescript.d.ts @@ -23,4 +23,11 @@ declare module 'typescript' { */ getTypeOfPropertyOfType(type: Type, propertyName: string): Type | undefined; } + + interface Type { + /** + * If the type is `any`, and this is set to "error", then TS was unable to resolve the type + */ + intrinsicName?: string; + } } From f5c271f69a2953ca71edc07f66cc0e174e538433 Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Fri, 19 Jun 2020 13:06:16 -0700 Subject: [PATCH 06/10] docs: update readmes and regen contributors (#2227) --- .all-contributorsrc | 151 +++++++++++++++++----- CONTRIBUTORS.md | 86 +++++++----- README.md | 4 +- docs/getting-started/linting/README.md | 9 +- packages/eslint-plugin-internal/README.md | 10 +- packages/eslint-plugin-tslint/README.md | 4 +- packages/eslint-plugin/README.md | 20 ++- packages/experimental-utils/README.md | 12 +- packages/parser/README.md | 11 +- packages/shared-fixtures/README.md | 7 + packages/typescript-estree/README.md | 8 +- tools/generate-contributors.ts | 1 + 12 files changed, 224 insertions(+), 99 deletions(-) create mode 100644 packages/shared-fixtures/README.md diff --git a/.all-contributorsrc b/.all-contributorsrc index bdd6f75d8c99..55cf18e201b1 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -16,6 +16,13 @@ "profile": "https://github.com/JamesHenry", "contributions": [] }, + { + "login": "bradzacher", + "name": "Brad Zacher", + "avatar_url": "https://avatars1.githubusercontent.com/u/7462525?v=4", + "profile": "https://github.com/bradzacher", + "contributions": [] + }, { "login": "armano2", "name": "Armano", @@ -24,10 +31,10 @@ "contributions": [] }, { - "login": "bradzacher", - "name": "Brad Zacher", - "avatar_url": "https://avatars1.githubusercontent.com/u/7462525?v=4", - "profile": "https://github.com/bradzacher", + "login": "a-tarasyuk", + "name": "Alexander T.", + "avatar_url": "https://avatars0.githubusercontent.com/u/509265?v=4", + "profile": "https://github.com/a-tarasyuk", "contributions": [] }, { @@ -44,6 +51,13 @@ "profile": "https://github.com/weirdpattern", "contributions": [] }, + { + "login": "G-Rath", + "name": "Gareth Jones", + "avatar_url": "https://avatars2.githubusercontent.com/u/3151613?v=4", + "profile": "https://github.com/G-Rath", + "contributions": [] + }, { "login": "nzakas", "name": "Nicholas C. Zakas", @@ -58,13 +72,6 @@ "profile": "https://github.com/j-f1", "contributions": [] }, - { - "login": "a-tarasyuk", - "name": "Alexander T.", - "avatar_url": "https://avatars0.githubusercontent.com/u/509265?v=4", - "profile": "https://github.com/a-tarasyuk", - "contributions": [] - }, { "login": "uniqueiniquity", "name": "Ben Lichtman", @@ -72,6 +79,13 @@ "profile": "https://github.com/uniqueiniquity", "contributions": [] }, + { + "login": "JoshuaKGoldberg", + "name": "Josh Goldberg", + "avatar_url": "https://avatars1.githubusercontent.com/u/3335181?v=4", + "profile": "https://github.com/JoshuaKGoldberg", + "contributions": [] + }, { "login": "scottohara", "name": "Scott O'Hara", @@ -80,10 +94,10 @@ "contributions": [] }, { - "login": "JoshuaKGoldberg", - "name": "Josh Goldberg", - "avatar_url": "https://avatars1.githubusercontent.com/u/3335181?v=4", - "profile": "https://github.com/JoshuaKGoldberg", + "login": "Retsam", + "name": "Retsam", + "avatar_url": "https://avatars0.githubusercontent.com/u/2281166?v=4", + "profile": "https://github.com/Retsam", "contributions": [] }, { @@ -114,6 +128,13 @@ "profile": "https://github.com/azz", "contributions": [] }, + { + "login": "yeonjuan", + "name": "YeonJuan", + "avatar_url": "https://avatars3.githubusercontent.com/u/41323220?v=4", + "profile": "https://github.com/yeonjuan", + "contributions": [] + }, { "login": "dannyfritz", "name": "Danny Fritz", @@ -135,6 +156,13 @@ "profile": "https://github.com/macklinu", "contributions": [] }, + { + "login": "phaux", + "name": "Nikita Stefaniak", + "avatar_url": "https://avatars1.githubusercontent.com/u/1270987?v=4", + "profile": "https://github.com/phaux", + "contributions": [] + }, { "login": "lukyth", "name": "Kanitkorn Sujautra", @@ -142,6 +170,13 @@ "profile": "https://github.com/lukyth", "contributions": [] }, + { + "login": "anikethsaha", + "name": "Anix", + "avatar_url": "https://avatars1.githubusercontent.com/u/26347874?v=4", + "profile": "https://github.com/anikethsaha", + "contributions": [] + }, { "login": "ldrick", "name": "Ricky Lippmann", @@ -156,6 +191,13 @@ "profile": "https://github.com/SimenB", "contributions": [] }, + { + "login": "vapurrmaid", + "name": "G r e y", + "avatar_url": "https://avatars0.githubusercontent.com/u/11184711?v=4", + "profile": "https://github.com/vapurrmaid", + "contributions": [] + }, { "login": "gavinbarron", "name": "Gavin Barron", @@ -177,6 +219,20 @@ "profile": "https://github.com/duailibe", "contributions": [] }, + { + "login": "Validark", + "name": "Niles", + "avatar_url": "https://avatars2.githubusercontent.com/u/15217173?v=4", + "profile": "https://github.com/Validark", + "contributions": [] + }, + { + "login": "pablobirukov", + "name": "Pavel Birukov ", + "avatar_url": "https://avatars2.githubusercontent.com/u/1861546?v=4", + "profile": "https://github.com/pablobirukov", + "contributions": [] + }, { "login": "octogonz", "name": "Pete Gonzalez", @@ -184,13 +240,6 @@ "profile": "https://github.com/octogonz", "contributions": [] }, - { - "login": "Retsam", - "name": "Retsam", - "avatar_url": "https://avatars0.githubusercontent.com/u/2281166?v=4", - "profile": "https://github.com/Retsam", - "contributions": [] - }, { "login": "mightyiam", "name": "Shahar Dawn Or", @@ -198,6 +247,20 @@ "profile": "https://github.com/mightyiam", "contributions": [] }, + { + "login": "sosukesuzuki", + "name": "Sosuke Suzuki", + "avatar_url": "https://avatars1.githubusercontent.com/u/14838850?v=4", + "profile": "https://github.com/sosukesuzuki", + "contributions": [] + }, + { + "login": "ulrichb", + "name": "ulrichb", + "avatar_url": "https://avatars3.githubusercontent.com/u/388796?v=4", + "profile": "https://github.com/ulrichb", + "contributions": [] + }, { "login": "webschik", "name": "Denys Kniazevych", @@ -206,17 +269,24 @@ "contributions": [] }, { - "login": "Validark", - "name": "Niles", - "avatar_url": "https://avatars2.githubusercontent.com/u/15217173?v=4", - "profile": "https://github.com/Validark", + "login": "dimitropoulos", + "name": "Dimitri Mitropoulos", + "avatar_url": "https://avatars2.githubusercontent.com/u/15232461?v=4", + "profile": "https://github.com/dimitropoulos", "contributions": [] }, { - "login": "pablobirukov", - "name": "Pavel Birukov ", - "avatar_url": "https://avatars2.githubusercontent.com/u/1861546?v=4", - "profile": "https://github.com/pablobirukov", + "login": "nevir", + "name": "Ian MacLeod", + "avatar_url": "https://avatars1.githubusercontent.com/u/41373?v=4", + "profile": "https://github.com/nevir", + "contributions": [] + }, + { + "login": "jonathanrdelgado", + "name": "Jonathan Delgado", + "avatar_url": "https://avatars2.githubusercontent.com/u/1841149?v=4", + "profile": "https://github.com/jonathanrdelgado", "contributions": [] }, { @@ -233,6 +303,13 @@ "profile": "https://github.com/g-plane", "contributions": [] }, + { + "login": "susisu", + "name": "Susisu", + "avatar_url": "https://avatars0.githubusercontent.com/u/2443491?v=4", + "profile": "https://github.com/susisu", + "contributions": [] + }, { "login": "ThomasdenH", "name": "Thomas den Hollander", @@ -240,12 +317,26 @@ "profile": "https://github.com/ThomasdenH", "contributions": [] }, + { + "login": "timkraut", + "name": "Tim Kraut", + "avatar_url": "https://avatars2.githubusercontent.com/u/509669?v=4", + "profile": "https://github.com/timkraut", + "contributions": [] + }, { "login": "madbence", "name": "Bence Dányi", "avatar_url": "https://avatars2.githubusercontent.com/u/296735?v=4", "profile": "https://github.com/madbence", "contributions": [] + }, + { + "login": "dependabot[bot]", + "name": "dependabot[bot]", + "avatar_url": "https://avatars0.githubusercontent.com/in/29110?v=4", + "profile": "https://github.com/apps/dependabot", + "contributions": [] } ], "contributorsPerLine": 5 diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 04023618bf81..23094e083494 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -7,52 +7,70 @@ Thanks goes to these wonderful people ([emoji key](https://github.com/all-contri - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - - + + + + + - - - - + + + + + + + + + + + + + + + + + + + + + +
James Henry
James Henry

Armano
Armano

Brad Zacher
Brad Zacher

Reyad Attiyat
Reyad Attiyat

Patricio Trevino
Patricio Trevino


James Henry


Brad Zacher


Armano


Alexander T.


Reyad Attiyat

Nicholas C. Zakas
Nicholas C. Zakas

Jed Fox
Jed Fox

Alexander T.
Alexander T.

Ben Lichtman
Ben Lichtman

Scott O'Hara
Scott O'Hara


Patricio Trevino


Gareth Jones


Nicholas C. Zakas


Jed Fox


Ben Lichtman

Josh Goldberg
Josh Goldberg

Kai Cataldo
Kai Cataldo

Rasmus Eneman
Rasmus Eneman

Toru Nagashima
Toru Nagashima

Lucas Azzola
Lucas Azzola


Josh Goldberg


Scott O'Hara


Retsam


Kai Cataldo


Rasmus Eneman

Danny Fritz
Danny Fritz

Ika
Ika

mackie
mackie

Kanitkorn Sujautra
Kanitkorn Sujautra

Ricky Lippmann
Ricky Lippmann


Toru Nagashima


Lucas Azzola


YeonJuan


Danny Fritz


Ika

Simen Bekkhus
Simen Bekkhus

Gavin Barron
Gavin Barron

Kevin Partington
Kevin Partington

Lucas Duailibe
Lucas Duailibe

Pete Gonzalez
Pete Gonzalez


mackie


Nikita Stefaniak


Kanitkorn Sujautra


Anix


Ricky Lippmann

Retsam
Retsam

Shahar Dawn Or
Shahar Dawn Or

Denys Kniazevych
Denys Kniazevych

Niles
Niles

Pavel Birukov
Pavel Birukov


Simen Bekkhus


G r e y


Gavin Barron


Kevin Partington


Lucas Duailibe

Philipp A.
Philipp A.

Pig Fang
Pig Fang

Thomas den Hollander
Thomas den Hollander

Bence Dányi
Bence Dányi


Niles


Pavel Birukov


Pete Gonzalez


Shahar Dawn Or


Sosuke Suzuki


ulrichb


Denys Kniazevych


Dimitri Mitropoulos


Ian MacLeod


Jonathan Delgado


Philipp A.


Pig Fang


Susisu


Thomas den Hollander


Tim Kraut


Bence Dányi

diff --git a/README.md b/README.md index 89922b3a685f..d327f2d355b2 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,10 @@

Monorepo for all the tooling which enables ESLint to support TypeScript

- GitHub Workflow Status + CI Financial Contributors on Open Collective - GitHub license NPM Downloads Codecov - Commitizen friendly


diff --git a/docs/getting-started/linting/README.md b/docs/getting-started/linting/README.md index f62888df0b73..6abe587e3a32 100644 --- a/docs/getting-started/linting/README.md +++ b/docs/getting-started/linting/README.md @@ -7,13 +7,8 @@ Whether you're adding linting to a new TypeScript codebase, adding TypeScript to First step is to make sure you've got the required packages installed: ```bash -$ yarn add -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin -``` - -or with NPM: - -```bash -$ npm i --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin +$ yarn add -D eslint typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin +$ npm i --save-dev eslint typescript @typescript-eslint/parser @typescript-eslint/eslint-plugin ``` ## Configuration diff --git a/packages/eslint-plugin-internal/README.md b/packages/eslint-plugin-internal/README.md index bf6ed0bbe384..adf369999286 100644 --- a/packages/eslint-plugin-internal/README.md +++ b/packages/eslint-plugin-internal/README.md @@ -1,5 +1,9 @@ -# `eslint-plugin-internal` +

Internal ESLint Plugin

-This is just a collection of internal lint rules to help enforce some guidelines specific to this repository. +

An ESLint plugin used internally in this project to ensure consistency.

-These are not intended to be used externally. +

+ CI +

+ +This plugin is not intended to be used externally. diff --git a/packages/eslint-plugin-tslint/README.md b/packages/eslint-plugin-tslint/README.md index f8a7f4f3e58a..021b8780bfbd 100644 --- a/packages/eslint-plugin-tslint/README.md +++ b/packages/eslint-plugin-tslint/README.md @@ -3,11 +3,9 @@

ESLint plugin wraps a TSLint configuration and lints the whole source using TSLint.

- Azure Pipelines - GitHub license + CI NPM Version NPM Downloads - Commitizen friendly

## Installation diff --git a/packages/eslint-plugin/README.md b/packages/eslint-plugin/README.md index cc2bbc078996..5f9822ed12f4 100644 --- a/packages/eslint-plugin/README.md +++ b/packages/eslint-plugin/README.md @@ -1,11 +1,11 @@

ESLint Plugin TypeScript

+

An ESLint plugin which provides lint rules for TypeScript codebases.

+

- Azure Pipelines - GitHub license + CI NPM Version NPM Downloads - Commitizen friendly

## Getting Started @@ -19,10 +19,18 @@ These docs walk you through setting up ESLint, this plugin, and our parser. If y ### Installation -Make sure you have TypeScript and [`@typescript-eslint/parser`](../parser) installed, then install the plugin: +Make sure you have TypeScript and [`@typescript-eslint/parser`](../parser) installed: + +```bash +$ yarn add -D typescript @typescript-eslint/parser +$ npm i --save-dev typescript @typescript-eslint/parser +``` + +Then install the plugin: -```sh -yarn add -D @typescript-eslint/eslint-plugin +```bash +$ yarn add -D @typescript-eslint/eslint-plugin +$ npm i --save-dev @typescript-eslint/eslint-plugin ``` It is important that you use the same version number for `@typescript-eslint/parser` and `@typescript-eslint/eslint-plugin`. diff --git a/packages/experimental-utils/README.md b/packages/experimental-utils/README.md index cba85c84d6e4..05f65ecb7da9 100644 --- a/packages/experimental-utils/README.md +++ b/packages/experimental-utils/README.md @@ -1,6 +1,12 @@ -# `@typescript-eslint/experimental-utils` +

Utils for ESLint Plugins

-(Experimental) Utilities for working with TypeScript + ESLint together. +

Utilities for working with TypeScript + ESLint together.

+ +

+ CI + NPM Version + NPM Downloads +

## Note @@ -10,7 +16,7 @@ i.e. treat it as a `0.x.y` package. Feel free to use it now, and let us know what utilities you need or send us PRs with utilities you build on top of it. -Once it is stable, it will be renamed to `@typescript-eslint/util` for a `3.0.0` release. +Once it is stable, it will be renamed to `@typescript-eslint/util` for a `4.0.0` release. ## Exports diff --git a/packages/parser/README.md b/packages/parser/README.md index 594f89dd6c29..02bb09e561a8 100644 --- a/packages/parser/README.md +++ b/packages/parser/README.md @@ -1,13 +1,11 @@

TypeScript ESLint Parser

-

An ESLint custom parser which leverages TypeScript ESTree to allow for ESLint to lint TypeScript source code.

+

An ESLint parser which leverages TypeScript ESTree to allow for ESLint to lint TypeScript source code.

- Azure Pipelines - GitHub license + CI NPM Version NPM Downloads - Commitizen friendly

## Getting Started @@ -20,8 +18,9 @@ These docs walk you through setting up ESLint, this parser, and our plugin. If y ### Installation -```sh -yarn add -D @typescript-eslint/parser +```bash +$ yarn add -D typescript @typescript-eslint/parser +$ npm i --save-dev typescript @typescript-eslint/parser ``` ### Usage diff --git a/packages/shared-fixtures/README.md b/packages/shared-fixtures/README.md new file mode 100644 index 000000000000..866a6e866149 --- /dev/null +++ b/packages/shared-fixtures/README.md @@ -0,0 +1,7 @@ +

Fixtures for Testing typescript-eslint

+ +

Code fixtures used to test the parser. This is not intended for external use.

+ +

+ CI +

diff --git a/packages/typescript-estree/README.md b/packages/typescript-estree/README.md index 5ab7fe44a7b9..eafb1463d530 100644 --- a/packages/typescript-estree/README.md +++ b/packages/typescript-estree/README.md @@ -3,14 +3,14 @@

A parser that converts TypeScript source code into an ESTree-compatible form

- Azure Pipelines - GitHub license + CI NPM Version NPM Downloads - Commitizen friendly

-
+## Getting Started + +**[You can find our Getting Started docs here](../../docs/getting-started/linting/README.md)** ## About diff --git a/tools/generate-contributors.ts b/tools/generate-contributors.ts index 4c3c2b0a36d4..38c3690cb0a4 100644 --- a/tools/generate-contributors.ts +++ b/tools/generate-contributors.ts @@ -7,6 +7,7 @@ import 'isomorphic-fetch'; import * as path from 'path'; const IGNORED_USERS = new Set([ + 'dependabot[bot]', 'eslint[bot]', 'greenkeeper[bot]', 'semantic-release-bot', From c3753c21768d355ecdb9e7ae8e0bfdfbbc1d3bbe Mon Sep 17 00:00:00 2001 From: YeonJuan Date: Sun, 21 Jun 2020 04:54:34 +0900 Subject: [PATCH 07/10] fix(eslint-plugin): [unbound-method] handling destructuring (#2228) --- .../eslint-plugin/src/rules/unbound-method.ts | 46 +++++- .../tests/rules/unbound-method.test.ts | 141 +++++++++++++++++- 2 files changed, 183 insertions(+), 4 deletions(-) diff --git a/packages/eslint-plugin/src/rules/unbound-method.ts b/packages/eslint-plugin/src/rules/unbound-method.ts index ade042298875..e8217348a4a6 100644 --- a/packages/eslint-plugin/src/rules/unbound-method.ts +++ b/packages/eslint-plugin/src/rules/unbound-method.ts @@ -99,7 +99,7 @@ const nativelyBoundMembers = SUPPORTED_GLOBALS.map(namespace => { .reduce((arr, names) => arr.concat(names), []) .filter(name => !nativelyNotBoundMembers.has(name)); -const isMemberNotImported = ( +const isNotImported = ( symbol: ts.Symbol, currentSourceFile: ts.SourceFile | undefined, ): boolean => { @@ -176,7 +176,7 @@ export default util.createRule({ if ( objectSymbol && nativelyBoundMembers.includes(getMemberFullName(node)) && - isMemberNotImported(objectSymbol, currentSourceFile) + isNotImported(objectSymbol, currentSourceFile) ) { return; } @@ -191,6 +191,48 @@ export default util.createRule({ }); } }, + 'VariableDeclarator, AssignmentExpression'( + node: TSESTree.VariableDeclarator | TSESTree.AssignmentExpression, + ): void { + const [idNode, initNode] = + node.type === AST_NODE_TYPES.VariableDeclarator + ? [node.id, node.init] + : [node.left, node.right]; + + if (initNode && idNode.type === AST_NODE_TYPES.ObjectPattern) { + const tsNode = parserServices.esTreeNodeToTSNodeMap.get(initNode); + const rightSymbol = checker.getSymbolAtLocation(tsNode); + const initTypes = checker.getTypeAtLocation(tsNode); + + const notImported = + rightSymbol && isNotImported(rightSymbol, currentSourceFile); + + idNode.properties.forEach(property => { + if ( + property.type === AST_NODE_TYPES.Property && + property.key.type === AST_NODE_TYPES.Identifier + ) { + if ( + notImported && + util.isIdentifier(initNode) && + nativelyBoundMembers.includes( + `${initNode.name}.${property.key.name}`, + ) + ) { + return; + } + + const symbol = initTypes.getProperty(property.key.name); + if (symbol && isDangerousMethod(symbol, ignoreStatic)) { + context.report({ + messageId: 'unbound', + node, + }); + } + } + }); + } + }, }; }, }); diff --git a/packages/eslint-plugin/tests/rules/unbound-method.test.ts b/packages/eslint-plugin/tests/rules/unbound-method.test.ts index 12d6486e09f5..4c0cb8f58d36 100644 --- a/packages/eslint-plugin/tests/rules/unbound-method.test.ts +++ b/packages/eslint-plugin/tests/rules/unbound-method.test.ts @@ -228,6 +228,35 @@ class A { } } `, + 'const { parseInt } = Number;', + 'const { log } = console;', + ` +let parseInt; +({ parseInt } = Number); + `, + ` +let log; +({ log } = console); + `, + ` +const foo = { + bar: 'bar', +}; +const { bar } = foo; + `, + ` +class Foo { + unbnound() {} + bar = 4; +} +const { bar } = new Foo(); + `, + ` +class Foo { + bound = () => 'foo'; +} +const { bound } = new Foo(); + `, ], invalid: [ { @@ -288,8 +317,8 @@ function foo(arg: ContainsMethods | null) { 'const unbound = instance.unbound;', 'const unboundStatic = ContainsMethods.unboundStatic;', - 'const { unbound } = instance.unbound;', - 'const { unboundStatic } = ContainsMethods.unboundStatic;', + 'const { unbound } = instance;', + 'const { unboundStatic } = ContainsMethods;', 'instance.unbound;', 'instance.unbound as any;', @@ -384,5 +413,113 @@ const unbound = new Foo().unbound; }, ], }, + { + code: ` +class Foo { + unbound() {} +} +const { unbound } = new Foo(); + `, + errors: [ + { + line: 5, + messageId: 'unbound', + }, + ], + }, + { + code: ` +class Foo { + unbound = function () {}; +} +const { unbound } = new Foo(); + `, + errors: [ + { + line: 5, + messageId: 'unbound', + }, + ], + }, + { + code: ` +class Foo { + unbound() {} +} +let unbound; +({ unbound } = new Foo()); + `, + errors: [ + { + line: 6, + messageId: 'unbound', + }, + ], + }, + { + code: ` +class Foo { + unbound = function () {}; +} +let unbound; +({ unbound } = new Foo()); + `, + errors: [ + { + line: 6, + messageId: 'unbound', + }, + ], + }, + { + code: ` +class CommunicationError { + foo() {} +} +const { foo } = CommunicationError.prototype; + `, + errors: [ + { + line: 5, + messageId: 'unbound', + }, + ], + }, + { + code: ` +class CommunicationError { + foo() {} +} +let foo; +({ foo } = CommunicationError.prototype); + `, + errors: [ + { + line: 6, + messageId: 'unbound', + }, + ], + }, + { + code: ` +import { console } from './class'; +const { log } = console; + `, + errors: [ + { + line: 3, + messageId: 'unbound', + }, + ], + }, + { + code: 'const { all } = Promise;', + errors: [ + { + line: 1, + messageId: 'unbound', + }, + ], + }, ], }); From c0b3057b7f7d515891ad2efe32e4ef8c01e0478f Mon Sep 17 00:00:00 2001 From: zachkirsch Date: Sat, 20 Jun 2020 16:28:14 -0400 Subject: [PATCH 08/10] feat(eslint-plugin): [no-unnecessary-boolean-literal-compare] add option to check nullable booleans (#1983) --- .../no-unnecessary-boolean-literal-compare.md | 93 ++++++++ .../no-unnecessary-boolean-literal-compare.ts | 207 +++++++++++++++--- packages/eslint-plugin/src/util/types.ts | 2 +- ...nnecessary-boolean-literal-compare.test.ts | 122 ++++++++++- 4 files changed, 395 insertions(+), 29 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/no-unnecessary-boolean-literal-compare.md b/packages/eslint-plugin/docs/rules/no-unnecessary-boolean-literal-compare.md index 81b4a5c67f6e..d600bb7930c0 100644 --- a/packages/eslint-plugin/docs/rules/no-unnecessary-boolean-literal-compare.md +++ b/packages/eslint-plugin/docs/rules/no-unnecessary-boolean-literal-compare.md @@ -8,6 +8,12 @@ This rule ensures that you do not include unnecessary comparisons with boolean l A comparison is considered unnecessary if it checks a boolean literal against any variable with just the `boolean` type. A comparison is **_not_** considered unnecessary if the type is a union of booleans (`string | boolean`, `someObject | boolean`). +**Note**: Throughout this page, only strict equality (`===` and `!==`) are +used in the examples. However, the implementation of the rule does not +distinguish between strict and loose equality. Any example below that uses +`===` would be treated the same way if `==` was used, and any example below +that uses `!==` would be treated the same way if `!=` was used. + Examples of **incorrect** code for this rule: ```ts @@ -30,12 +36,99 @@ if (someObjectBoolean === true) { declare const someStringBoolean: boolean | string; if (someStringBoolean === true) { } +``` + +## Options + +The rule accepts an options object with the following properties. + +```ts +type Options = { + // if false, comparisons between a nullable boolean variable to `true` will be checked and fixed + allowComparingNullableBooleansToTrue?: boolean; + // if false, comparisons between a nullable boolean variable to `false` will be checked and fixed + allowComparingNullableBooleansToFalse?: boolean; +}; +``` + +### Defaults + +This rule always checks comparisons between a boolean variable and a boolean +literal. Comparisons between nullable boolean variables and boolean literals +are **not** checked by default. + +```ts +const defaults = { + allowComparingNullableBooleansToTrue: true, + allowComparingNullableBooleansToFalse: true, +}; +``` + +### `allowComparingNullableBooleansToTrue` + +Examples of **incorrect** code for this rule with `{ allowComparingNullableBooleansToTrue: false }`: + +```ts +declare const someUndefinedCondition: boolean | undefined; +if (someUndefinedCondition === true) { +} + +declare const someNullCondition: boolean | null; +if (someNullCondition !== true) { +} +``` + +Examples of **correct** code for this rule with `{ allowComparingNullableBooleansToTrue: false }`: + +```ts +declare const someUndefinedCondition: boolean | undefined; +if (someUndefinedCondition) { +} +declare const someNullCondition: boolean | null; +if (!someNullCondition) { +} +``` + +### `allowComparingNullableBooleansToFalse` + +Examples of **incorrect** code for this rule with `{ allowComparingNullableBooleansToFalse: false }`: + +```ts declare const someUndefinedCondition: boolean | undefined; if (someUndefinedCondition === false) { } + +declare const someNullCondition: boolean | null; +if (someNullCondition !== false) { +} ``` +Examples of **correct** code for this rule with `{ allowComparingNullableBooleansToFalse: false }`: + +```ts +declare const someUndefinedCondition: boolean | undefined; +if (someUndefinedCondition ?? true) { +} + +declare const someNullCondition: boolean | null; +if (!(someNullCondition ?? true)) { +} +``` + +## Fixer + +| Comparison | Fixer Output | Notes | +| :----------------------------: | ------------------------------- | ----------------------------------------------------------------------------------- | +| `booleanVar === true` | `booleanLiteral` | | +| `booleanVar !== true` | `!booleanLiteral` | | +| `booleanVar === false` | `!booleanLiteral` | | +| `booleanVar !== false` | `booleanLiteral` | | +| `nullableBooleanVar === true` | `nullableBooleanVar` | Only checked/fixed if the `allowComparingNullableBooleansToTrue` option is `false` | +| `nullableBooleanVar !== true` | `!nullableBooleanVar` | Only checked/fixed if the `allowComparingNullableBooleansToTrue` option is `false` | +| `nullableBooleanVar === false` | `nullableBooleanVar ?? true` | Only checked/fixed if the `allowComparingNullableBooleansToFalse` option is `false` | +| `nullableBooleanVar !== false` | `!(nullableBooleanVar ?? true)` | Only checked/fixed if the `allowComparingNullableBooleansToFalse` option is `false` | + ## Related to - TSLint: [no-boolean-literal-compare](https://palantir.github.io/tslint/rules/no-boolean-literal-compare) diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-boolean-literal-compare.ts b/packages/eslint-plugin/src/rules/no-unnecessary-boolean-literal-compare.ts index ffcdd0e07320..fe1fd24cc4f1 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-boolean-literal-compare.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-boolean-literal-compare.ts @@ -6,16 +6,33 @@ import * as tsutils from 'tsutils'; import * as ts from 'typescript'; import * as util from '../util'; -type MessageIds = 'direct' | 'negated'; +type MessageIds = + | 'direct' + | 'negated' + | 'comparingNullableToTrueDirect' + | 'comparingNullableToTrueNegated' + | 'comparingNullableToFalse'; + +type Options = [ + { + allowComparingNullableBooleansToTrue?: boolean; + allowComparingNullableBooleansToFalse?: boolean; + }, +]; interface BooleanComparison { expression: TSESTree.Expression; + literalBooleanInComparison: boolean; forTruthy: boolean; negated: boolean; range: [number, number]; } -export default util.createRule<[], MessageIds>({ +interface BooleanComparisonWithTypeInformation extends BooleanComparison { + expressionIsNullableBoolean: boolean; +} + +export default util.createRule({ name: 'no-unnecessary-boolean-literal-compare', meta: { docs: { @@ -31,18 +48,42 @@ export default util.createRule<[], MessageIds>({ 'This expression unnecessarily compares a boolean value to a boolean instead of using it directly.', negated: 'This expression unnecessarily compares a boolean value to a boolean instead of negating it.', + comparingNullableToTrueDirect: + 'This expression unnecessarily compares a nullable boolean value to true instead of using it directly.', + comparingNullableToTrueNegated: + 'This expression unnecessarily compares a nullable boolean value to true instead of negating it.', + comparingNullableToFalse: + 'This expression unnecessarily compares a nullable boolean value to false instead of using the ?? operator to provide a default.', }, - schema: [], + schema: [ + { + type: 'object', + properties: { + allowComparingNullableBooleansToTrue: { + type: 'boolean', + }, + allowComparingNullableBooleansToFalse: { + type: 'boolean', + }, + }, + additionalProperties: false, + }, + ], type: 'suggestion', }, - defaultOptions: [], - create(context) { + defaultOptions: [ + { + allowComparingNullableBooleansToTrue: true, + allowComparingNullableBooleansToFalse: true, + }, + ], + create(context, [options]) { const parserServices = util.getParserServices(context); const checker = parserServices.program.getTypeChecker(); function getBooleanComparison( node: TSESTree.BinaryExpression, - ): BooleanComparison | undefined { + ): BooleanComparisonWithTypeInformation | undefined { const comparison = deconstructComparison(node); if (!comparison) { return undefined; @@ -52,16 +93,67 @@ export default util.createRule<[], MessageIds>({ parserServices.esTreeNodeToTSNodeMap.get(comparison.expression), ); - if ( - !tsutils.isTypeFlagSet( - expressionType, - ts.TypeFlags.Boolean | ts.TypeFlags.BooleanLiteral, - ) - ) { - return undefined; + if (isBooleanType(expressionType)) { + return { + ...comparison, + expressionIsNullableBoolean: false, + }; + } + + if (isNullableBoolean(expressionType)) { + return { + ...comparison, + expressionIsNullableBoolean: true, + }; } - return comparison; + return undefined; + } + + function isBooleanType(expressionType: ts.Type): boolean { + return tsutils.isTypeFlagSet( + expressionType, + ts.TypeFlags.Boolean | ts.TypeFlags.BooleanLiteral, + ); + } + + /** + * checks if the expressionType is a union that + * 1) contains at least one nullish type (null or undefined) + * 2) contains at least once boolean type (true or false or boolean) + * 3) does not contain any types besides nullish and boolean types + */ + function isNullableBoolean(expressionType: ts.Type): boolean { + if (!expressionType.isUnion()) { + return false; + } + + const { types } = expressionType; + + const nonNullishTypes = types.filter( + type => + !tsutils.isTypeFlagSet( + type, + ts.TypeFlags.Undefined | ts.TypeFlags.Null, + ), + ); + + const hasNonNullishType = nonNullishTypes.length > 0; + if (!hasNonNullishType) { + return false; + } + + const hasNullableType = nonNullishTypes.length < types.length; + if (!hasNullableType) { + return false; + } + + const allNonNullishTypesAreBoolean = nonNullishTypes.every(isBooleanType); + if (!allNonNullishTypesAreBoolean) { + return false; + } + + return true; } function deconstructComparison( @@ -83,11 +175,12 @@ export default util.createRule<[], MessageIds>({ continue; } - const { value } = against; - const negated = node.operator.startsWith('!'); + const { value: literalBooleanInComparison } = against; + const negated = !comparisonType.isPositive; return { - forTruthy: value ? !negated : negated, + literalBooleanInComparison, + forTruthy: literalBooleanInComparison ? !negated : negated, expression, negated, range: @@ -100,23 +193,85 @@ export default util.createRule<[], MessageIds>({ return undefined; } + function nodeIsUnaryNegation(node: TSESTree.Node): boolean { + return ( + node.type === AST_NODE_TYPES.UnaryExpression && + node.prefix && + node.operator === '!' + ); + } + return { BinaryExpression(node): void { const comparison = getBooleanComparison(node); + if (comparison === undefined) { + return; + } - if (comparison) { - context.report({ - fix: function* (fixer) { - yield fixer.removeRange(comparison.range); + if (comparison.expressionIsNullableBoolean) { + if ( + comparison.literalBooleanInComparison && + options.allowComparingNullableBooleansToTrue + ) { + return; + } + if ( + !comparison.literalBooleanInComparison && + options.allowComparingNullableBooleansToFalse + ) { + return; + } + } + context.report({ + fix: function* (fixer) { + yield fixer.removeRange(comparison.range); + + // if the expression `exp` isn't nullable, or we're comparing to `true`, + // we can just replace the entire comparison with `exp` or `!exp` + if ( + !comparison.expressionIsNullableBoolean || + comparison.literalBooleanInComparison + ) { if (!comparison.forTruthy) { yield fixer.insertTextBefore(node, '!'); } - }, - messageId: comparison.negated ? 'negated' : 'direct', - node, - }); - } + return; + } + + // if we're here, then the expression is a nullable boolean and we're + // comparing to a literal `false` + + // if we're doing `== false` or `=== false`, then we need to negate the expression + if (!comparison.negated) { + const { parent } = node; + // if the parent is a negation, we can instead just get rid of the parent's negation. + // i.e. instead of resulting in `!(!(exp))`, we can just result in `exp` + if (parent != null && nodeIsUnaryNegation(parent)) { + // remove from the beginning of the parent to the beginning of this node + yield fixer.removeRange([parent.range[0], node.range[0]]); + // remove from the end of the node to the end of the parent + yield fixer.removeRange([node.range[1], parent.range[1]]); + } else { + yield fixer.insertTextBefore(node, '!'); + } + } + + // provide the default `true` + yield fixer.insertTextBefore(node, '('); + yield fixer.insertTextAfter(node, ' ?? true)'); + }, + messageId: comparison.expressionIsNullableBoolean + ? comparison.literalBooleanInComparison + ? comparison.negated + ? 'comparingNullableToTrueNegated' + : 'comparingNullableToTrueDirect' + : 'comparingNullableToFalse' + : comparison.negated + ? 'negated' + : 'direct', + node, + }); }, }; }, diff --git a/packages/eslint-plugin/src/util/types.ts b/packages/eslint-plugin/src/util/types.ts index 2bd7e1997392..d030b829cd46 100644 --- a/packages/eslint-plugin/src/util/types.ts +++ b/packages/eslint-plugin/src/util/types.ts @@ -308,7 +308,7 @@ export function getEqualsKind(operator: string): EqualsKind | undefined { case '!==': return { - isPositive: true, + isPositive: false, isStrict: true, }; diff --git a/packages/eslint-plugin/tests/rules/no-unnecessary-boolean-literal-compare.test.ts b/packages/eslint-plugin/tests/rules/no-unnecessary-boolean-literal-compare.test.ts index 6480d5489062..36eb36033de1 100644 --- a/packages/eslint-plugin/tests/rules/no-unnecessary-boolean-literal-compare.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unnecessary-boolean-literal-compare.test.ts @@ -38,17 +38,39 @@ ruleTester.run('no-unnecessary-boolean-literal-compare', rule, { varObject == false; `, ` - declare const varBooleanOrString: boolean | undefined; + declare const varNullOrUndefined: null | undefined; + varNullOrUndefined === false; + `, + ` + declare const varBooleanOrString: boolean | string; varBooleanOrString === false; `, ` - declare const varBooleanOrString: boolean | undefined; + declare const varBooleanOrString: boolean | string; varBooleanOrString == true; `, + ` + declare const varTrueOrStringOrUndefined: true | string | undefined; + varTrueOrStringOrUndefined == true; + `, ` declare const varBooleanOrUndefined: boolean | undefined; varBooleanOrUndefined === true; `, + { + code: ` + declare const varBooleanOrUndefined: boolean | undefined; + varBooleanOrUndefined === true; + `, + options: [{ allowComparingNullableBooleansToFalse: false }], + }, + { + code: ` + declare const varBooleanOrUndefined: boolean | undefined; + varBooleanOrUndefined === false; + `, + options: [{ allowComparingNullableBooleansToTrue: false }], + }, "'false' === true;", "'true' === false;", ], @@ -106,5 +128,101 @@ ruleTester.run('no-unnecessary-boolean-literal-compare', rule, { } `, }, + { + code: ` + declare const varTrueOrUndefined: true | undefined; + if (varTrueOrUndefined === true) { + } + `, + options: [{ allowComparingNullableBooleansToTrue: false }], + errors: [ + { + messageId: 'comparingNullableToTrueDirect', + }, + ], + output: ` + declare const varTrueOrUndefined: true | undefined; + if (varTrueOrUndefined) { + } + `, + }, + { + code: ` + declare const varFalseOrNull: false | null; + if (varFalseOrNull !== true) { + } + `, + options: [{ allowComparingNullableBooleansToTrue: false }], + errors: [ + { + messageId: 'comparingNullableToTrueNegated', + }, + ], + output: ` + declare const varFalseOrNull: false | null; + if (!varFalseOrNull) { + } + `, + }, + { + code: ` + declare const varBooleanOrNull: boolean | null; + declare const otherBoolean: boolean; + if (varBooleanOrNull === false && otherBoolean) { + } + `, + options: [{ allowComparingNullableBooleansToFalse: false }], + errors: [ + { + messageId: 'comparingNullableToFalse', + }, + ], + output: ` + declare const varBooleanOrNull: boolean | null; + declare const otherBoolean: boolean; + if (!(varBooleanOrNull ?? true) && otherBoolean) { + } + `, + }, + { + code: ` + declare const varBooleanOrNull: boolean | null; + declare const otherBoolean: boolean; + if (!(varBooleanOrNull === false) || otherBoolean) { + } + `, + options: [{ allowComparingNullableBooleansToFalse: false }], + errors: [ + { + messageId: 'comparingNullableToFalse', + }, + ], + output: ` + declare const varBooleanOrNull: boolean | null; + declare const otherBoolean: boolean; + if ((varBooleanOrNull ?? true) || otherBoolean) { + } + `, + }, + { + code: ` + declare const varTrueOrFalseOrUndefined: true | false | undefined; + declare const otherBoolean: boolean; + if (varTrueOrFalseOrUndefined !== false && !otherBoolean) { + } + `, + options: [{ allowComparingNullableBooleansToFalse: false }], + errors: [ + { + messageId: 'comparingNullableToFalse', + }, + ], + output: ` + declare const varTrueOrFalseOrUndefined: true | false | undefined; + declare const otherBoolean: boolean; + if ((varTrueOrFalseOrUndefined ?? true) && !otherBoolean) { + } + `, + }, ], }); From 26da8de7fcde9eddec63212d79af781c4bb22991 Mon Sep 17 00:00:00 2001 From: Daniel Nixon Date: Mon, 22 Jun 2020 04:32:43 +1000 Subject: [PATCH 09/10] fix(experimental-utils): getParserServices takes a readonly context (#2235) --- .../experimental-utils/src/eslint-utils/getParserServices.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/experimental-utils/src/eslint-utils/getParserServices.ts b/packages/experimental-utils/src/eslint-utils/getParserServices.ts index 481603d7ed51..925d49761522 100644 --- a/packages/experimental-utils/src/eslint-utils/getParserServices.ts +++ b/packages/experimental-utils/src/eslint-utils/getParserServices.ts @@ -11,7 +11,7 @@ function getParserServices< TMessageIds extends string, TOptions extends readonly unknown[] >( - context: TSESLint.RuleContext, + context: Readonly>, allowWithoutFullTypeInformation = false, ): ParserServices { // backwards compatibility check From a2202c7da6012db7e18eb63926b0a016f9475551 Mon Sep 17 00:00:00 2001 From: James Henry Date: Mon, 22 Jun 2020 17:01:50 +0000 Subject: [PATCH 10/10] chore: publish v3.4.0 --- CHANGELOG.md | 20 ++++++++++++++++++++ lerna.json | 2 +- packages/eslint-plugin-internal/CHANGELOG.md | 8 ++++++++ packages/eslint-plugin-internal/package.json | 4 ++-- packages/eslint-plugin-tslint/CHANGELOG.md | 8 ++++++++ packages/eslint-plugin-tslint/package.json | 6 +++--- packages/eslint-plugin/CHANGELOG.md | 18 ++++++++++++++++++ packages/eslint-plugin/package.json | 4 ++-- packages/experimental-utils/CHANGELOG.md | 12 ++++++++++++ packages/experimental-utils/package.json | 4 ++-- packages/parser/CHANGELOG.md | 8 ++++++++ packages/parser/package.json | 8 ++++---- packages/shared-fixtures/CHANGELOG.md | 8 ++++++++ packages/shared-fixtures/package.json | 2 +- packages/typescript-estree/CHANGELOG.md | 8 ++++++++ packages/typescript-estree/package.json | 4 ++-- 16 files changed, 107 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19e2f00eaf38..e2500151a516 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,26 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.4.0](https://github.com/typescript-eslint/typescript-eslint/compare/v3.3.0...v3.4.0) (2020-06-22) + + +### Bug Fixes + +* **eslint-plugin:** [no-base-to-string] handle intersection types ([#2170](https://github.com/typescript-eslint/typescript-eslint/issues/2170)) ([9cca3a9](https://github.com/typescript-eslint/typescript-eslint/commit/9cca3a9584d5d5ef0536219c5a734f4e87efb543)) +* **eslint-plugin:** [unbound-method] handling destructuring ([#2228](https://github.com/typescript-eslint/typescript-eslint/issues/2228)) ([c3753c2](https://github.com/typescript-eslint/typescript-eslint/commit/c3753c21768d355ecdb9e7ae8e0bfdfbbc1d3bbe)) +* **experimental-utils:** correct types for TS versions older than 3.8 ([#2217](https://github.com/typescript-eslint/typescript-eslint/issues/2217)) ([5e4dda2](https://github.com/typescript-eslint/typescript-eslint/commit/5e4dda264a7d6a6a1626848e7599faea1ac34922)) +* **experimental-utils:** getParserServices takes a readonly context ([#2235](https://github.com/typescript-eslint/typescript-eslint/issues/2235)) ([26da8de](https://github.com/typescript-eslint/typescript-eslint/commit/26da8de7fcde9eddec63212d79af781c4bb22991)) + + +### Features + +* **eslint-plugin:** [no-unnecessary-boolean-literal-compare] add option to check nullable booleans ([#1983](https://github.com/typescript-eslint/typescript-eslint/issues/1983)) ([c0b3057](https://github.com/typescript-eslint/typescript-eslint/commit/c0b3057b7f7d515891ad2efe32e4ef8c01e0478f)) +* **eslint-plugin:** add extension rule `no-loss-of-precision` ([#2196](https://github.com/typescript-eslint/typescript-eslint/issues/2196)) ([535b0f2](https://github.com/typescript-eslint/typescript-eslint/commit/535b0f2ddd82efa6a2c40307a61c480f4b3cdea3)) + + + + + # [3.3.0](https://github.com/typescript-eslint/typescript-eslint/compare/v3.2.0...v3.3.0) (2020-06-15) diff --git a/lerna.json b/lerna.json index 72afa49c8eb2..4f34c322983c 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "3.3.0", + "version": "3.4.0", "npmClient": "yarn", "useWorkspaces": true, "stream": true diff --git a/packages/eslint-plugin-internal/CHANGELOG.md b/packages/eslint-plugin-internal/CHANGELOG.md index 173a97a02190..f511b95f2840 100644 --- a/packages/eslint-plugin-internal/CHANGELOG.md +++ b/packages/eslint-plugin-internal/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.4.0](https://github.com/typescript-eslint/typescript-eslint/compare/v3.3.0...v3.4.0) (2020-06-22) + +**Note:** Version bump only for package @typescript-eslint/eslint-plugin-internal + + + + + # [3.3.0](https://github.com/typescript-eslint/typescript-eslint/compare/v3.2.0...v3.3.0) (2020-06-15) **Note:** Version bump only for package @typescript-eslint/eslint-plugin-internal diff --git a/packages/eslint-plugin-internal/package.json b/packages/eslint-plugin-internal/package.json index aaa9957fe8ce..c20031b6bd06 100644 --- a/packages/eslint-plugin-internal/package.json +++ b/packages/eslint-plugin-internal/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin-internal", - "version": "3.3.0", + "version": "3.4.0", "private": true, "main": "dist/index.js", "scripts": { @@ -13,7 +13,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/experimental-utils": "3.3.0", + "@typescript-eslint/experimental-utils": "3.4.0", "prettier": "*" } } diff --git a/packages/eslint-plugin-tslint/CHANGELOG.md b/packages/eslint-plugin-tslint/CHANGELOG.md index 434977a40190..64841ee61b35 100644 --- a/packages/eslint-plugin-tslint/CHANGELOG.md +++ b/packages/eslint-plugin-tslint/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.4.0](https://github.com/typescript-eslint/typescript-eslint/compare/v3.3.0...v3.4.0) (2020-06-22) + +**Note:** Version bump only for package @typescript-eslint/eslint-plugin-tslint + + + + + # [3.3.0](https://github.com/typescript-eslint/typescript-eslint/compare/v3.2.0...v3.3.0) (2020-06-15) **Note:** Version bump only for package @typescript-eslint/eslint-plugin-tslint diff --git a/packages/eslint-plugin-tslint/package.json b/packages/eslint-plugin-tslint/package.json index 97d415083aad..bf6bb3ec1ea1 100644 --- a/packages/eslint-plugin-tslint/package.json +++ b/packages/eslint-plugin-tslint/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin-tslint", - "version": "3.3.0", + "version": "3.4.0", "main": "dist/index.js", "typings": "src/index.ts", "description": "TSLint wrapper plugin for ESLint", @@ -32,7 +32,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/experimental-utils": "3.3.0", + "@typescript-eslint/experimental-utils": "3.4.0", "lodash": "^4.17.15" }, "peerDependencies": { @@ -42,6 +42,6 @@ }, "devDependencies": { "@types/lodash": "^4.14.149", - "@typescript-eslint/parser": "3.3.0" + "@typescript-eslint/parser": "3.4.0" } } diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index 42e7e147f901..709a49e455be 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -3,6 +3,24 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.4.0](https://github.com/typescript-eslint/typescript-eslint/compare/v3.3.0...v3.4.0) (2020-06-22) + + +### Bug Fixes + +* **eslint-plugin:** [no-base-to-string] handle intersection types ([#2170](https://github.com/typescript-eslint/typescript-eslint/issues/2170)) ([9cca3a9](https://github.com/typescript-eslint/typescript-eslint/commit/9cca3a9584d5d5ef0536219c5a734f4e87efb543)) +* **eslint-plugin:** [unbound-method] handling destructuring ([#2228](https://github.com/typescript-eslint/typescript-eslint/issues/2228)) ([c3753c2](https://github.com/typescript-eslint/typescript-eslint/commit/c3753c21768d355ecdb9e7ae8e0bfdfbbc1d3bbe)) + + +### Features + +* **eslint-plugin:** [no-unnecessary-boolean-literal-compare] add option to check nullable booleans ([#1983](https://github.com/typescript-eslint/typescript-eslint/issues/1983)) ([c0b3057](https://github.com/typescript-eslint/typescript-eslint/commit/c0b3057b7f7d515891ad2efe32e4ef8c01e0478f)) +* **eslint-plugin:** add extension rule `no-loss-of-precision` ([#2196](https://github.com/typescript-eslint/typescript-eslint/issues/2196)) ([535b0f2](https://github.com/typescript-eslint/typescript-eslint/commit/535b0f2ddd82efa6a2c40307a61c480f4b3cdea3)) + + + + + # [3.3.0](https://github.com/typescript-eslint/typescript-eslint/compare/v3.2.0...v3.3.0) (2020-06-15) diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index c1b56bc9f0d8..08a04f8b7605 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin", - "version": "3.3.0", + "version": "3.4.0", "description": "TypeScript plugin for ESLint", "keywords": [ "eslint", @@ -42,7 +42,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/experimental-utils": "3.3.0", + "@typescript-eslint/experimental-utils": "3.4.0", "debug": "^4.1.1", "functional-red-black-tree": "^1.0.1", "regexpp": "^3.0.0", diff --git a/packages/experimental-utils/CHANGELOG.md b/packages/experimental-utils/CHANGELOG.md index 91e2035933e6..585d87d32569 100644 --- a/packages/experimental-utils/CHANGELOG.md +++ b/packages/experimental-utils/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.4.0](https://github.com/typescript-eslint/typescript-eslint/compare/v3.3.0...v3.4.0) (2020-06-22) + + +### Bug Fixes + +* **experimental-utils:** correct types for TS versions older than 3.8 ([#2217](https://github.com/typescript-eslint/typescript-eslint/issues/2217)) ([5e4dda2](https://github.com/typescript-eslint/typescript-eslint/commit/5e4dda264a7d6a6a1626848e7599faea1ac34922)) +* **experimental-utils:** getParserServices takes a readonly context ([#2235](https://github.com/typescript-eslint/typescript-eslint/issues/2235)) ([26da8de](https://github.com/typescript-eslint/typescript-eslint/commit/26da8de7fcde9eddec63212d79af781c4bb22991)) + + + + + # [3.3.0](https://github.com/typescript-eslint/typescript-eslint/compare/v3.2.0...v3.3.0) (2020-06-15) **Note:** Version bump only for package @typescript-eslint/experimental-utils diff --git a/packages/experimental-utils/package.json b/packages/experimental-utils/package.json index 5ed24642f447..376b75559236 100644 --- a/packages/experimental-utils/package.json +++ b/packages/experimental-utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/experimental-utils", - "version": "3.3.0", + "version": "3.4.0", "description": "(Experimental) Utilities for working with TypeScript + ESLint together", "keywords": [ "eslint", @@ -40,7 +40,7 @@ }, "dependencies": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/typescript-estree": "3.3.0", + "@typescript-eslint/typescript-estree": "3.4.0", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" }, diff --git a/packages/parser/CHANGELOG.md b/packages/parser/CHANGELOG.md index bf6cf0a44377..8f092f231aa4 100644 --- a/packages/parser/CHANGELOG.md +++ b/packages/parser/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.4.0](https://github.com/typescript-eslint/typescript-eslint/compare/v3.3.0...v3.4.0) (2020-06-22) + +**Note:** Version bump only for package @typescript-eslint/parser + + + + + # [3.3.0](https://github.com/typescript-eslint/typescript-eslint/compare/v3.2.0...v3.3.0) (2020-06-15) **Note:** Version bump only for package @typescript-eslint/parser diff --git a/packages/parser/package.json b/packages/parser/package.json index b9ca23514946..cf28e63968e7 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/parser", - "version": "3.3.0", + "version": "3.4.0", "description": "An ESLint custom parser which leverages TypeScript ESTree", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -44,13 +44,13 @@ }, "dependencies": { "@types/eslint-visitor-keys": "^1.0.0", - "@typescript-eslint/experimental-utils": "3.3.0", - "@typescript-eslint/typescript-estree": "3.3.0", + "@typescript-eslint/experimental-utils": "3.4.0", + "@typescript-eslint/typescript-estree": "3.4.0", "eslint-visitor-keys": "^1.1.0" }, "devDependencies": { "@types/glob": "^7.1.1", - "@typescript-eslint/shared-fixtures": "3.3.0", + "@typescript-eslint/shared-fixtures": "3.4.0", "glob": "*" }, "peerDependenciesMeta": { diff --git a/packages/shared-fixtures/CHANGELOG.md b/packages/shared-fixtures/CHANGELOG.md index c3f5fcda81e9..42e10121707d 100644 --- a/packages/shared-fixtures/CHANGELOG.md +++ b/packages/shared-fixtures/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.4.0](https://github.com/typescript-eslint/typescript-eslint/compare/v3.3.0...v3.4.0) (2020-06-22) + +**Note:** Version bump only for package @typescript-eslint/shared-fixtures + + + + + # [3.3.0](https://github.com/typescript-eslint/typescript-eslint/compare/v3.2.0...v3.3.0) (2020-06-15) **Note:** Version bump only for package @typescript-eslint/shared-fixtures diff --git a/packages/shared-fixtures/package.json b/packages/shared-fixtures/package.json index b19dae20fe3a..4f5d0982ca50 100644 --- a/packages/shared-fixtures/package.json +++ b/packages/shared-fixtures/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/shared-fixtures", - "version": "3.3.0", + "version": "3.4.0", "private": true, "scripts": { "build": "tsc -b tsconfig.build.json", diff --git a/packages/typescript-estree/CHANGELOG.md b/packages/typescript-estree/CHANGELOG.md index e6b50349ca67..aad24b5c9073 100644 --- a/packages/typescript-estree/CHANGELOG.md +++ b/packages/typescript-estree/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [3.4.0](https://github.com/typescript-eslint/typescript-eslint/compare/v3.3.0...v3.4.0) (2020-06-22) + +**Note:** Version bump only for package @typescript-eslint/typescript-estree + + + + + # [3.3.0](https://github.com/typescript-eslint/typescript-eslint/compare/v3.2.0...v3.3.0) (2020-06-15) diff --git a/packages/typescript-estree/package.json b/packages/typescript-estree/package.json index a83b562bb417..e0d03e774e18 100644 --- a/packages/typescript-estree/package.json +++ b/packages/typescript-estree/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/typescript-estree", - "version": "3.3.0", + "version": "3.4.0", "description": "A parser that converts TypeScript source code into an ESTree compatible form", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -59,7 +59,7 @@ "@types/lodash": "^4.14.149", "@types/semver": "^7.1.0", "@types/tmp": "^0.2.0", - "@typescript-eslint/shared-fixtures": "3.3.0", + "@typescript-eslint/shared-fixtures": "3.4.0", "tmp": "^0.2.1", "typescript": "*" },